在本次項目中,限於空間要求我們選用了STM32F030F4作為控制芯片。這款MCU不但封裝緊湊,而且自帶的Flash空間也非常有限,所以我們選擇了LL庫實現。本篇將說明基於LL實現USART通訊。
1、概述
我們想要實現基於RS485的Modbus通訊實際就是基於USART的通訊。USART使用可編程波特率發生器提供非常廣泛的波特率范圍。根據不同配置可以實現我們不同的串行通訊應用需求。其結構圖如下:
我們在USART基礎上實現一個Modbus的從站應用,所以我們對於接收采用中斷接收,而對於發送則根據接收到的信息做出反饋。所以我們要根據接收狀態和發送狀態來確定我們的操作。
2、USART配置
在實現之前,我們來了解一下滿足前述的需求,我們應該做哪些配置。主要有2個寄存器需要注意:控制寄存器1(USART_CR1)和波特率寄存器(USART_BRR)。
首先我們還是來看一看控制寄存器1(USART_CR1)。其中RXNEIE(RXNE中斷使能)、TE(發送使能)、RE(接收使能)、UE(USART使能)等位是需要我們注意的。該寄存器的結構如下:
在控制寄存器1(USART_CR1)中,RXNEIE(RXNE中斷使能)被置位后,只要USART_ISRORE=1或者RXNE=1就會產生該中斷。接下來我們看一看波特率寄存器(USART_BRR),其結構如下:
對於波特率寄存器(USART_BRR),顧名思義就是設置波特率。但波特率的值不是隨意設置,有一套計算方法,可以查看STM的手冊。
3、軟件實現
接下來我們在軟件上實現我們的應用。我們先看USART配置,我們將其配置為我們需要的參數,並將其配置為中斷接收模式。具體代碼如下:
/*配置上位通訊串口*/
static void Comm_UART_Configuration(void)
{
LL_USART_InitTypeDef USART_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
/* 使能相關外設時鍾 */
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_USART1);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
/* USART1 GPIO 配置:PA2 ------> USART1_TX
PA3 ------> USART1_RX */
GPIO_InitStruct.Pin = LL_GPIO_PIN_2;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_3;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART1中斷初始化 */
NVIC_SetPriority(USART1_IRQn, 1);
NVIC_EnableIRQ(USART1_IRQn);
/* USART1端口配置 */
USART_InitStruct.BaudRate = 115200;
USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
USART_InitStruct.Parity = LL_USART_PARITY_NONE;
USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
LL_USART_Init(USART1, &USART_InitStruct);
LL_USART_DisableIT_CTS(USART1);
LL_USART_ConfigAsyncMode(USART1);
LL_USART_Enable(USART1);
LL_USART_EnableIT_RXNE(USART1);
}
大部分配置都可通過初始化函數來實現,有一些需同過專門的LL庫函數實現。配置完成后寄存器的狀態如下圖所示。
我們配置的波特率是115200,其在寄存器中的配置為1A1,關於波特率的配置問題可以查看相關資料。另外我們還需要編寫一個接收中斷的服務函數。
/*數據接收中斷處理函數,添加到USART1中斷響應函數中*/
void USART1_ReceiveDataHandle(void)
{
if(rxLength>=RECEIVEDATALENGTH)
{
rxLength=0;
}
/*接收寄存器為空,等待字節被對應的串口完全接收*/
if(LL_USART_IsActiveFlag_RXNE(USART1))
{
uint8_t rData;
/*獲取接收到的字節*/
rData=LL_USART_ReceiveData8(USART1);
rxBuffer[rxLength++] = rData;
}
if(LL_USART_IsActiveFlag_ORE(USART1))
{
LL_USART_ClearFlag_ORE(USART1);
}
}
需要注意的是需要添加ORE溢出標志的檢測,確保每次的接收中斷都是有效的。
4、總結
最后我們來測試一下我們的代碼。將相關項目下載到目標板並采用兩種監測方式查看結果。首先接到PC機的串口,在上位中使用Modscan來查看,其結果如下:
然后通過J-Link在線調試監控數據通訊,其結果如下:
上圖中,上部是我們的物理量數據,而下面是接收到的上位下發的讀取保持寄存器的Modbus報文。結合前一張圖,很明顯收發都是正確的。
歡迎關注: