UART异步串行通信协议

UART概述

UART的定义

  • UART简介

    USART指通用同步收发器,UART指通用异步收发器

    这些通用收发器提供了一种灵活的方式与外部设备进行全双工方式(也支持其他方式,见下文)的数据交互,并且可配置多种波特率,支持多种通信协议和功能模式等
    UART一般用于单对单的通信(也可以通过一些硬件上的手段实现一个主设备发送、多个从设备接收的通信,但是不能实现多主机通信,此文不深入探讨此问题)

  • UART的引脚

    因为UART是异步通信,其结构相对简单,只需要两条数据线即可,即TX与RX,分别用作发送与接收数据,实现全双工通信

    它们与GPIO引脚功能复用,一般来说PD6为RX,PD5为TX,具体引脚要查阅数据手册,在使用时要对引脚进行初始化

  • TX(PD5):发送数据,使用时配置为OD输出

  • RX(PD6):接收数据,使用时配置为上拉输入

UART的类别

  • STM8S单片机片内总共有3个串口资源:UART1/2/3(STM8S105则只有UART2这个串口资源,具体情况查阅对应型号的数据手册)

  • UART1/2/3之间在功能支持上存在差异,见下图:
    UART一般用作全双工通信,额外的:UART1支持仅需一根线的半双工模式,UART1与2支持单向通信模式

    image

UART配置流程

UART配置简述

  1. 主时钟频率配置

    确定主时钟,这与后续波特率的设置相关

  2. 配置通信数据帧格式

    设定发送/接收数据位数

    设定发送/接收数据校验位以及校验方式(可选),

    设定发送/接收数据停止位位数

  3. 计算并配置波特率

    设定发送/接收数据波特率

  4. 使能发送/接收中断功能

    此步可选,让单片机发送出数据/接收到数据时进入中断服务程序

  5. 使能发送/接收功能

    使能之后,然后就开始向寄存器写入数据以发送/接收单字节数据,并等待发送/接收完毕

UART相关寄存器

  • 控制寄存器UART_CR1

    明确发送的数据帧格式,配置奇偶校验

    • 本寄存器的M位(位4)配置数据帧的格式(UART数据字长度由此位决定):

      配置为1,数据帧格式为1个起始位,8个数据位,n个停止位(取决于另一个寄存器UART_CR3中的STOP[1:0]位)

      配置为1,数据帧格式为1个起始位,9个数据位,1个停止位;此时需要本寄存器的T8位(位6)与R8位(位7)用以储存发送与接收的第九位

    • PIEN位(位0)、PS位(位1)与PCEN位(位2)用于配置校验:

      PCEN位配置为1则使能硬件奇偶校验控制(校验位的启用状态将导致数据帧格式变化,例如:M位为1且PCEN位也为1,则数据帧有1起始位+8数据位+1校验位+停止位,校验位将挤占一个数据位);

      PS位用于选择校验方式,0使能偶校验,1则使能奇校验;

      PIEN位配置为1则使能校验中断,当发生数据校验错误时产生中断

    各个位的具体作用

    image

  • 控制寄存器UART_CR3

    配置数据的停止位

    • STM8单片机通信的停止位可以设定为1位/1.5位/2位,通过对本寄存器的STOP[1:0]位(由位5与4共同组成)配置得到:写入00则为1位,10为2位,11为1.5位

    各个位的具体作用(其它位在UART3上不存在):

    image

  • 控制寄存器UART_CR2

    使能发送/接收功能,配置发送/接收中断

    • 配置好数据帧格式后,配置发送功能位TEN位(位3)为1以使能发送,配置接收功能位REN位(位2)为1以使能接收
    • 如果需要检测数据是否被硬件传送到移位寄存器中,可以将发送数据中断使能位TIEN位(位7)置1;如果需要检测数据是否发送完毕,可以将发送完成中断使能位TCIEN位(位6)置1
    • 如果需要检测是否接收到数据,可以将接收中断使能位RIEN位(位5)置1

    各个位的具体功能:

    image

  • 波特率寄存器UART_BRR1/2

    收发双方波特率应当匹配,配置波特率流程如下:

    1. 确定主时钟频率fMASTER

    2. 确定预设波特率:串口收发波特率=fMASTER/UART_DIV(串口分频值)

    3. 计算UART_DIV取值:例如欲设定波特率为9600bps,而主时钟频率为fHSI/2=8MHz,则根据公式可计算得UART_DIV=8.33.33,取833

      在连续大数据量通信时这样的误差会导致缺码,可以把时钟源切换为更高精度的外部时钟源以减小误差

    4. 配置波特率寄存器:将计算得的数值转换为十六进制,得0341HEX,配置如下

      image

      UART_BRR1的0至7位均为UART_DIV位,定义了UART分频数的中间8位(第二、第三半位元),UART_BRR2的7至4位则是分频数的高四位,3到0位是低四位

    • 特别注意,计算出的分频值不应小于16,且UART_BRR1不能被赋值为0,否则会关闭波特率时钟导致无法通信,若中间两位恰好为0则需要重新设定波特率或改变主时钟频率
  • 数据状态寄存器UART_SR

    用于反映通信过程中的一些状态变化,例如:

    • 检测数据是否出错:发生奇偶校验错误时,此寄存器的PE位(位0)会被置1;
    • 检测发送数据是否移入寄存器:开启发送数据中断使能(UART_CR2的TIEN位(位7)置1),此时UART_SR的TXE位(位7)为1时产生中断(表示数据已经被转入寄存器);
    • 检测数据是否发送完毕:开启发送完成中断使能(UART_CR2的TCIEN位(位7)置1),此时UART_SR的TC位(位6)为1时产生中断(表示发送已经完成);
    • 检测接收到数据:开启接收中断使能(UART_CR2的RIEN位(位5)置1),此时UART_SR的RXNE位(位5)或OR位(位3)为1时产生中断(表示收到数据);

    各个位的具体含义:

    image

  • 数据寄存器UART_DR

    内部分为数据发送寄存器TDR与数据接收寄存器RDR

    上述寄存器配置完成后,即完成了对数据帧格式的约定与功能位的使能,就可以进入正常的发送/接收程序了,发送过程只需将欲发送的数据传入串口数据寄存器UART_DR即可

