stm32之波特率、USART
先说一下波特率,下面抄自百度:
波特率表示每秒钟传送的码元符号的个数,是衡量数据传送速率的指标,它用单位时间内载波调制状态改变的次数来表示。在信息传输通道中,携带数据信息的信号单元叫码元,每秒钟通过信道传输的码元数称为码元传输速率,简称波特率。波特率是传输通道频宽的指标。
好的,那么怎么配置波特率?
原理图如下:
就是用最下面这两个公式去计算和配置波特率。
配置什么东西,肯定要看看寄存器。。。
和上面的原理图相似,波特率分为整数和小数部分,分别把这两个和单片机的时钟带进公式,就能得到波特率了
代码如下:(M4的USART时钟波特率是84MHZ,所以下面写成84000000ul)
usart_div = (float)84000000ul / (DEBUG_USART_BOUND * 16); div_mantissa = (u16)usart_div; //得到整数部分 div_fraction = (usart_div - div_mantissa) * 16 + 0.5;//四舍五入 USART1->BRR = (div_mantissa << 4) + div_fraction; //设置波特率
下面说说串口USART:
代码如下:
初始化USART(本代码中顺带加入了中断;本例中引脚为PA9)
void debug_usart_init(void) { float usart_div = 0; u16 div_mantissa = 0; u16 div_fraction = 0; debug_usart_port_init(); RCC->APB2ENR |= (0X1 << 4); //开启USART1的时钟 usart_div = (float)84000000ul / (DEBUG_USART_BOUND * 16); div_mantissa = (u16)usart_div; //得到整数部分 div_fraction = (usart_div - div_mantissa) * 16 + 0.5;//四舍五入 USART1->BRR = (div_mantissa << 4) + div_fraction; //设置波特率 USART1->CR1 = 0;//清空所有配置 USART1->CR1 |= (0X1 << 3);//发送器使能 USART1->CR1 |= (0X1 << 2);//接收器使能 USART1->CR1 |= (0X1 << 13);//使能USART1 USART1->CR2 &= ~(0X3 << 12);//停止位为1个位 uint32_t priority = 0; //保存合成的优先级值 NVIC_SetPriorityGrouping(7 - 2); priority = NVIC_EncodePriority(7 - 2, 2, 2); NVIC_SetPriority(USART1_IRQn, priority); //以USART1为例 //根据外设寄存器配置----需要掌握该外设相关的寄存器 USART1->CR1 |= (0X1 << 5);//接收中断使能 NVIC_EnableIRQ(USART1_IRQn); //以USART1为例 }
USART的中断服务函数:
void USART1_IRQHandler(void) { uint8_t receive_data = 0; //如果接收到数据,产生接收标志位 if(USART1->SR & (0x1 << 5)) { USART1->SR &= ~(0x1 << 5); //清除标志位 //读取接收缓冲区中的数据 receive_data = USART1->DR; dubug_usart_write_byte_data(receive_data); //将接收到的字节数据发送出去 } }
发送和接受数据函数:
/* *********************************************************************************************** * 函数功能: 发送一个字节数据 * 函数形参: writedata 需要发送的数据 * 函数返回值: None * 备注: None * 作者: * 时间: * 修改作者: None * 修改时间: None *********************************************************************************************** */ void dubug_usart_write_byte_data(uint8_t writedata) { //等待发送缓冲区空 while(!(USART1->SR & (0X1 << 7))) { } //发送缓冲区已经空了 //发送数据 USART1->DR = writedata; } /* *********************************************************************************************** * 函数功能: 接收一个字节数据 * 函数形参: None * 函数返回值: 接收到的数据 * 备注: None * 作者: * 时间: * 修改作者: None * 修改时间: None *********************************************************************************************** */ uint8_t dubug_usart_read_byte_data(void) { //等待接收缓冲区非空 while(!(USART1->SR & (0X1 << 5))) { } //接收缓冲区非空,有数据 //读取数据 return USART1->DR; } /* *********************************************************************************************** * 函数功能: 接收一串字符数据 * 函数形参: *string 用来存储接收到的字符串 * 函数返回值: None * 备注: None * 作者: * 时间: * 修改作者: None * 修改时间: None *********************************************************************************************** */ void debug_usart_recivied_string(uint8_t *string) { while(1) { //等待接收缓冲区非空 while(!(USART1->SR & (0X1 << 5))) { } //接收缓冲区非空,有数据 //读取数据 *string = USART1->DR; //如果接收到的字符为'\r'或'\n'认为接收字符串完成 if(*string == '\r' || *string == '\n') { *string = '\0'; //不存储'\r'或'\n',存储一个字符串结束标志 break; } string++; } }
实现printf()功能的代码 ,直接加进去就好:
#pragma import(__use_no_semihosting_swi) //取消半主机状态 struct __FILE { int handle; /* Add whatever you need here */ }; FILE __stdout; int fputc(int ch, FILE *f) { while((USART1->SR &(0X01<<7))==0); //等待之前的数据发送完毕 USART1->DR=ch; return (ch); } int ferror(FILE *f) { /* Your implementation of ferror */ return EOF; } void _ttywrch(int ch) { while((USART1->SR &(0X01<<7))==0); USART1->DR=ch; } void _sys_exit(int return_code) { label: goto label; /* endless loop */ }
84000000