【51单片机】UART串口通讯原理 + 使用

[复制链接]
发表于 2025-12-30 14:05:09 | 显示全部楼层 |阅读模式
学习使用的开辟板:STC89C52RC/LE52RC
编程软件:Keil5
烧录软件:stc-isp
开辟板实图:



串口

   

  • 串口是一种应用非常广泛的通讯接口,串口本钱低、轻易使用、通讯线路简单,可实现两个装备的相互通讯
  • 单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块相互通讯,极大的扩展了单片机的应用范围,加强了单片机体系的硬件气力
    51单片机内部自带UART(Universal Asynchronous Receiver Transmitter,通用异步收发器),可实现单片机的串口通讯
  

硬件电路

简单双向串口通讯有两根通讯线(发送端TXD(Transmit Exchange Data)和吸收端RXD(Receive Exchange Date))
TXD和RXD要交织毗连,装备1的TXD毗连装备2的RXD,装备1的RXD毗连装备2的TXD

当只要单向传输数据时,可以只有一根通讯线
GND是肯定要毗连的,若两个装备都可以各自供电,则不须要毗连VCC
当电平尺度差别等时,还须要加电平转换芯片

电平尺度
电平尺度是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平尺度有如下三种:


  • TTL电平:+5V体现1,0V体现0,一样平常用于单片机
  • RS232电平:-3 ~ -15V 体现1,+3 ~ +15V 体现0,一样平常用于电脑
  • RS485电平:两线压差 +2 ~ +6V 体现1,-2 ~ -6V 体现0(差分信号),一样平常用于CAN总线
前两个通讯隔断都较近,一样平常只有十几米,隔断过远传输的数据就很轻易堕落;而RS485通讯隔断远,信号可靠性高,传输隔断可达1KM以上

干系术语


  • 全双工:通讯双方可以在同一时候相互传输数据



  • 半双工:通讯双方可以相互传输数据,但同时间只能有一段发送,另一端吸收,必须分时复用一根数据线



  • 单工:通讯双方只能一方发送到另一方,不能反向传输。比如遥控器控制电视,只能遥控器向电视发送数据

  • 异步:通讯双方各自约定通讯速率
  • 同步:通讯双方靠一根时钟线来约定通讯速率
数据传输是依靠高低电平的,也就是电平协议。比如如下两个数据

看电平都是从高电平变为低电平,但是假如通讯速率不一样,则获取的数据不一样

通讯速率快,10大概会被分析为1100;通讯速率慢,1100也大概会被分析为10。
以是约定好通讯速率很告急


  • 总线:毗连各个装备的数据传输线路(类似一条马路,把路边的住户毗连起来,使住户可以相互互换)


常见通讯接口比力



  • UART:为本节学习的串口通讯接口
  • I2C:板子上的C24C02使用该串口
  • SPI:板子上的DS1302使用非尺度SPI
  • 1-Wire:板子上的DS18B20使用该串口
常见的另有CAN总线和USB,CAN总线常用于汽车范畴

UART

51单片机的UART
STC89C52有1个UART,RXD和TXD分别和P3.0和P3.1这两个I/O口共用同一个引脚

STC89C52的UART有四种工作模式:
模式0:同步移位寄存器
模式1:8位UART,波特率可变(常用)
模式2:9位UART,波特率固定
模式3:9位UART,波特率可变

串口参数及时序图


  • 波特率:串口通讯的速率(发送和吸收各数据位的隔断时间)
  • 校验位:用于数据验证,肯定步调可以知道数据是否错误,也须要双方提前协商同一校验。常用的校验如01校验奇偶校验。9位UART就是多了一位校验位
  • 克制位:用于数据帧隔断,发送多个数据,怎样隔断两个数据,就使用克制位
    波特率就是上述异步双方要约定好的怎样对数据举行采样
串口收发数据,都是从低位开始

串口模式图
简单的串口模式图

UART是集成在单片机内部的,通过TXD引脚发送数据,RXD引脚吸收数据
UART可以分为三个部分,中央为定时器T1——控制波特率;左侧绿框的SBUF用于收发数据;右侧为停止体系
SBUF:串口数据缓存寄存器,物理上是两个独立的寄存器,但占用类似的地点。写利用时,写入的是发送寄存器,读利用时,读出的是吸收寄存器
完备的串口和停止体系模式图如下:

下面通过先容干系寄存器来报告串口通讯的原理
串口干系寄存器


串行口控制寄存器SCON和PCON
STC89C52系列单片机的串行口设有两个控制寄存器:串行控制寄存器SCON波特率选择特别功能寄存器PCON
PCON
电源控制寄存器,大概是电源控制另有剩下比特位,以是波特率选择和帧错误控制位也集成此中,淘汰资源斲丧
格式如下:

我们只要关注SMOD 和 SMOD0 即可


  • SMOD:波特率选择位。当软件置SMOD = 1时,使串行通讯方式1、2、3的波特率更加;SMOD = 0,则不更加。复位时SMOD = 0
  • SMOD0:帧错误检测有用控制位。当SMOD = 1,SCON寄存器中的 SM0/FE 位于 FE(帧错误检测)功能;当SMOD0 = 0,SCON的SM0/FE 用于 和 SM1 组合指定串行口的工作模式。复位时 SMOD0 = 0

SCON
用于选择串行通讯的工作方式和某些控制功能,格式如下:



  • SM0/FE:当PCON寄存器的 SMOD0/FE = 1时,该位用于帧错误检测。当检测到一个无效克制位时,通过UART吸收器设置该位,必须由软件清零;当SMOD0/FE = 0,该位和 SM1 组合指定工作模式



  • REN:答应/克制串行吸收控制位。由软件置位,若REN = 1即答应串行吸收数据;REN = 0则克制吸收
  • SM2:答应方式2或方式3多机通讯控制位。
  • TB8:在方式2或方式3,为要发送的第9位数据,按须要由软件置位或清0。可用作数据的校验位或多机通讯中体现地点帧/数据帧的标志位。
  • RB8:在方式2或方式3,是吸收到的第9位数据。在方式1,若SM2=0,则RB8是吸收到的克制位。方式0不消RB8。
  • TI:发送停止哀求标志位。在方式0,当串行发送数据第8位竣事时,由内部硬件置TI = 1,向主机哀求停止,相应停止后必须用软件复位,即TI = 0。在其他方式中,则在克制位开始发送时由内部硬件置位,必须用软件复位TI = 0
  • RI:吸收停止哀求标志位。在方式0,当串行吸收到第8位竣事时由内部硬件自动置位 RI = 1 ,向主机哀求停止,相应停止后必须用软件复位,即RI=0。在其他方式中,串行吸收到克制位的中央时候由内部硬件置位,即RI=1,必须由软件复位,即RI=0
IE
停止答应寄存器

此中我们只关注EA 和 ES


  • EA:CPU的总停止答应控制位,EA = 1,CPU开放停止;EA = 0,CPU屏蔽全部停止哀求
  • ES:串行口停止答应位,ES = 1,答应串行口停止;ES = 0,克制串行口停止

注意:吸收停止和发送停止共用一个停止,在停止处理处罚函数中还须要通过RI 和 TI 的置位判断本次停止是吸收停止还是发送停止

末了我们回归模式图,讲授一下串口通讯的流程

发送数据
通过总线将数据写入SBUF,定时器1控制波特率。通过TXD发送数据,当发送数据竣事时(方式0为发完8位数据,其他方式为发送克制位时),将 TI = 1,发送停止哀求
吸收数据
RXD吸收数据,通过定时器1控制波特率,对吸收数据举行采样,存放在SBUF,当吸收数据竣事(方式0当串行发送数据第8位竣事时,在其他方式中,则在克制位开始发送时由内部硬件置位),将 RI = 1,发出停止哀求
注意:TI 和 RI 都须要由软件置0
编码

颠末上述学习,我们已经对串口有了肯定的相识,接下来就是实现串口通讯
单片机通过串口发送数据

我们使用UART串口通讯,起首要举行初始化,如:选择工作方式,初始化停止体系,设置波特率,初始化定时器
选择工作模式
涉及到SCON 和 PCON
起首是PCON的SMOD0,当 SMOD0 = 0 时,SMOD 的 SM0 才会被用来选择工作方式
其次,我们选择 8位UART,波特率可变模式,即方式1,SCON的SM0 = 0,SM1 = 1
末了,假如要答应串口吸收数据,还须要置SCON的REN = 1

初始化停止体系
起首,初始化串口收发数据的停止哀求标志位,SCON的 TI 和 RI,由硬件置1,我们初始化时清零即可:TI = 0, RI = 0
到此,SCON的设置就竣事了
总结一下,SM0 = 0, SM1 = 1, REN = 1/0, TI = 0, RI = 0,其他默以为0即可,以是SCON = 0x40/0x50
然后是停止开关

ES = 1, EA = 1
  1. SCON = 0x50;        //选择工作方式 & 允许串口接收数据
  2. PCON |= 0x80;        //使SM0为选择工作方式
  3. //中断开关
  4. ES = 1;                        //串口中断开关
  5. EA = 1;                        //总中断开关