代码实现

  • 初始化UART
    //初始化函数,用于配置UART2的波特率与数据帧格式,并最后使能UART2
    void UART2_init()
    {
    	//首先初始化UART2的TX与RX,以PD6复用RX,PD5复用TX为例
    	PD_DDR=0x20;		//TXD设置为OD输出
    	PD_CR1=0x40;		//RXD设置为上拉输入
    	PD_CR2=0x00;		//全部低速率
    
    	UART2_BRR2 = 0x00;	//设置波特率寄存器,先设置BRR2再设置1
    	UART2_BRR1 = 0x0D;	// 2M/9600,换算为十六进制为000D
    	//具体配置事项见寄存器UART_BRR介绍,此处使用默认时钟2MHz,波特率为9600
    
    	UART2_CR1 = 0x00;			//设置数据帧格式:8个数据位,无校验位
    	UART2_CR3 = 0x00;			//设置 1个停止位
    	UART2_CR2 = 0x2C;			//使能发送、接收以及接收中断
    	//0010 1100 三个1分别对应RIEN位接收中断 TEN位发送使能 REN位接收使能
    }
    
  • 发送程序
    //让单片机通过UART向外发送数据
    //原理:利用UART_SR状态寄存器判断当前发送的进程,以作出不同反应
    void UART2_SendStr(unsigned char *s)	//传入指向欲发送字符的指针
    {
    	while(*s != '\0')	//当发送未到达终止位时
    	{
    		while(UART2_SR & 0x80==0);
    		//1000 0000,UART_SR的TXE位为1时表示数据已经被转入寄存器
    		//当TXE位还不是1时等待,以让数据从数据发送寄存器转移到 Transmit shift register
    
    		UART2_DR = *s;	//发送数据寄存器装填当前指向的一位
    		s++;			//指针指向下一位
    
    		while((UART2_SR & 0x40)== 0);
    		//0100 0000,UART_SR的TC位为1时表示数据发送已经完成
    		//当TC位还不是1的时候等待,以待数据发送完成
    	}
    }
    
  • 接收程序
    //让单片机读取自UART发送来的数据
    //原理:开启接收中断后,将接收程序写在中断服务函数中
    unsigned int ReceiveData=0xFF;//用一个变量存放接收到的数据
    #pragma vector=23	//UART2中断向量号为21
    __interrupt void UART2_Receive_Interrupt(void)
    {
    	while(UART2_SR & 0x20 == 0);//等待数据接收完成
    	ReceiveData = UART2_DR;	//保存接收而来的数据
    }
    
  • 与电脑进行串口通信的实验设计
    1. 在实验之前,先在电脑上打开“串口调试助手”这个软件(有很多软件都可以实现电脑与单片机的串口通信功能,自行搜索选择一个下载即可)

    2. 然后,使用USB线将电脑和单片机连接起来(一般的开发板上会有USB-UART接口),在串口调试助手的串口选择中选择USB连接的串口

      需要注意的是,电脑未必能识别出这个串口,原因是电脑系统没有你的单片机上的USB-UART芯片的相应驱动,解决方法是看你的开发板上使用的USB-UART芯片型号(比如PL-2303),下载对应驱动安装

      如果还是找不到串口,很可能是因为新的Win系统不支持这个驱动,打开电脑的设备管理器,在“通用串行总线控制器”中刚刚安装的驱动有没有带三角感叹号标识,如果有的话卸载它,去网上搜索其他能够兼容的版本

    3. 在软件中设置波特率、停止位、校验位、数据位等与单片机程序一致,打开串口

    4. 实验现象是:发送0到3不同的数时,分别控制PB0-3连接的LED灯亮灭,然后在接收窗口中应该就能看到单片机发送的数据

    实验代码很简单,首先写好上文提到的初始化、发送与接收函数,再调用

    unsigned char StringBuf[]="Hello,world! \r\n";
    void main(void)
    {
    	GPIO_init();//对LED灯初始化
    	UART2_init();
    	asm("RIM");
    	while(1)
    	{
    		UART2_SendStr(StringBuf);//发送字符串
    		delay_ms(3000);
    	}
    }
    
    #pragma vector=23
    __interrupt void UART2_Receive_Interrupt(void)
    {
    	while(UART2_SR & 0x20 == 0);
    	ReceiveData = UART2_DR;
    	switch(ReceiveData)
    	{
    		case 0:PB_ODR_ODR0 = !PB_ODR_ODR0; break;
    		case 1:PB_ODR_ODR1 = !PB_ODR_ODR1; break;
    		case 2:PB_ODR_ODR2 = !PB_ODR_ODR2; break;
    		case 3:PB_ODR_ODR3 = !PB_ODR_ODR3; break;
    	}
    }
    

posted on   无术师  阅读(25)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤

统计

点击右上角即可分享
微信分享提示