【STM32开发之寄存器版】(二)-USART

一、前言

串口作为STM32的重要外设,对程序调试具有不可替代的作用。通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换。USART利用分数波特率发生器提供宽范围的波特率选择。其主要具备以下特性:

  • 支持全双工的异步通信
  • 支持LIN(局部互联网)
  • 支持智能卡协议和IrDA(红外数据组织)SIR ENDEC规范
  • 支持调制解调器(CTS/RTS)操作
  • 支持多处理器通信
  • 支持使用多缓冲器配置的DMA方式,实现高速数据通信。

STM32F103ZET6具备多达5路串口,本文将使用USART1(PA9/PA10)实现串口回环测试DEMO。

二、串口通信原理与时序

2.1 USART和UART的区别

STM32F103ZET6具备5个串口,其中串口1,2,3均为USART(通用同步异步收发传输器),串口4,5为UART(通用异步收发传输器)。他们的区别如下:

  • 同步与异步UART仅支持异步通信,数据在没有时钟信号的情况下进行传输,发送和接收双方必须在波特率等设置上保持一致;USART支持同步和异步两种通信模式。在同步模式下,它使用额外的时钟信号来同步数据的发送和接收。
  • 信号引脚USART1、USART2和USART3接口具有硬件的CTS和RTS信号管理、兼容ISO7816的智能卡模式和类SPI通信模式,除了UART5之外所有其他接口都可以使用DMA操作。
  • 数据传输可靠性UART数据传输仅依赖于预设的波特率,没有时钟信号,因此数据传输的可靠性可能受到干扰;USART在同步模式下,数据传输更加可靠,因为有时钟信号来确保数据的正确接收和发送。USART1接口通信速率可达4.5兆位/秒,其他接口的通信速率可达2.25兆位/秒。

2.2 串口通信的硬件组成

USART1由6根线组成,如下所示:

USART1线束功能
USART1_TX发送数据引脚
USART1_RX接受数据引脚
USART1_CK用于输出同步信号传输的时钟
USART1_CTS用于流量控制的清除发送引脚,若是高电平,在当前数据传输结束时阻断下一次的数据发送。
USART1_RTS用于流量控制的发送请求引脚,若是低电平,表明USART准备好接收数据。
GND接地

其中,同步模式下的CK引脚以及用于流量控制的CTS/RTS引脚不常用,而TX/RX/GND引脚是串口通信中不可或缺的,因此本文只关注这三个引脚。

2.3 串口通信的通讯方式

从传输数据的方向性和同时性上划分,串口通信主要被分为全双工、半双工和单工模式:

  • 全双工模式:允许数据在两个通信设备之间同时双向传输。
  • 半双工模式:数据可以在两个通信设备之间双向传输,但不能同时进行。
  • 单工模式:数据只能单向传输,不能同时发送和接收。

STM32F103ZET6的USART1通讯方式是全双工的。

2.4 串口通信的时序要求和数据格式

串口通信的时序要求如下所示:

每一个字符帧都满足以下数据格式:

字符帧的位含义
起始位每个数据帧的开始部分,通常是一个低电平信号。
数据位实际传输的数据部分,可以是8位、7位或9位,具体取决于配置。每个位依次从最低有效位(LSB)到最高有效位(MSB)传输(小端传输)。
校验位在数据位后添加一个校验位,可以帮助检测数据在传输过程中是否发生了错误。校验方式有奇偶校验
停止位数据帧的结束部分,通常是一个高电平信号。一般来讲,停止位有1,1.5,2个单位时间三种长度。
空闲位处于逻辑1状态, 表示当前线路上没有数据传送。

2.5 串口通信的奇校验和偶校验

在标准ASCII码中,其最高位(b7)用作奇偶校验位。所谓奇偶校验,是指在代码传送过程中用来检验是否出现错误的一种方法,一般分奇校验和偶校验两种。奇校验规定:正确的代码一个字节中1的个数必须是奇数,若非奇数,则在最高位b7添1;偶校验规定:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位b7添1。

2.6 串口通信的波特率

波特率(Baud Rate)是串行通信中衡量数据传输速度的一个重要参数,定义为每秒钟传输的符号(信号变化)次数,通常以bps(bits per second,位/秒)为单位。

三、时钟树配置

从《STM32中文参考手册》可知,USART1是归属APB2总线下的外设,其时钟来源为APB2的外设时钟PCLK2。APB2时钟来源于AHB时钟,AHB时钟来源于经锁相环PLL倍频后的外部8MHz高速时钟HSE。具体时钟树配置流程如下所示。

时钟树配置代码在正点原子官方例程SYSTEM/sys.c下实现:

