为什么需要波特率自动检测机制
- 我们都知道,串口通讯是需要约定波特率才能够进行准确的通讯。
- 此时假设,你们公司开发了一个板子,有一个串口与外接设备进行通讯。因为你们公司开发的产品要提供给多个客户,而有些客户可能之前就有一个类似功能的产品,之所以现在用你们公司的产品,可能是基于安全,价格,稳定性等因素考虑。
- 现在,你规定自己板子上的串口波特率为
115200
,而你客户之前用的那个产品波特率是9600
。你板子都要卖给客户,总不可能要求客户去该他们的波特率吧。好,你们公司为了保住这个订单,现在修改波特率为9600
,然后安排人将程序重新烧录到产品中。 - 这个订单是保住了,现在又来了一个客户,他们也想要用你们的产品,不过他们的波特率是
19200
。没办法,客户是上帝,你们又得重新修改波特率,然后烧录。 - 人工成本也是钱呀,所以说,如果不提出一个好的解决办法,这家公司迟早会凉凉。
- 为了解决这个问题,我们可用用
0x55/0xAA
这两个特殊值进行处理。
波特率自动检测机制的原理
- 我们知道
0x55/0xAA
从二进制角度来看,就是变化的0
和1
。我们知道,0
是低电平,1
是高电平。而0x55/0xAA
这两个特殊的值每次变化时候,他们的0
和1
都是1bit
。因此,我们只需要计算出一个高电平或者一个低电平的持续时间,即可算出波特率。 - 例如,现在我们截取
0x55/0xAA
波形中的一小段如下。现在如果我想知道这里的波特率,只需要测量出图中所指示的低电平部分持续时间即可。 - 测量低电平持续时间也很简单,打开
MCU
的双边沿检测。对端设备串口发送0x55/0xAA
,此时MCU
检测到下降沿那么就打开定时器,当检测到上升沿那么就关闭定时器。最终将定时器中的值读取出来,即可算出波特率。
代码
- 如下为网上找到的一段波特率自适应的代码,我进行简单的分析。
- 这里就是让 GPIO10 作为 RX 输入,不过将该引脚设置为 UART 之前,先将该引脚设置为浮空输入,测试出对端设备的波特率,然后再将该引脚设置为 UART。
- 打开定时器,之后 CPU 轮询 GPIO10,检测 32 次该引脚的电平变化,找到最大的两次电平变化差值。然后再将该值进行 0.75% 的修正。最终返回算出来的波特率。
- 这个时候肯定会有人问,如果对端设备的波特率是 115200,但是我算出来的是115249 ,阁下如何应对呢?木有关系,首先 UART 是存在一个波特率误差容限的,而且你在设置一个非标准波特率时,芯片也会匹配到一个接近的标准波特率。因为波特率本身就是利用时钟产生的。
u32 USART1_Baud(void)
{u16 t1=0,t2,t=0; u32 b1,b2;u32 i;GPIO_Init(GPIOA, 10, GPIO_IN_FLOAT); TIM_Open(Tim3); TIM_Enable(TIM3); b1 = GPIO_Pin_Get(GPIOA,10); for(i=0;i<32;) {b2 = GPIO_Pin_Get(GPIOA,10); if(b2 != b1) {t2 = TIM3->COUNT; b1 = b2; if((t1 == 0)&&(t==0)) {t1 = t2; }else {if(t == 0) {t = t2-t1; }else {if((t2-t1)< t) {t = t2-t1;}}t1 = t2; }i++; }}TIM_Close(Tim3); return ((u32)t*403/400);
}
参考
- 博客园:UART串口波特率自适应