這次我們利用STM32F103的UART內(nèi)部的空閑中斷來實(shí)現(xiàn)對(duì)串口任意長數(shù)據(jù)的接收,通過簡(jiǎn)潔的手段解決了接收端在事前無法得知數(shù)據(jù)長度的問題。本次教程我們需要一塊STM32核心板與一個(gè)USB轉(zhuǎn)TTL工具。
一、原理介紹
STM32的異步串口接收寄存器可以存放1個(gè)字節(jié),當(dāng)我們開啟接收中斷(RXNEIE)時(shí),當(dāng)串口外設(shè)接收到一個(gè)字節(jié)的數(shù)據(jù)時(shí) 數(shù)據(jù)接收(RXNE)標(biāo)志位置1,同時(shí)觸發(fā)串口中斷,此時(shí)我們可以把接收寄存器RDR中的數(shù)據(jù)轉(zhuǎn)移至我們自定的緩存區(qū)中。
此種方式我們只能一個(gè)字節(jié)一個(gè)字節(jié)的接收數(shù)據(jù),如果我們事先不知道需要接收的數(shù)據(jù)長度或未規(guī)定幀尾內(nèi)容,我們便無法判斷數(shù)據(jù)是否已經(jīng)接收完畢。這時(shí)我們可以采用總線空閑標(biāo)志(IDLE),使能空閑中斷(IDLEIE)當(dāng)檢測(cè)到線路空閑時(shí)會(huì)觸發(fā)串口中斷,我們便知道一幀數(shù)據(jù)接收完成,可以送往上層應(yīng)用中進(jìn)行處理了。
二、代碼編寫
這里我們使用串口1,波特率初始化為115200,因?yàn)閟tm32f1的hal庫似乎實(shí)現(xiàn)不完全,沒有總線空閑相關(guān)的函數(shù),我們這里自己實(shí)現(xiàn)下。如果使用的是stm32f4及以上可以使用函數(shù):
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
1、IO及UART初始化,并使能空閑中斷:
// UART.c
int UARTInit(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* IO初始化 */
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* UART1初始化 */
__HAL_RCC_USART1_CLK_ENABLE();
UARTDev1.UART_Handle.Instance = USART1;
UARTDev1.UART_Handle.Init.BaudRate = 115200;
UARTDev1.UART_Handle.Init.Parity = UART_PARITY_NONE;
UARTDev1.UART_Handle.Init.WordLength = UART_WORDLENGTH_8B;
UARTDev1.UART_Handle.Init.StopBits = UART_STOPBITS_1;
UARTDev1.UART_Handle.Init.Mode = UART_MODE_TX_RX;
HAL_UART_Init(&UARTDev1.UART_Handle);
/* UART1中斷初始化 */
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
/* UART1啟動(dòng)接收 */
HAL_UART_Receive_IT(&UARTDev1.UART_Handle, UARTDev1.RxBuffer, UART_RX_BUFFSIZE);
/** UART1開啟空閑中斷 **/
__HAL_UART_ENABLE_IT(&UARTDev1.UART_Handle, UART_IT_IDLE);
return 0;
}
2、中斷處理函數(shù),這里接收完一幀數(shù)據(jù)后會(huì)原樣發(fā)出去:
// UART.c
void USART1_IRQHandler(void)
{
UARTDef *huart = &UARTDev1;
HAL_UART_IRQHandler(&huart->UART_Handle);
/* F1的HAL庫中未實(shí)現(xiàn)IDLE相關(guān)功能,固自行實(shí)現(xiàn) */
if(__HAL_UART_GET_FLAG(&huart->UART_Handle, UART_FLAG_IDLE))
{ /* 接收到完整一幀數(shù)據(jù) */
UARTSendData(huart, UARTDev1.RxBuffer, UART_RX_BUFFSIZE - UARTDev1.UART_Handle.RxXferCount);
/* 重新啟動(dòng)接收 */
HAL_UART_AbortReceive_IT(&UARTDev1.UART_Handle);
HAL_UART_Receive_IT(&UARTDev1.UART_Handle, UARTDev1.RxBuffer, UART_RX_BUFFSIZE);
/* 清空閑中斷 */
__HAL_UART_CLEAR_IDLEFLAG(&huart->UART_Handle);
}
}
3、主函數(shù)里別忘了添加初始化函數(shù),因?yàn)樗刑幚矶荚谥袛嘀型瓿闪?,這里主循環(huán)里就放了個(gè)led閃爍的代碼:
int main()
{
HAL_Init();
SystemClockInit();
GPIOInit();
UARTInit();
while(1)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);
HAL_Delay(500);
}
}
三、效果演示
我們當(dāng)前實(shí)現(xiàn)了從串口1接收了一幀數(shù)據(jù)后原樣返回的功能,我們拿出USB轉(zhuǎn)TTL模塊,把RXD、TXD分別與板子的PA9、PA10連接,打開串口調(diào)試助手,設(shè)置好對(duì)應(yīng)波特率,發(fā)送一條信息可以看到我們收到了相同的字符。
完整代碼可以從文章最后方下載,不同文章的代碼在不同branch。下次我們討論下SPI的使用。文章來源:http://www.zghlxwxcb.cn/news/detail-646735.html
https://github.com/ss302810694/STM32F103RCT6-Example文章來源地址http://www.zghlxwxcb.cn/news/detail-646735.html
到了這里,關(guān)于STM32實(shí)戰(zhàn)(三):利用空閑中斷從串口接收任意長數(shù)據(jù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!