复制代码

初始化定时器
初始化定时器可参看【51单片机】定时器
此处定时器1选择工作模式2——8位自动重装
   8位自动重装
一次只对TL1或TH1计数加一
当一个溢出后,直接使用另一个计数单元的初值
  1. //设置定时器1
  2. TMOD &= 0x0F;        //高4位清零
  3. TMOD |= 0x20;        //0010,模式3——8位自动重载
  4. TR1 = 1;                //启用定时器T1
  5. ET1 = 0;                //禁止定时器T1中断       
  6. //定时器初值
  7. TL1 = 0xF3;                //设定定时初值
  8. TH1 = 0xF3;                //设定定时器重装值
复制代码

设置波特率
我们设置波特率为4800
设置波特率须要通过设置定时器1的初始值
  1. TL1 = 0xF3;                //设定定时初值
  2. TH1 = 0xF3;                //设定定时器重装值
复制代码
讲授一下为什么定时器初值是这个
假设体系频率为12MHz,使用12T模式,则定时器频率为12 / 12 = 1MHz,即每1us,计数单元加1。
使用8位自动重装,256时会溢出,0xF3 = 243,256 - 243 = 13。以是定时器溢出须要13us
溢出率:1 / 13 = 0.07692
使用SMOD = 1,波特率更加(不除2)

还须要 0.07692 / 16 = 0.0048076923MHz
转化为Hz:4807.6923Hz,这个就是波特率
会存在肯定毛病
也可参看如下盘算


到此,串口的初始化就完成了
完备代码如下:
  1. /**
  2.   * @brief                初始化串口
  3.   * @parm                无
  4.   * @retval                无
  5.   */
  6. void UART_Init()
  7. {
  8.         //SCON高4位分别为SM0、SM1、SM2、REN
  9.         //SM0和SM1控制串口模式,选择01——8位UART,波特率可变
  10.         //REN接收使能,REN = 0禁止接收,REN = 1允许接收
  11.         //所以设置0101 0000
  12.         SCON = 0x50;
  13.         //PCON包含波特率和电源设置
  14.         //前两位为SMOD和SMOD0
  15.         //SMOD = 1波特率加倍,SMOD = 0,波特率不加倍
  16.         //SMOD0是帧错误的,此处不用
  17.         //所以设置1000 0000
  18.         PCON |= 0x80;
  19.         //设置定时器1
  20.         TMOD &= 0x0F;        //高4位清零
  21.         TMOD |= 0x20;        //0010,模式3——8位自动重载
  22.         TR1 = 1;                //启用定时器T1
  23.         ET1 = 0;                //禁止定时器T1中断       
  24.         //定时器初值
  25.         TL1 = 0xF4;                //设定定时初值
  26.         TH1 = 0xF4;                //设定定时器重装值
  27.         //中断开关
  28.         ES = 1;                        //串口中断开关
  29.         EA = 1;                        //总中断开关
  30. }
复制代码
博主的单片机体系频率为11.0592MHz
可以使用STC-ICP天生波特率设置代码

注意:设置肯定要选择精确;代码中的AUXR寄存器为高版本单片机才有的,低版本不认识这个寄存器,可以直接删掉

串口发送数据通过赋值SBUF,数据发送完后,硬件置位TI = 1,须要我们手动对TI清零
代码如下:
  1. /**
  2.   * @brief                 通过串口发送一个字节数据
  3.   * @parm                Byte:要发送字节数据
  4.   * @retval                无
  5.   */
  6. void UART_SendByte(unsigned char Byte)
  7. {
  8.         SBUF = Byte;
  9.         while(TI == 0);//数据发送完,硬件置1
  10.         TI = 0;                //软件置0
  11. }
复制代码

模块化编程,完备代码如下:
延时模块——控制串口发送数据速率
Delay.h
  1. #ifndef __DELAY_H__
  2. #define __DELAT_H__
  3. void Delayms(unsigned int xms);//等待指定毫秒
  4. #endif
复制代码
Delay.c
  1. #include <INTRINS.h>
  2. /**
  3.   * @brief  延迟一定时间
  4.   * @parm        延迟的时间,单位是毫秒,范围:0 ~ 65535
  5.   * @retval        无
  6.   */
  7. void Delayms(unsigned int xms)                //@11.0592MHz
  8. {
  9.         while(xms--)
  10.         {
  11.                 unsigned char i, j;
  12.                 _nop_();
  13.                 i = 2;
  14.                 j = 199;
  15.                 do
  16.                 {
  17.                         while (--j);
  18.                 } while (--i);
  19.         }       
  20. }
复制代码

