版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/LinLingPeng_/article/details/8944993
在單片機中,UART是常用的通信方式。最近在做Profibus DP的產品,由於Profibus DP有波特率自適應的特性,故研究了一下UART的波特率自適應方法。現在介紹一種自適應波特率的設置方法。
上述函數的返回值,直接填入USART1的波特率寄存即可(如果APB2的時鐘與定時器時鐘相同的話)。
上述計算檢測出來的波特率值,與實際波特有一點點差異,但不影響正常通信。
參與測試的波特率有1200、2400、4800、9600、14400、19200、28800、38400、56000、57600、115200、128000、250000、500000bps.
還有一點要說明的是:我沒有使用ST的庫,上面的函數,是我自己用的。但註釋已經很好的說明了如何進行自適應波特率的設置,不依賴於發送方的發送數據。當然,數據幀的前面部分,肯定有多個字節是收不到的(被檢測用掉了)。
條件
空閒的內部定時器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的庫,上面的函數,是我自己用的。但註釋已經很好的說明了如何進行自適應波特率的設置,不依賴於發送方的發送數據。當然,數據幀的前面部分,肯定有多個字節是收不到的(被檢測用掉了)。