STM32使用DMA加串口空閑中斷接收數(shù)據(jù)
這個時候,就要用到STM32在串口中提供的另一個好用的東西了,就是串口空閑中斷。在STM32的串口控制器中,設置了有串口空閑中斷,即如果串口空閑,又開啟了串口空閑中斷的話,就觸發(fā)串口空閑中斷,然后程序就會跳到串口中斷去執(zhí)行。有了這個,是不是可以判斷什么時候串口數(shù)據(jù)接收完畢了呢?因為串口數(shù)據(jù)接收完畢后,串口總線肯定是會空閑的嘛,那這個中斷肯定是會觸發(fā)的了。
本文引用地址:http://www.ex-cimer.com/article/201611/318282.htm還有一個問題,這串口空閑中斷是只要串口空閑就會產生嗎?其實不是的,串口空閑中斷要觸發(fā)的話,是要RXNE位被置位后,串口總線空閑才會觸發(fā)的。所以我們不用擔心,串口數(shù)據(jù)發(fā)送完畢后,會不會觸發(fā)串口空閑中斷了。
下面用代碼來說明。
1、配置串口。包括設置串口的引腳配置,串口的配置,串口中斷的配置,串口的接收DMA的配置
void USART_init(void){ GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; //開啟時鐘 RCC_APB2PeriphClockCmd(USART_RCC,ENABLE); //配置TX端口 GPIO_InitStructure.GPIO_Pin = GPIO_USART_TX; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIO_USART_TYPE,&GPIO_InitStructure); //配置RX端口 GPIO_InitStructure.GPIO_Pin = GPIO_USART_RX; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIO_USART_TYPE,&GPIO_InitStructure); //配置串口模式 USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1,&USART_InitStructure); //中斷配置 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* 若總線空閑,產生中斷 */ USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); /*開啟串口DMA接收*/ USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); USART_Cmd(USART1,ENABLE);}
代碼比較簡單,一看就明白了,這就是使用庫函數(shù)開發(fā)的好處,代碼易懂。這里,關鍵的是要開啟總線空閑中斷,并且開啟串口DMA接收。注意,不要開啟串口接收中斷,不然接收數(shù)據(jù)就會一直產生中斷了。
2、DMA配置
DMA配置,要先查看串口接收是使用的哪個DMA的哪個通道,對于USART1_RX使用的是DMA1的5通道。
然后就是代碼配置DMA了。
void DMA_init(void){ DMA_InitTypeDef DMA_Initstructure;// NVIC_InitTypeDef NVIC_Initstructure; /*開啟DMA時鐘*/ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); // /* Enable the DMA1 Interrupt */// NVIC_Initstructure.NVIC_IRQChannel = DMA1_Channel4_IRQn; //通道設置為串口1中斷// NVIC_Initstructure.NVIC_IRQChannelSubPriority = 1; //中斷響應優(yōu)先級0// NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority=1;// NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE; //打開中斷// NVIC_Init(&NVIC_Initstructure); /*DMA配置*/ DMA_Initstructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);; DMA_Initstructure.DMA_MemoryBaseAddr = (u32)receive_data; DMA_Initstructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_Initstructure.DMA_BufferSize = 128; DMA_Initstructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_Initstructure.DMA_MemoryInc =DMA_MemoryInc_Enable; DMA_Initstructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_Initstructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_Initstructure.DMA_Mode = DMA_Mode_Normal; DMA_Initstructure.DMA_Priority = DMA_Priority_High; DMA_Initstructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel5,&DMA_Initstructure); //啟動DMA DMA_Cmd(DMA1_Channel5,ENABLE); //開啟DMA發(fā)送發(fā)成中斷 //DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE); }
因為這里,不需要用到DMA中斷,所以DMA中斷就不要使能了。因此DMA中斷配置也就不需要了。這里,關鍵的是要設置DMA_DIR為DMA_DIR_PeripheralSRC,表示數(shù)據(jù)是從外設到內存。這里設定的DMA_Mode是普通模式,即數(shù)據(jù)傳輸就只能一次。
3、串口中斷程序編寫
這個就是關鍵的地方了。在這里,需要做什么了。需要對DMA設置下。當進入這個中斷的時候,串口接收的數(shù)據(jù),已經在內存的數(shù)組中了。通過讀取DMA的計數(shù)值,就可以知道接收到了多少個數(shù)據(jù)。然后再把DMA給diable掉,重新設置接收數(shù)據(jù)長度,在開啟DMA,接收下一次串口數(shù)據(jù)。為什么要這么做了,因為在STM32手冊中有如下說明:
另外還有一點,串口空閑中斷觸發(fā)后,硬件會自動將串口空閑中斷標志位給置1,我們是需要將給標志位給置0的,不然又要進中斷了,這個在手冊中也有說明。
代碼就如下了:
void USART1_IRQHandler(void){ unsigned char num=0; if(USART_GetITStatus(USART1,USART_IT_IDLE) == SET) { num = USART1->SR; num = USART1->DR; //清USART_IT_IDLE標志 DMA_Cmd(DMA1_Channel5,DISABLE); //關閉DMA num = 128 - DMA_GetCurrDataCounter(DMA1_Channel5); //得到真正接收數(shù)據(jù)個數(shù) receive_data[num] = 看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();