历史上的今天
今天是:2024年10月20日(星期日)
2021年10月20日 | #51单片机# UART串口通信的基本应用、模块介绍和串口程序
2021-10-20 来源:eefocus
UART串口通信的基本应用
通信的三种基本类型:
单工通信:值允许一方向另一方传送星系,另一方不能回传信息。例:电视遥控器、收音机广播
半双工通信:数据可在双方之间相互传播,但同一时刻只能一方传给另一方。例:对讲机
全双工通信:发送数据的同时也可接收数据,两者同步进行。例:电话
UART模块介绍
通常情况下,我们关心的是通信的结果而非过程。51单片机内部存在UART模块,可自动接收数据,接收完毕,会发出通知信号。要使用这个模块,需要配置对应的具有特殊功能的寄存器。
51单片机的UART串口结构由串行口控制寄存器SCON、发送和接收电路三部分构成。
先来了解串口控制寄存器SCON
SCON——串行控制寄存器的位分配(地址0X98、可位寻址)

SCON——串行控制寄存器的位描述

对于串口的四种模式,模式1是最常用的,就是前面提到的1位起始位,8位数据位和1位停止位。 下面讲详细介绍模式1的工作细节和使用方法(其他3种模式与模式1大同小异,要用的时候自行查阅资料既可)。
在硬件模块中,有一个专门的波特率发生器用来控制发送和接收数据的速度。对于STC89C52单片机来说,这个波特率只能由定时器T1或定时器T2产生。这与模拟的通信概念完全不同。默认使用定时器T1(定时器T2需要额外配置的寄存器)。
下面主要就使用T1作为波特率发生器来讲解,方式1下的波特率发生器必须使用T1的模式2,也就是自动重装载模式。
定时器的重载值计算公式为:TH1 = TL1 = 256-晶振值/12/2/16/波特率
这里介绍一个与波特率有关的另一个计算器:电源管理寄存器PCON,他的最高位可以把波特率提高一倍,也就是如果写PCON |= 0X80以后,计算公式就成了:TH1 = TL1 = 256-晶振值/12/16/波特率
公式中数字的含义解释如下:
256——8位定时器的溢出值,1TL1的溢出值。
晶振值——在开发板上是11059200
12——1个机器周期等于12个时钟周期
16——将一位信号采集16次(IO口模拟串口通信接收数据时采集的是这位数据的中间位置,而实际串口模块比模拟的要复杂和精确一些。它采取的方式是把一位信号采集16次,其中7,8,9次取出来,如果这三次中有两次是高电平,就认为这个数据是1,如果有两次是低电平,就认为这个数据是0,这样即使是受到干扰导致数据读错,仍可保证最终数据的正确性)
了解了串口采集模式,这里可以思考一个问题。“晶振值/12/2/16/波特率”计算出的值有没有可能是小数?把这里理解了也就解释了晶振为何使用11059200。 因为11059200可以被常见的波特率整除。
串口通信的发送和接收电路在物理上有两个名字相同的SBUF寄存器,它们的地址相同都是0X99。 这两个寄存器一个用来发送缓冲,一个用来接收缓冲,实现了UART的全双工通信,互相不干扰。操作SBUF,单片机会自动判断并决定选择接收SBUF还是发送SBUF。
UART串口程序
一般情况下,串口通信程序的编写步骤如下:
1)配置串口为模式1
2)配置定时器T1为模式2(自动重装模式)
3)根据波特率计算TH1和TL1的初值,如果有需要可以使用PCON进行波特率加倍。
4)打开定时器控制寄存器TR1,让定时器跑起来。
注意:使用T1时,即在使用T1做波特率发生器,千万不能再使能T1中断。
以下是一段演示代码
#include void ConfigUART(unsigned int baud);//串口配置函数,baud——通信波特率 void main() { ConfigUART(9600); //配置波特率为9600 while(1) { while(!RI); //等待接收完成 RI = 0; //清零接收中断标志 SBUF = SBUF + 1;//接收到的数据+1后,发送回去 while(!TI); //等待发送完成 TI = 0; //清零发送中断标志位 } } void ConfigUART(unsigned int baud) { SCON = 0X50; //配置串口为模式1 TMOD &= 0X0F; //清零T1的控制位 TMOD |= 0X20; //配置T1为模式2 TH1 = 256 - (11059200/12/32)/baud; //计算T1重载值 TL1 = TH1; //初值等于重载值 ES = 0; //禁止T1中断 TR1 = 1; //启动T1 } 注意:实际工程开发中,并不会这样编写这段代码,因为这段代码在主循环里等待接收中断标志位和发送中断标志位,占据了大量程序内存。实际使用串口时常用到串口中断。 以下是串口中断的演示代码 #include void ConfigUART(unsigned int baud);//串口配置函数,baud——通信波特率 void main() { EA = 1; //使能总中断 ConfigUART(9600); //配置波特率为9600 while(1); } void ConfigUART(unsigned int baud) { SCON = 0X50; //配置串口为模式1 TMOD &= 0X0F; //清零T1的控制位 TMOD |= 0X20; //配置T1为模式2 TH1 = 256 - (11059200/12/32)/baud; //计算T1重载值 TL1 = TH1; //初值等于重载值 ET1 = 1; //禁止T1中断 ES = 1; //使能串口中断 TR1 = 1; //启动T1 } //UART中断服务函数 void InterruptUART() interrupt 4 { if(RI) //接收到字节 { RI = 0; //手动清零接收中断标志 SBUF = SBUF + 1; //接收到的数据+1后发回,左边是发送SBUF,右边是接收SBUF } if(TI) //字节发送完毕 { TI = 0; //手动清零发送中断标志位 } }
上一篇:80C51
史海拾趣
|
HTTPServer.obj : error LNK2019: unresolved external symbol \"public: __cdecl std::_Lockit::~_Lockit(void)\" (??1_Lockit@std@@QAA@XZ) referenced in function \"public: __cdecl std::_Tree::~_Tree(vo id)\" (??1?$_Tree@V?$basic_string ...… 查看全部问答> |
|
我想利用IDE转SATA和SATA转IDE 2种卡实现并/串高速数据传输! 有2个地方都是并口,40M速度,想利用IDE转SATA卡先并--串行,然后用SATA转IDE卡再把串--并行,实现近距离数据传输。实验时距离不超过30cm, 但用示波器就是看不到数据传过来。此方案若 ...… 查看全部问答> |
|
用什么方法能够实时采集8路PWM信号的占空比 现有8路PWM信号,信号不同步,且占空比都很小周期一样都为50HZ,最小脉宽为0.5ms,最大为2.5ms,想通过一种方法实时得到这8路信号的脉冲宽度 … 查看全部问答> |
|
FCI已推出高速I/O接口的完整产品线。然而随着科技的不断进步,由FCI公司生产的新型SFGL系列( 0.4毫米间距和0.9毫米高度)FPC后翻式ZIF连接器含有各种微间距后翻执行机构系列,它们就是目前的间距0.5毫米、高度0.9毫米( ...… 查看全部问答> |
|
最近在研究430 看到有人写的一段代码,为了接收GPS的数据,使用串口中断接收,部分代码如下: if(global_temp_data_num==0) //获取\"GG\"标志 { if ...… 查看全部问答> |




