前文回顾↓↓↓
单片机:串口通信知识详解(上)
我们接着上节的内容来给讲一下51单片机串口的使用方法,好的,直接开始我们今天的内容。
串行口结构串行口的结构,如图1所示。
图1 串行口的结构
这里有两个物理上独立的接收、发送寄存器SBUF,它们占用同一内存(99H)。
在程序逻辑上,SBUF只有一个,既代表发送寄存器,又代表接收寄存器,具有同一单元地址,但在物理结构上,则有两个完全独立的SBUF,一个发送寄存器SBUF和一个接收寄存器SBUF。如果CPU写SBUF,数据会被存入发送寄存器准备发送;如果CPU读SBUF,则读入的数据一定来自接收寄存器SBUF。(a=SBUF;SBUF=a;)。
串口相关的寄存器接下来讲一下与串口有关的寄存器。
1 SCON寄存器首先是SCON寄存器。
这里我简单说一下每一位的功能。
SM0:当PCON寄存器中SMOD0位为1时,该位用于帧错误检测。为0时,该位与SM1一起控制串口通信的工作方式。(这里一般用于控制工作方式)
SM0、SM1控制串口通信工作方式,如图2所示。
图2 SM0、SM1控制串口通信工作方式
这里的SYSclk是晶振频率,方式0和方式2是比波特率固定的,具体大家可以自己算一下。方式1和方式3通过配置定时器1来改变波特率,SMOD是PCON寄存器中可以配置的,配置为1时可以将波特率提升1倍,后边会再介绍。
我们一般使用方式1,发送/接收8位数据,波特率可变。
SM2:多机通信控制位,主要用在方式2和方式3,为0时双机通信,为1时多机通信。
REN:串行接收允许位,REN=0时禁止接收,REN=1时允许接收
TB8/TR8:在方式2和方式3时分别用于存放发送/接收的第9位数据。
TI:发送中断请求标志位,数据发送结束时,标志位被自动置1并向CPU请求中断,需通过程序置0。
RI:接收中断请求标志位,数据接收结束时,标志位被自动置1并向CPU请求中断,需通过程序置0。
2 PCON寄存器接下来是PCON寄存器。
SMOD:波特率选择位,SMOD=1时,工作方式1、2、3中波特率加倍。
3 IE寄存器最后还是我们熟悉的IE寄存器。
这里与串口相关的位有:
EA,CPU总中断允许控制位,前边多次介绍过的,不多说了。
ES,串行口中断允许位,ES=1,允许串行口中断;ES=0,禁止串行口中断。
我们配置好串口工作模式、打开串口中断后,CPU接收到串口的中断请求时就会相应串口中断执行串口中断服务函数。
波特率计算当串口工作在方式1时,波特率由定时器1的溢出率决定,此时定时器1通常选用定时器初值自动重装的工作模式(工作模式2,TMOD=0x20;)此时仅用低8位来计数,溢出以后高8位的存放的数据会放入低8位中重新计时,无需再通过程序重放初值。
因此,
波特率=(2^SMOD/32)*(单片机时钟频率/(256-X))
X是初值。
在实际应用中,通常是选确定波特率,再根据波特率算出TI的定时初值,因此:
X=256-(2^SMOD/32)*(单片机时钟频率/波特率)
举例
波特率为9600时,求T1存放的初值(晶振频率为11.0592MHZ):
SMOD=0
(2^SMOD/32)=1/32
(单片机时钟频率/波特率)=((11.0592MHZ/12)/9600)=96
X=253
因此T1存放初值为253(TH1=0xfd;TL1=0xfd;)。
寄存器配置步骤在使用串口前,我们要把上边讲到的寄存器进行配置,设定好工作方式。
设置T1工作方式(编程TMOD寄存器);
计算T1的初值,装载TH1、TL1;
启动T1(编程TCON中的TR1位);
确定串行口控制(编程SCON寄存器);
如需串口在中断方式工作时,要进行中断设置编程IE寄存器。
好的,现在用代码来对串口进行初始化:
void uart_init()
{
TMOD = 0x20; //T1工作模式2 8位自动重装
TH1 = 0xfd;
TL1 = 0xfd; //比特率9600
TR1 = 1; //启动T1定时器
SM0 = 0;
SM1 = 1; //串口工作方式1 10位异步
REN = 1; //串口允许接收
EA = 1; //开总中断
ES = 1; //串口中断打开
}
←左右滑动,查看全部代码→
举个栗子下边用一个例子来带大家了解一下。
串口收发数据,设置波特率为9600,把接收到的数据用P1端口的LED灯以二进制的形式显示(灭为0,亮为1),在把接收到的数据加1并发出。
#include
#define u8 unsigned char
#define u16 unsigned int
u8 num; //用于存放接收/发送数据
void delay(u16 z)
{
u16 x,y;
for(x = z; x > 0; x--)
for(y = 114; y > 0 ; y--);
}
void UART_init()
{
TMOD = 0x20; //T1工作模式2 8位自动重装
TH1 = 0xfd;
TL1 = 0xfd; //比特率9600
TR1 = 1; //启动T1定时器
SM0 = 0;
SM1 = 1; //串口工作方式1 10位异步
REN = 1; //串口允许接收
EA = 1; //开总中断
ES = 1; //串口中断打开
}
void main()
{
UART_init(); //串口初始化
while(1);
}
void UART() interrupt 4
{
if(RI) //检测是否接收完成
{
num = SBUF; //采集接收到的数据
P1 = SBUF;
num++; //把接收的数据加1并发送
RI = 0;
SBUF = num;
while(!TI); //等待发送完成
TI = 0;
}
}
←左右滑动,查看全部代码→
当我们使用串口发送字符串时,可以直接添加头文件“#include ”,这个就是我们学习C语言时常用到了,我们可以直接调用其中的“printf”、“putchar”等函数来通过串口发送数据,这里要注意的是:在发送前要通过程序来把“TI”置1,因为在这些函数开头就会通过“while(!TI);”来判断数据是否发送完成。
/*********************************************
void putchar (unsigned char sbyte)
{
while(!TI); //等待数据发送完成
//如果没有置1,程序会卡在这里
SBUF = sbyte;
}
*********************************************/
好的,现在用程序来实现一下:
#include
#define u8 unsigned char
#define u16 unsigned int
u8 num; //用于存放接收/发送数据
void Delay(u16 n)
{
u8 j;
while(n--)
for(j=113;j>0;j--);
}
void UART_init()
{
TMOD = 0x20; //T1工作模式2 8位自动重装
TH1 = 0xfd;
TL1 = 0xfd; //比特率9600
TR1 = 1; //启动T1定时器
SM0 = 0;
SM1 = 1; //串口工作方式1 10位异步
}//这里没有使用中断和接收功能,可以不配置
void main()
{
UART_init(); //串口初始化
while(1)
{
TI = 1;
printf("欢迎大家使用串口通信!\n");
while(!TI); //等待发送完成
TI = 0;
Delay(1000); //每隔1S发送一次
}
}
←左右滑动,查看全部代码→
调试串口时,可以使用“STC-ISP(V6.85)”(其它版本应该也可以)。
好的,本节内容就先到这里啦。
▼ 更多蓝桥杯文章 ▼蓝桥杯·单片机竞赛备赛之串口通信(上)
蓝桥杯·单片机竞赛备赛之定时器
蓝桥杯·单片机竞赛备赛之外部中断
蓝桥杯·单片机竞赛备赛之机械按键
扫码入群 扫码添加管理员微信加入“电子产品世界”粉丝交流群
↓↓↓↓点击,查看更多新闻