UART串口模块
UART.h
  1. #ifndef __UART_H__
  2. #define __UART_H__
  3. void UART_Init();
  4. void UART_SendByte(unsigned char Byte);
  5. #endif
复制代码
UART.c
  1. #include <REGX52.H>/**
  2.   * @brief                初始化串口
  3.   * @parm                无
  4.   * @retval                无
  5.   */
  6. void UART_Init()
  7. {
  8.         //SCON高4位分别为SM0、SM1、SM2、REN
  9.         //SM0和SM1控制串口模式,选择01——8位UART,波特率可变
  10.         //REN接收使能,REN = 0禁止接收,REN = 1允许接收
  11.         //所以设置0101 0000
  12.         SCON = 0x50;
  13.         //PCON包含波特率和电源设置
  14.         //前两位为SMOD和SMOD0
  15.         //SMOD = 1波特率加倍,SMOD = 0,波特率不加倍
  16.         //SMOD0是帧错误的,此处不用
  17.         //所以设置1000 0000
  18.         PCON |= 0x80;
  19.         //设置定时器1
  20.         TMOD &= 0x0F;        //高4位清零
  21.         TMOD |= 0x20;        //0010,模式3——8位自动重载
  22.         TR1 = 1;                //启用定时器T1
  23.         ET1 = 0;                //禁止定时器T1中断       
  24.         //定时器初值
  25.         TL1 = 0xF4;                //设定定时初值
  26.         TH1 = 0xF4;                //设定定时器重装值
  27.         //中断开关
  28.         ES = 1;                        //串口中断开关
  29.         EA = 1;                        //总中断开关
  30. }
  31. /**  * @brief                 通过串口发送一个字节数据  * @parm                Byte 要发送字节数据  * @retval                无  */void UART_SendByte(unsigned char Byte){        SBUF = Byte;        while(TI == 0);//数据发送完,硬件置1        TI = 0;                //软件置0}///**//  * @brief                 吸收数据 模版//  * @parm                        无//  * @retval                无//  *///void UART_Routine() interrupt 4//{//        if(RI == 1)//检测是否是吸收数据停止//        {//                RI = 0;//软件置0//        }//}
复制代码

主步调——每隔一秒通过串口发送递增数据
  1. #include <REGX52.H>
  2. #include "UART.h"
  3. #include "Delay.h"
  4. /**
  5.   * @brief                通过串口每隔1s发送递增的数据 范围:0 ~ 255
  6.   * @parm                无
  7.   * @retval                无
  8.   */
  9. void SendIncreasingNum()
  10. {
  11.         static unsigned char num;
  12.         UART_SendByte(num++);
  13.         Delayms(1000);
  14. }
  15. void main()
  16. {
  17.         UART_Init();
  18.     while(1)
  19.     {
  20.         SendIncreasingNum();
  21.     }
  22. }
复制代码
使用STC-IST 的 串口助手 检察结果

注意:下面一行的设置要精确
电脑通过串口发送数据控制LED灯

电脑发送数据给单片机须要USB转串口,自带的USB线就已经实现了这一转换,以是我们直接编写单片机通过串口吸收数据的逻辑即可。
串口吸收数据会存放在SBUF,吸收完毕后会将RI置1,发出停止哀求,停止号为4,然后须要手动清零RI
代码如下:
  1. void UART_Routine() interrupt 4
  2. {
  3.         if(RI == 1)//检测是否是接收数据中断
  4.         {
  5.                 P2 = SBUF;
  6.                 RI = 0;//软件置0
  7.         }
  8. }
复制代码
注意:P2寄存器用于控制LED亮灭,为0亮起,为1熄灭
还可以将数据重新返回给电脑,同样使用Delay 和 UART 模块,只有main.c差别
main.c
  1. #include <REGX52.H>
  2. #include "UART.h"
  3. #include "Delay.h"
  4. /**
  5.   * @brief                 接收数据,亮相应的灯,并返回数据
  6.   * @parm                无
  7.   * @retval                无
  8.   */
  9. void UART_Routine() interrupt 4
  10. {
  11.         if(RI == 1)//检测是否是接收数据中断
  12.         {
  13.                 P2 = SBUF;
  14.                 UART_SendByte(SBUF);
  15.                 RI = 0;//软件置0
  16.         }
  17. }
  18. void main()
  19. {
  20.         UART_Init();
  21.     while(1)
  22.     {
  23.         
  24.     }
  25. }
复制代码
结果如下:
我们通过串口助手,发送 0xAA = 1010 1010

LED灯结果如下:


以上就是本篇博客的全部内容,感谢你的阅读
假如以为本篇文章对你有所资助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很告急。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表