在使用單片機做項目開發的時候,串口是最常用的外設之一,比如打印調試信息,接主從串口設備等。這里主要對串口通信時中斷方式收發數據的超時時間的設置和485發送數據時控制IO口的處理做一些記錄。
1.串口中斷接收超時設置
在項目中,如果使用中斷方式數據,那么需要設置一個超時時間,超過設置的時間沒有收到數據則認為當前數據包接收完成,為一個完整的數據包並開始后續的數據處理;那么這個超時時間的設置需要根據實際的應用情況合理的設置。首先,如果只做簡單的超時或者MCU緩存足夠大,則可以選擇內核心跳或者心跳定時器來做超時,各個波特率做一個統一的超時時間,比如20毫秒;但是,如果時序相對嚴格或者緩存不夠大,那么在硬件資源允許的情況下最好單獨開一個定時器來做串口超時定時器,比如本菜鳥常用結構如下:
switch(boundrate)
{
...... //其它波特率
case RATE_9600:
//波特率設置
//超時時間設置
break;
...... //其它配置
default:
break;
}
在我使用的部分單片機中,GD32的某個系列的單片機串口自帶了超時功能,開啟並設置合適的時間,不得不說還是方便了不少。超時時間根據實際應用和實際使用的波特率來確定,比如實效高的應用則需要盡可能的短一點,減少通信延遲,2倍單字節時間即可;如果是標准ModBus協議則至少需要3.5背單字節時間;但是如果是帶有操作系統的中斷超時分包則要盡可能的長,因為時間太短可能會因為系統調度的原因導致一個數據包被拆分成好幾個。
2.中斷方式通過485發送數據
如果是查詢方式或者DMA方式不考慮,此處主要是中斷方式發送數據,發送之前首先將485芯片控制腳拉高,為發送狀態,然后開始發送數據,一般開啟的中斷方式為發送為空中斷,但是發送為空中斷只是判斷數據寄存器中是否為空,並不表示移位寄存器中的數據已經發出,所以在一個數據包的最后一個字節需要修改發送空中斷為發送完成中斷,確保最后一個字節發送完成后再拉低485控制腳,轉為接收狀態。如果使用STM32單片機的話,官方文檔有詳細說明,ST官方的中斷處理源代碼如下:
void USART1_IRQHandler(void)
{
/* If the buffer is fully transmitted */
if(TxCount == TxLength)
{
/* Set DE pin to low level (TC interrupt is occured )*/
GPIOC->BRR = GPIO_Pin_6;
/* Disable the USART1 Transmit Complete interrupt */
USART_ITConfig(USART1, USART_IT_TC, DISABLE);
USART_ClearFlag(USART1, USART_FLAG_TC);
}
else if ((TxCount == (TxLength-1)) && (TxLength /= 1))
{
/* Enable TC interrupt at the last byte to transmit */
USART1->DR = TxBuffer[TxCount++];
/* Enable USART TC interrupt */
USART_ITConfig(USART1, USART_IT_TC , ENABLE);
/* Disable USART TXE interrupt */
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
}
else if(TxCount != 0) /* if it's not the first byte */
{
/* USART1 Tx empty interrupt has occured */
if(USART1->SR & 0x80)
{
/* Continue the buffer transmission via USART */
USART1->DR = TxBuffer[TxCount++];
}
}
else /* The first byte to be transmitted */
{
/* USART1 Tx empty interrupt has occured */
if(USART1->SR & 0x80)
{
/* Set DE pin to high level */
GPIOC->BSRR = GPIO_Pin_6;
/* Transmit the first byte */
USART1->DR = TxBuffer[TxCount++];
}
if (TxLength == 1 )
{
/* Enable TC interrupt at the last byte to transmit (single byte) */
/* Enable USART TC interrupt */
USART_ITConfig(USART1, USART_IT_TC , ENABLE);
/* Disable USART TXE interrupt */
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
}
}
}
485為差分信號,屬於半雙工通信,如果發送時處理不當會出現丟數據;另外,如果通信比較密集,最好能做一下485防沖突,避免數據沖突出現錯誤。