void Stm32_Clock_Init(u8 PLL)
{
	unsigned char temp=0;   
	MYRCC_DeInit();		  //复位并配置向量表
 	RCC->CR|=0x00010000;  //外部高速时钟使能HSEON
	while(!(RCC->CR>>17));//等待外部时钟就绪
	RCC->CFGR=0X00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1;
	PLL-=2;				  //抵消2个单位(因为是从2开始的,设置0就是2)
	RCC->CFGR|=PLL<<18;   //设置PLL值 2~16
	RCC->CFGR|=1<<16;	  //PLLSRC ON 
	FLASH->ACR|=0x32;	  //FLASH 2个延时周期
	RCC->CR|=0x01000000;  //PLLON
	while(!(RCC->CR>>25));//等待PLL锁定
	RCC->CFGR|=0x00000002;//PLL作为系统时钟	 
	while(temp!=0x02)     //等待PLL作为系统时钟设置成功
	{   
		temp=RCC->CFGR>>2;
		temp&=0x03;
	}    
}		    

调用该函数时,函数传参PLL倍频为9, 最终串口1获得的基础时钟频率PCLK2为72MHz。 

四、寄存器介绍

实现USART1的功能主要涉及以下寄存器:

寄存器功能
APB2ENR
APB2 外设时钟使能寄存器
GPIOx_CRH
端口配置高寄存器
APB2RSTR
APB2 外设复位寄存器
USART_BRR
波特比率寄存器
USART_CR1
控制寄存器 1
USART_SR
状态寄存器
USART_DR
数据寄存器

下面将对这些寄存器进行一一介绍。

4.1  APB2ENR外设时钟使能寄存器

《STM32中文参考手册》对APB2ENR寄存器的描述如下:

毋庸置疑,本文需要将USART1时钟使能,即将位14置1

除此以外,本文用到的串口1的TX和RX分别是PA9和PA10,因此需要使能IO端口A的时钟,即将位2置1

4.2 GPIOx_CRH端口配置高寄存器

《STM32中文参考手册》对GPIOx_CRH寄存器的描述如下:

 本文使用PA9和PA10作为串口1的功能端口,因此需要按照如下要求进行配置:

GPIO端口复用功能配置GPIO配置
PA9
USART1_TX
全双工模式推挽复用输出
PA10USART1_RX全双工模式浮空输入或上拉输入

因此,需要按照如下进行配置:

GPIO端口寄存器配置
PA9GPIOA_CRH[7:6] = 0b10
GPIOA_CRH[5:4] = 0b11
PA10GPIOA_CRH[11:10] = 0b10
GPIOA_CRH[9:8] = 0b00

4.3  APB2RSTR外设复位寄存器

《STM32中文参考手册》对APB2RSTR寄存器的描述如下:

本次DEMO仅需将USART1复位即可,故仅需将 APB2RSTR的第14位 置1 后再 置0 即可复位

4.4 USART_BRR波特比率寄存器

《STM32中文参考手册》对USART_BRR寄存器的描述如下:

STM32F103ZET6的USART1波特率计算方法如下:

若设置USART1的波特率为115200bps,按照如下方式求得USART_BRR寄存器的值:

  • 由第三节时钟树配置可知,USART1的时钟来源PCLK2为72MHz。
  • USARTDIV=fPCLK2/(16*bound)=72000000/(16*115200)=39.0625
  • 故DIV_Mantissa[11:0]=39=0X27
  • 故DIV_Fraction[3:0]=0.0625*16=1=0X1
  • USART_BRR寄存器的值为(DIV_Mantissa[11:0]<<4)|(DIV_Fraction[3:0])=0X0271

4.5 USART_SR状态寄存器

《STM32中文参考手册》对USART_SR寄存器的描述如下:

其中,仅重点关注TXE、TC和RXNE标志位。当发送寄存器为空时,TXE为1;当发送完成时,TC为1,;当读寄存器非空,即接收到数据时,RXNE为1。

4.6 USART_CR1控制寄存器 1

《STM32中文参考手册》对USART_CR1寄存器的描述如下:

 其中,仅需重点关注以下几位:

标志位功能用法
13:UE串口使能位置1
12:M字长选择位,当该位为 0 的时候设置串口为 8 个字长外加 n 个停止
位,停止位的个数(n)是根据 USART_CR2 的[13:12]位设置来决定的,默认为 0。
置0
10:PCE
校验使能位,设置为 0,则禁止校验,否则使能校验。  
置0
9:PS
校验位选择,设置为 0 则为偶校验,否则为奇校验
/
7:TXEIE
发送缓冲区空中断使能位,设置该位为 1,当 USART_SR 中的 TXE 位为1 时,将产生串口中断。
置1
6:TCIE
发送完成中断使能位,设置该位为 1,当 USART_SR 中的 TC 位为 1 时,将产生串口中断。
置1
5:RXNEIE
RXNEIE 为接收缓冲区非空中断使能,设置该位为 1,当USART_SR 中的 ORE 或者 RXNE 位为1时,将产生串口中断。
置1
3:TE
发送使能位
置1
2:RE
接收使能位
置1

4.7 USART_DR数据寄存器

《STM32中文参考手册》对USART_DR寄存器的描述如下:

将数据放入TDR中即可发送,同理,可以从RDR中读出接收到的数据。 

五、硬件连接

  1. 将以上跳线帽接好,即将USART1接到板载CH340 USB转串口芯片上。
  2. 将USB线接到USB_SLAVE端口。

