串口IDLE空闲中断+DMA实现接收不定长数据基于stm32cubemx
引言:對(duì)于串口接收一些不定長(zhǎng)的數(shù)據(jù),必須面對(duì)一個(gè)問題:怎么判斷一幀數(shù)據(jù)接收是否完成?通常使用RXNE非空中斷配合簡(jiǎn)單的數(shù)據(jù)協(xié)議,在數(shù)據(jù)中加入幀頭、幀尾,在程序中判斷是否接收到幀尾來(lái)確定數(shù)據(jù)接收完畢,因此對(duì)每個(gè)字節(jié)都要觸發(fā)中斷進(jìn)行判斷,比較消耗系統(tǒng)資源,尤其是在一些實(shí)時(shí)性要求較高的場(chǎng)合,而串口空閑中斷可以大大簡(jiǎn)化數(shù)據(jù)接收過(guò)程的判斷。本文章介紹基于stm32cubemx使用DMA+IDLE串口空閑中斷實(shí)現(xiàn)接收不定長(zhǎng)數(shù)據(jù)。
STM32的IDLE空閑中斷產(chǎn)生機(jī)制
IDLE空閑中斷是在監(jiān)測(cè)到數(shù)據(jù)接收后(即串口的RXNE位被置位)開始檢測(cè),當(dāng)總線上在一個(gè)字節(jié)對(duì)應(yīng)的周期內(nèi)未再有新的數(shù)據(jù)接收時(shí),控制觸發(fā)空閑中斷的IDLE位被硬件置1, 便會(huì)激發(fā)一個(gè)空閑中斷,在中斷處理函數(shù)中,我們可以解析接收到的不定長(zhǎng)數(shù)據(jù)。
?使用工具
軟件:stm32cubemx ,keil uVision5,串口收發(fā)軟件(vofa+),
硬件:stm32f103rct6,ST-link下載器,數(shù)據(jù)線.
STM32CUBEMX初始化配置
打開stm32cubemx,點(diǎn)擊紅色方框處,開始新建工程
查找芯片型號(hào),選擇對(duì)應(yīng)芯片型號(hào)處雙擊
對(duì)sys進(jìn)行如下配置,便于進(jìn)行st-link下載
設(shè)置rcc,選擇高速時(shí)鐘(HSE)為外部晶振
配置時(shí)鐘樹,本文使用的是f103系列,HCLK最大為72MHz
配置串口:
1.設(shè)置MODE為異步通信(Asynchronous)
2.使用默認(rèn)配置(波特率為115200 Bits/s,傳輸數(shù)據(jù)長(zhǎng)度為8 Bit,奇偶檢驗(yàn)無(wú),停止位為1 Bit, 接收和發(fā)送都使能)
3.使能串口中斷
?
設(shè)置DMA:
工程命名,選擇保存位置,選擇使用的編譯器及版本
?
如下配置,點(diǎn)擊GENERATE CODE生成代碼
代碼編寫
注釋部分為使用雙緩沖區(qū)接收數(shù)據(jù),可有效防止接收中斷間隔時(shí)間非常短(即發(fā)送數(shù)據(jù)幀的速率很快),MCU來(lái)不及處理此次接收到的數(shù)據(jù),又產(chǎn)生中斷,導(dǎo)致數(shù)據(jù)會(huì)被覆蓋的情況
main.h中添加
#define BUFFER_SIZE 100 void USAR_UART_IDLECallback(UART_HandleTypeDef *huart,uint8_t rxlen );main.c
/* USER CODE BEGIN PV */ uint8_t rxbuffer1[BUFFER_SIZE]={0}; //接收數(shù)據(jù)緩存數(shù)組1 //uint8_t rxbuffer2[BUFFER_SIZE]={0}; //接收數(shù)據(jù)緩存數(shù)組2 //uint8_t flag=0;雙緩沖區(qū)切換標(biāo)志 /* USER CODE END PV */?main函數(shù)中注意確保DMA初始化函數(shù)放在串口初始化之前,
并在串口初始化之后使能IDLE中斷、開啟串口DMA接收
/* Initialize all configured peripherals */MX_GPIO_Init();MX_DMA_Init();//放在串口初始化之前MX_USART1_UART_Init();/* USER CODE BEGIN 2 */__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能IDLE中斷HAL_UART_Receive_DMA(&huart1,rxbuffer1,BUFFER_SIZE);//開啟串口DMA接收/* USER CODE END 2 */在/* USER CODE BEGIN 4 */下添加用戶自定義IDLE空閑中斷回調(diào)函數(shù)(注釋部分為雙緩沖接收)
void USAR_UART_IDLECallback(UART_HandleTypeDef *huart,uint8_t rxlen ){if(huart == &huart1) //判斷是否為串口1產(chǎn)生中斷{/* switch(flag){case 0: flag=1;memset(rxbuffer2,0,BUFFER_SIZE);//清空接收緩存,調(diào)用需包含string.h,本例程刪去也基本無(wú)影響HAL_UART_Receive_DMA(&huart1,rxbuffer2,BUFFER_SIZE);//重新打開DMA接收HAL_UART_Transmit_DMA(&huart1, rxbuffer1,rxlen);//將接收到的不定長(zhǎng)數(shù)據(jù)發(fā)送到上位機(jī) rxlen = 0;//清除數(shù)據(jù)長(zhǎng)度計(jì)數(shù)break;case 1:flag=0;memset(rxbuffer1,0,BUFFER_SIZE);//清空接收緩存,調(diào)用需包含string.h,本例程刪去也基本無(wú)影響HAL_UART_Receive_DMA(&huart1,rxbuffer1,BUFFER_SIZE);//重新打開DMA接收HAL_UART_Transmit_DMA(&huart1, rxbuffer2,rxlen);//將接收到的不定長(zhǎng)數(shù)據(jù)發(fā)送到上位機(jī) rxlen = 0;//清除數(shù)據(jù)長(zhǎng)度計(jì)數(shù)break;}*/HAL_UART_Transmit_DMA(&huart1, rxbuffer1,rxlen);//將接收到的不定長(zhǎng)數(shù)據(jù)發(fā)送到上位機(jī)rxlen = 0;//清除數(shù)據(jù)長(zhǎng)度計(jì)數(shù)HAL_UART_Receive_DMA(&huart1,rxbuffer1,BUFFER_SIZE);//重新打開DMA接收}}由于hal庫(kù)中沒有定義IDLE空閑中斷的中斷處理函數(shù),需要用戶自行定義
打開stm32f1xx_it.c,找到void USART1_IRQHandler(void)函數(shù),并添加如下代碼:
void USART1_IRQHandler(void) {/* USER CODE BEGIN USART1_IRQn 0 *//* USER CODE END USART1_IRQn 0 */HAL_UART_IRQHandler(&huart1);/* USER CODE BEGIN USART1_IRQn 1 */uint8_t rxlen ; //接收一幀數(shù)據(jù)的長(zhǎng)度if(RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)) //判斷idle標(biāo)志被置位{ __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除標(biāo)志位HAL_UART_DMAStop(&huart1); // 停止DMA傳輸rxlen = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); //總計(jì)數(shù)減去未傳輸?shù)臄?shù)據(jù)個(gè)數(shù),得到已經(jīng)接收的數(shù)據(jù)個(gè)數(shù)USAR_UART_IDLECallback(&huart1,rxlen); // 調(diào)用用戶定義空閑中斷回調(diào)函數(shù)}/* USER CODE END USART1_IRQn 1 */ }下載程序測(cè)試
藍(lán)色為上位機(jī)發(fā)送數(shù)據(jù),綠色為上位機(jī)接收數(shù)據(jù)
測(cè)試正常
總結(jié)
以上是生活随笔為你收集整理的串口IDLE空闲中断+DMA实现接收不定长数据基于stm32cubemx的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql多实例(三种方法)
- 下一篇: 邮件服务 交换空间(虚拟内存)