最近使用开发的过程中出现了一个小问题,顺便记录一下原因和方法--电平波特率
在单片机中,UART是经常使用的通信方法。最近在做Profibus DP的产品,由于Profibus DP有波特率自适应的特性,故研讨了一下UART的波特率自适应方法。当初介绍一种自适应波特率的设置方法。
条件
闲暇的外部定时器1个
方法
通过定时器,连续检测UART输入引脚RXD上的电平变更,以达到波特率自适应。
STM32来举例
假设要自适应的UART为STM32的USART1,其RXD引脚为GPIOA.10。同时也假定定时器3闲暇。
代码
u32 USART1_Baud(void) { u16 t1=0,t2,t=0; // 定时器寄存器为16位 u32 b1,b2; u32 i; GPIO_Init(GPIOA, 10, GPIO_IN_FLOAT); // GPIOA.10浮空输入 TIM_Open(Tim3); // 开TIM3的时钟 TIM_Enable(TIM3); // 开启TIM3 b1 = GPIO_Pin_Get(GPIOA,10); // 读GPIOA.10的电平 for(i=0;i<32;) // 连续检测GPIO.10引脚32次电平变更 { b2 = GPIO_Pin_Get(GPIOA,10); // 读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++; // 电平变更数+1 } } TIM_Close(Tim3); // 关闭TIM3的时钟 return ((u32)t*403/400); // 修正波特率值(加上电平变更的斜率,大概为0.75%,经验值) }
上述函数的返回值,直接填入USART1的波特率寄存即可(如果APB2的时钟与定时器时钟雷同的话)。
上述盘算检测出来的波特率值,与实际波特有一点点差异,但不影响正常通信。
介入测试的波特率有1200、2400、4800、9600、14400、19200、28800、38400、56000、57600、115200、128000、250000、500000bps.
还有一点要说明的是:我没有使用ST的库,下面的函数,是我自己用的。但注释已经很好的说明了如何进行自适应波特率的设置,不依赖于发送方的发送数据。当然,数据帧的后面部份,肯定有多个字节是收不到的(被检测用掉了)。
文章结束给大家分享下程序员的一些笑话语录: 看到有人回帖“不顶不是中国人”,他的本意是想让帖子沉了。