六、程序设计

6.1 USART1初始化

本函数位于SYSTEM/usart.c/uart_init(),该函数主要进行串口波特率设置(参考4.4)、使能A口和串口1外设时钟(参考4.1),设置端口复用(参考4.2),复位串口1(参考4.3)、使能接收中断(参考4.6)。具体代码如下所示:

void uart_init(u32 pclk2,u32 bound)
{  	 
	float temp;
	u16 mantissa;
	u16 fraction;	   
	temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV
	mantissa=temp;				 //得到整数部分
	fraction=(temp-mantissa)*16; //得到小数部分	 
    mantissa<<=4;
	mantissa+=fraction; 
	RCC->APB2ENR|=1<<2;   //使能PORTA口时钟  
	RCC->APB2ENR|=1<<14;  //使能串口时钟 
	GPIOA->CRH&=0XFFFFF00F;//IO状态设置
	GPIOA->CRH|=0X000008B0;//IO状态设置 
	RCC->APB2RSTR|=1<<14;   //复位串口1
	RCC->APB2RSTR&=~(1<<14);//停止复位	   	   
	//波特率设置
 	USART1->BRR=mantissa; // 波特率设置	 
	USART1->CR1|=0X200C;  //1位停止,无校验位.
#if EN_USART1_RX		  //如果使能了接收
	//使能接收中断 
	USART1->CR1|=1<<5;    //接收缓冲区非空中断使能	    	
	MY_NVIC_Init(3,3,USART1_IRQn,2);//组2,最低优先级 
#endif
}

6.2 USART1接收中断函数

本函数位于SYSTEM/usart.c/USART1_IRQHandler(),主要通过定义一个标志USART_RX_STA,其bit15为接收完成标志位,bit14为接收到0X0d标志位,bit13-bit0为Buf计数。接收到的数据需要以0X0d 0X0a结尾。具体流程如下图所示:

具体实现如下所示:

#if EN_USART1_RX   //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   	
u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15,	接收完成标志
//bit14,	接收到0x0d
//bit13~0,	接收到的有效字节数目
u16 USART_RX_STA=0;       //接收状态标记	  
  
void USART1_IRQHandler(void)
{
	u8 res;	
	if(USART1->SR&(1<<5))	//接收到数据
	{	 
		res=USART1->DR; 
		if((USART_RX_STA&0x8000)==0)//接收未完成
		{
			if(USART_RX_STA&0x4000)//接收到了0x0d
			{
				if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				else USART_RX_STA|=0x8000;	//接收完成了 
			}else //还没收到0X0D
			{	
				if(res==0x0d)USART_RX_STA|=0x4000;
				else
				{
					USART_RX_BUF[USART_RX_STA&0X3FFF]=res;
					USART_RX_STA++;
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
				}		 
			}
		}  		 									     
	}
}

6.3 printf函数重定向

本函数位于SYSTEM/usart.c/fputc(),主要是将fputc重定向到USART1上。

int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//等待上一次串口数据发送完成  
	USART1->DR = (u8) ch;      	//写DR,串口1将发送数据
	return ch;
}

6.4 轮询主函数

本函数位于USER/test.c,主要是通过USART_RX_STA获得接收到的信息长度,并将信息按照字节通过USART1->DR发送出去,利用USART_SR->TC判断是否发送完成。进而形成USART回环。具体代码如下所示:

#include "sys.h"
#include "usart.h"		
#include "delay.h"	
#include "led.h" 
#include "beep.h" 
#include "key.h"	 	 

int main(void)
{								  
	u16 t; 
	u16 len;	
	u16 times=0;    
	Stm32_Clock_Init(9);	//系统时钟设置
	uart_init(72,115200); 	//串口初始化为115200
	delay_init(72);	   	 	//延时初始化 
	LED_Init();		  		//初始化与LED连接的硬件接口 
 	while(1)
	{
		if(USART_RX_STA&0x8000)
		{					   
			len=USART_RX_STA&0x3FFF;//得到此次接收到的数据长度
			printf("\r\n您发送的消息为:\r\n\r\n");
			for(t=0;t<len;t++)
			{
				USART1->DR=USART_RX_BUF[t];
				while((USART1->SR&0X40)==0);//等待发送结束
			}
			printf("\r\n\r\n");//插入换行
			USART_RX_STA=0;
		}else
		{
			times++;
			if(times%5000==0)
			{
				printf("\r\n串口USART1寄存器实验\r\n");
			}
			if(times%200==0)printf("请输入数据,以回车键结束\r\n");  
			if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
			delay_ms(10);   
		}
	}		 
}

完整版代码见正点原子官方:【正点原子】精英STM32F103开发板\【正点原子】精英STM32F103开发板资料 资料盘(A盘)\4,程序源码\1,标准例程-寄存器版本\1,标准例程-寄存器版本\实验4 串口实验

七、上机测试

使用XCOM查看串口发送的数据,并测试串口回环:

至此测试成功! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值