单片机模板七:串口通信
一、串口通信
1、通信
通信可以分为并行通信和串行通信。
并行通信:数据的各位同时进行发送或接收的通信方式。优点是速率高。缺点是需要的传输线多,成本高,只适合近距离的数据通信。
串行通信:一位一位的按顺序的进行发送或接收的通信方式。优点是需要的传输线少,成本低。缺点是传输的速率慢,适合远距离的数据通信。
2、RXD和TXD
STC89C52
有两个引脚是专门用来做
UART
串行通信的,一个是
P3.0
一个是
P3.1
,它们还分别有另外的名字叫做 RXD
和
TXD
,由它们组成的通信接口就叫做串行接口,简称串口。
图中,
GND
表示单片机系统电源的参考地,
TXD
是串行发送引脚,
RXD
是串行接收引脚。把两个单片机的 GND 相互连接起来,然后单片机 1 的 TXD 引脚接到单片机 2 的 RXD 引脚上,即此路为单片机 1 发送而单片机 2 接收的通道,单片机 1 的 RXD 引脚接到单片机 2 的 TXD 引脚上,即此路为单片机 2 发送而单片机 1 接收的通道。
当单片机
1
想给单片机
2 发送数据时,用二进制表示,采用低位先发,高位后发的原则。
3、波特率
波特率就是发送二进制数据位的速率,习惯上用
baud
表示,即我们发送一位二进制数据的持续时间=1/baud
。在通信之前,单片机
1
和单片机
2
首先都要明确的约定好它们之间的通信波特率,必须保持一致,收发双方才能正常实现通信。
4、常见通讯接口
5、通信的基本类型
常用的通信从传输方向上可以分为单工通信、半双工通信、全双工通信三类。
单工通信就是指只允许一方向另外一方传送信息,而另一方不能回传信息。比如电视遥 控器、收音机广播等;
半双工通信是指数据可以在双方之间相互传播,但是同一时刻只能其中一方发给另外一方。比如我们的对讲机;
全双工通信就发送数据的同时也能够接收数据,两者同步进行。比如我们的电话。
6、UART
51
单片机的
UART
串口的结构由串行口控制寄存器
SCON
、发送和接收电路三部分构成。
STC89C52的UART有四种工作模式:
7、寄存器
这是串口模式配置图,这里有一个很重要的寄存器,就是SBUF寄存器,也叫串口数据缓存寄存器,物理上是两个独立的寄存器,但占用相同的地址。写操作时,写入的是发送寄存器,读操作时,读出的是接收寄存器。
最左边的就是总线,两个不同意义上的SBUF寄存器使用一个总线连接,从输入端进入就会从输出端出。
其中的这部分是使用定时器1实现的,主要作用就是控制波特率,也就是我们的数据收发速率。
下图是串口相关寄存器:
我们主要介绍SCON和PCON。
SCON(串行控制寄存器)
总的来说,如果我们只需要串口发送数据,我们只要把SCON中的SM1置为1,其他的置为0就可以了,这样我们就可以直接配置SCON = 0x40;或者是分开来。如果我们需要串口接收数据,就还要加一个REN = 1,即SCON = 0x50.
PCON(电源控制寄存器)
该寄存器较常用到就是SWOD位,知道SWOD就好了。
SWOD,波特率选择位,就是用于波特率是否加倍。
○ 当用软件置位SMOD,即SMOD=1,则使波特率加倍;
○ SMOD=0,则各工作方式的波特率不加倍不变。复位时默认SMOD=0。
8、电平标准
电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:
TTL电平:+5V表示1,0V表示0 RS232电平:-3~-15V表示1,+3~+15V表示0 RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)
二、串口配置
1、配置SCON寄存器(用于串口初始化)
以常用的串口模式1(8位UART,波特率可变)来举例。
在模式1下,SM0和SM1置为0 1。
REN,可置0 可置1,根据自己代码需求。
代码:
SCON = 0x40; //模式1,REN置0,禁止接受信息
SCON =0x50 //模式1,REN置1,启用TXD,允许接受信息
2、配置PCON寄存器(用于串口初始化)
这里我们只考虑SWOD位,需不需要波特率加倍,如果要加倍,则SWOD位置1。
代码:
PCON |= 0x80; //波特率加倍
3、串口初始化
代码:
//如果使用reg52.h头文件需要提前定义AUXR寄存器 (地址为0x8e)
void UART_Init()
{
TH1=0xFD;//波特率定义
TL1=0xFD;
TMOD=0x20;//计时器模式设定
AUXR=0x00;
SCON=0x50;//串口初始化
TR1=1;//打开计时器1
ES=1;//打开串口中断
EA=1;//打开总中断
}
4、配置发送数据函数
串口发送一个字节数据。
代码:
void UART_SendByte(char Byte)
{
SBUF=Byte; //向缓存器中写入数据
while(TI==0); //等待是否完成
TI=0; //TI复位
}
5、配置中断函数
代码:
//串口中断函数格式
void (函数名无所谓)() interrupt 4
{
中断程序;
}
//中断接收数据函数
void UART_Routine() interrupt 4
{
if(RI==1) //判断接收中断请求标志位是否置1
{
RI=0; //清空标志位,复位
UART_Send(SBUF); //查看接受的数据
}
}
6、字符串的发送、接收与判断
利用指针的移位,一个字节一个字节的发送,直到结束为'\0'。
代码:
//字符串发送
void UART_Sendstring(unsigned char *str)
{
while(*str!='\0')
{
UART_SendByte(*str++);
}
}
代码:
//字符串接收
void UART_Service() interrupt 4
{
unsigned char temp=0;
if(RI==1)
{
temp=SBUF;
RI=0;
Receive[len++]=temp;
}
}
代码:
//字符串的判断,以接收Retur为例子n
void UART_deal(){
if(len==6)
{
if(Receive[0]=='R'&&Receive[1]=='e'&&Receive[2]=='t'&&Receive[3]=='u'&&Receive[4]=='r'&&Receive[5]=='n')
{
//执行一定操作
len=0;
}
else{
len=0;
}
}
}
7、串口中断
在具体操作串行口之前,需要对单片机的一些与串口有关的特殊功能寄存器进行初始化设置,主要是设置产生波特率的定时器1,串行口控制,和中断控制,具体步骤如下:
配置TMOD寄存器:确定定时器的工作模式(T2);
配置TCON寄存器:定时器的控制开关;
计数器初值配置:装载TH1,TL1;
配置SCON寄存器:确定串行口工作模式;
中断配置:串行口在中断方式时,要进行中断设置(配置IE,I);
//*串口初始化
void UART_Init()
{
//*TMOD配置:设置定时器模式,
TMOD&=0x0F;
TMOD|=0x20;
//*TCON配置
TR1=1; //打开定时器
//*计数器配置
TH1=0xF3; //设置定时器初始值 1111 0011
TL1=0xF3; //设置定时器重装值 1111 0011
/********************************************
波特率计算:
1.二进制的OxF3=十进制的243;
2.每隔256溢出一次,256-243=13(每计13个数就溢出1次)
3.12MHz的晶振,每1us计一次数,以上计13个数就会溢出,也就需要13us
4.溢出率=1/13us=0.07692MHz
5.波特率=溢出率/16=0.00480769MHz=4807Hz
6.波特率加倍=波特率*2=9614Hz
**********************************************/
//*SCON配置 波特率9600hz
SCON=0x50; //设置串口工作模式1,SCON=0101 0000
PCON=0x80; //设置波特率,SMOD=1,波特率加倍;PCON=1000 0000
//*中断配置
ES=1; //打开串行口中断
EA=1; //打开总中断
}
三、串口通信的应用
1、实现发送与接收
首先hex模式是十六进制模式,当我们用电脑以hex模式给单片机USART口发数据时,发的是十六进制,单片机接收的也是十六进制;当我们用电脑以文本模式给单片机发数据时,只能发字母(0-9,a-z,A-Z等其他符号),单片机收到的也是字母。
代码:
#include <reg52.h>
sfr AUXR = 0x8e; //定义辅助寄存器
void Send_Byte(unsigned char dat);
//声明数据发送函数(因数据接收函数在发送函数之前要调用发送函数)
void Select_HC573(unsigned char channel)
{
switch(channel)
{
case 4:
P2 = (P2 & 0x1f) | 0x80;
break;
case 5:
P2 = (P2 & 0x1f) | 0xa0;
break;
case 6:
P2 = (P2 & 0x1f) | 0xc0;
break;
case 7:
P2 = (P2 & 0x1f) | 0xe0;
break;
}
}
//============中断接收函数===============
void Init_Uart()
{
TMOD = 0x20;
TH1 = 0xfd;
TL1 = 0xfd;
TR1 = 1;
SCON = 0x50;
AUXR = 0x00;
ES = 1;
EA = 1;
}
unsigned char urdat;
void Service_Uart() interrupt 4 //数据接收(中断方式)
{
if(RI == 1)
{
RI = 0; //软件复位
urdat = SBUF;
Send_Byte(urdat);
}
}
//===================================
void Send_Byte(unsigned char dat) //数据发送(轮询方式)
{
SBUF = dat; //SBUF 串口数据缓冲寄存器
while(TI == 0); //如果数据已发送则TI为1,跳出此循环
TI = 0;
}
void Init_System()
{
Select_HC573(5);
P0 = 0x00;
Select_HC573(4);
P0 = 0xff;
}
void main()
{
Init_System();
Init_Uart();
Send_Byte(0x5a);
Send_Byte(0xa5);
while(1);
}
2、控制LED灯
实现下图功能:
代码:
#include <reg52.h>
sfr AUXR = 0x8e; //定义辅助寄存器
void Select_HC573(unsigned char channel) //锁存器选择函数
{
switch(channel)
{
case 4: P2 = (P2 &0x1f) | 0x80; break; //控制LED
case 5: P2 = (P2 &0x1f) | 0xa0; break; //控制蜂鸣器、继电器
case 6: P2 = (P2 &0x1f) | 0xc0; break; //数码管com共阳公共端
case 7: P2 = (P2 &0x1f) | 0xe0; break; //数码管段码端
}
}
//==============串口数据接收中断===================
void Init_Uart() //中断初始化函数
{
TMOD = 0x20; //定时器1
TH1 = 0xfd; //设置波特率为9600
TL1 = 0xfd; //11.0592M或12M的12分频
SCON = 0X50; //串口参数为模式1且允许接收
AUXR = 0x00; //bit7=1:定时器1不分频,0则12分频
TR1 = 1; //启动定时器1
ES = 1; //使能串口中断
EA = 1; //打开总中断
}
unsigned char command = 0x00; //注意赋初值为16进制
void Service_Uart() interrupt 4 //中断服务函数
{
if(RI == 1) //收到一个完整字节
{
command = SBUF; //将SBUF缓冲器中数据赋值给command
RI = 0; //人工清零
}
}
//=================================================
void SendByte(unsigned char dat) //发送数据函数
{
SBUF = dat; //将数据放入SBUF缓冲器
while(TI == 0); //如果成功发送数据,则TI为1跳出此循环
TI = 0; //人工清零
}
void SendString(unsigned char *str) //发送字符串函数
{
while(*str != '\0') //判断指针是否指向字符串结束符
{
SendByte(*str++); //先执行SendByte(*str),赋值完成后,指针++移向下一位
}
}
void Working()
{
Select_HC573(4); //控制LED
if(command != 0x00)
{
switch(command & 0xf0) //高4位不变,低4位清零
{
case 0xa0:
P0 = (P0 | 0x0f) & (~command | 0xf0);
command = 0x00; //避免重复执行working函数
break;
case 0xb0:
P0 = (P0 | 0xf0) & ((~command << 4)| 0x0f);
command = 0x00;
break;
case 0xc0:
SendString("The System is Working Normally…");
command = 0x00;
break;
}
}
}
void Init_System() //程序初始化
{
Select_HC573(5);
P0 = 0x00;
Select_HC573(4);
P0 = 0xff;
}
void main()
{
Init_Uart();
Init_System();
SendString("Welcome to the System…\r\n");
while(1)
{
Working();
}
}
作者:lmp_041018