简介

串口通信详解

寄存器版本

寄存器

使能串口时钟

串口 1 的时钟使能在 APB2ENR 寄存器,
其他串口的时钟使能位都在 APB1ENR 寄存器
串口1的时钟是在APB2ENR寄存器的第14位

串口复位

当外设出现异常的时候可以通过复位寄存器里面的对应位设置,实现该外设的复位,然后重新配置这个外设达到让其重新工作的目的。一般在系统刚开始配置外设的时候,都会先执行复位该外设的操作。
串口 1 的复位是通过配置 APB2RSTR 寄存器的第 14 位来实现的。

串口波特率设置

STM32 的每个串口都有一个自己独立的波特率寄存器USART_BRR,通过设置该寄存器就可以达到配置不同波特率的目的。

USART_BRR 的最低 4 位(位[3:0])用来存放小数部分DIV_Fraction,紧接着的 12 位(位[15:4])用来存放整数部分 DIV_Mantissa,最高 16 位未使用。

串口波特率计算公式

protues stm32 串口1 stm32f103c8t6串口1_初始化


假设我们的串口 1 要设置为 115200 的波特率,而 PCLK2 的时钟为 72M。这样,我们根据上面的公式有:

USARTDIV=72000000/(11520016)= 39.0625
那么得到:
DIV_Fractinotallow=16
0. 0625=1=0X01;

DIV_Mantissa=39=0X27;

只要设置串口 1 的 BRR 寄存器值为0X0271 就可以得到 115200 的波特率

串口

串口初始化

//初始化 IO 串口 1
//pclk2:PCLK2 时钟频率(Mhz)
//bound:波特率
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
}

串口中断

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;
					//接收数据错误,重新开始接收 
				}
			}
		} 
	}
}