生活随笔
收集整理的這篇文章主要介紹了
STM32串口+DMA使用1
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
STM32串口+DMA使用
? ? ? ? STM32有5個串口資源(USART1,USART2,USART3及UART4,UART5)。其中3個USART(通用同步/異步收/發器universalsynchronous asynchronous receiver and transmitter);2個UART(通用異步收/發器universalasynchronous receiver and transmitter);至于USART與UART的區別,如果只是拿來做串口用,沒什么區別,在車載項目里,我們拿來做串口用,USART與UART在編程上并沒有區別。
? ? ? ? 其中USART1,USART2,USART3,UART4支持DMA方式,UART5不支持DMA。(詳見數據手冊stm32f105&107_datesheet_English的P18/2.3.17)。
? ? ? ? DMA(Derect MemoryAcess直接存儲器存取),STM32有2個DMA,DMA1有7個通道,DMA2有5和通道,每個通道對應不同的外設(詳見數據手冊P272/13.3.7)。
1.時鐘RCC配置:串口時鐘 + DMA時鐘 + IO時鐘static void RCC_Configuration(void){RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE); //串口時鐘 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2,ENABLE); //DMA2時鐘 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC| RCC_APB2Periph_AFIO, ENABLE);//IO時鐘} 2.GPIO配置:UART4的TX為PC10腳,發送端配置為復用推挽輸出模式(GPIO_Mode_AF_PP)UART4的RX為PC11腳,接收端配置為浮空輸入模式(GPIO_Mode_IN_FLOATING)
static void GPIO_Configuration(void){GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin =GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP; //TX復用推挽輸出模式GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;GPIO_Init(GPIOC,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin =GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //RX浮空輸入模式GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;GPIO_Init(GPIOC,&GPIO_InitStructure);}3.中斷NVIC配置:配置兩個DMA通道中斷:UART4的RX的DMA通道為DMA2的通道3;UART4的TX的DMA通道為DMA2的通道5;static void NVIC_Configuration(void){NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel =UART4_IRQn;//串口中斷NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0;NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel5_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE; NVIC_Init(&NVIC_InitStructure);}4.串口配置:即填充串口配置結構體static void UART4_Configuration(void){USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate =115200;USART_InitStructure.USART_WordLength =USART_WordLength_8b;//數據位8位USART_InitStructure.USART_StopBits =USART_StopBits_1;//停止位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;//TX、RX都開啟USART_Init(UART4,&USART_InitStructure);USART_Cmd(UART4, ENABLE); //使能UART4外設}5.DMA配置:DMA可以把數據從外設轉移到內存(如串口接收的時候),也可以從內存轉移到外設(如串口發送的時候);不同方向的數據轉移要各做相應的配置串口接收:void UART4_Start_DMA_Recv(void * recvBuf, uint32_t bufLen){DMA_InitTypeDef DMA_InitStructure;UART4_Configuration();/* DMA1 Channel5 (triggered by USART1 Rxevent) Config */DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)&(UART4->DR);//外設基地址,串口4數據寄存器DMA_InitStructure.DMA_MemoryBaseAddr =(u32)recvBuf;//內存基地址,數組UART4_DMA_HeadBufDMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralSRC;//SRC外設到內存DMA_InitStructure.DMA_BufferSize =bufLen;//DMA數據傳輸長度DMA_InitStructure.DMA_PeripheralInc =DMA_PeripheralInc_Disable;//外設地址不自增DMA_InitStructure.DMA_MemoryInc =DMA_MemoryInc_Enable;//內存地址自增DMA_InitStructure.DMA_PeripheralDataSize =DMA_PeripheralDataSize_Byte;//外設數據單位為1字節DMA_InitStructure.DMA_MemoryDataSize =DMA_MemoryDataSize_Byte;//內存數據單位為1字節DMA_InitStructure.DMA_Mode =DMA_Mode_Normal;//DMA傳輸數據模式,正常模式,傳一輪DMA_InitStructure.DMA_Priority =DMA_Priority_High;//DMA通道優先級DMA_InitStructure.DMA_M2M =DMA_M2M_Disable;//禁止DMA內存到內存傳輸DMA_DeInit(DMA2_Channel3);//UART4的RX為DMA2通道3DMA_Init(DMA2_Channel3,&DMA_InitStructure);DMA_ITConfig(DMA2_Channel3, DMA_IT_TC,ENABLE);//配置DMA2發送完成后產生中斷USART_DMACmd(UART4, USART_DMAReq_Rx,ENABLE);//配置串口向DMA發出Tx請求,請求傳輸數據DMA_Cmd(DMA2_Channel3, ENABLE);//正式開啟DMA}串口發送:void UART4_Start_DMA_Send(void * sendBuf, uint32_t bufLen){DMA_InitTypeDefDMA_InitStructure;if (bufLen == 0)return ;memcpy(UART4_DMA_SendBuf, sendBuf, bufLen);DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)(&UART4->DR);//外設基地址,串口4數據寄存器DMA_InitStructure.DMA_MemoryBaseAddr =(uint32_t)UART4_DMA_SendBuf; DMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralDST;//DST內存到外設 DMA_InitStructure.DMA_BufferSize =bufLen; 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_PeripheralDataSize_Byte; DMA_InitStructure.DMA_Mode =DMA_Mode_Normal; DMA_InitStructure.DMA_Priority =DMA_Priority_High; DMA_InitStructure.DMA_M2M =DMA_M2M_Disable;DMA_DeInit(DMA2_Channel5); //UART4的TX為DMA2通道5DMA_Init(DMA2_Channel5,&DMA_InitStructure); DMA_ITConfig(DMA2_Channel5, DMA_IT_TC,ENABLE);//配置DMA2發送完成后產生中斷USART_DMACmd(UART4,USART_DMAReq_Tx,ENABLE);//配置串口向DMA發出Tx請求,請求傳輸數據DMA_Cmd(DMA2_Channel5, ENABLE);//正式開啟DMAgDMA2Channel5Running = true;}6.DMA中斷函數:串口接收或發送的時候,DMA數據傳輸完成后會產生中斷,在相應中斷函數編寫代碼(注意中斷函數名一定要與啟動文件中斷向量表一致)DMA串口接收完成中斷:void DMA2_Channel3_IRQHandler(void)//接收完成中斷{ OSIntEnter();//ucos進入中斷服務函數if(DMA_GetITStatus(DMA2_IT_TC3)){//獲取剩余長度,一般都為0,調試用DMA_ClearITPendingBit(DMA2_IT_GL3); //清除全部中斷標志 DMA_Cmd(DMA2_Channel3, DISABLE);if(0 == DMAReciveState){if(HOST_MSG_START_CODE_FIRST_BYTE== UART4_DMA_HeadBuf[0])//比較讀取的第1個字節FF{DMAReciveState = 1;UART4_Start_DMA_Recv((void*)(UART4_DMA_HeadBuf + 1), 3);//再讀取后3個字節FFFFFF}else{UART4_Start_DMA_Recv((void*)UART4_DMA_HeadBuf, 1);}}else if(1 == DMAReciveState){if(HOST_MSG_START_CODE ==*(uint32_t *)UART4_DMA_HeadBuf)//比較整個起始碼FFFFFFFF{DMAReciveState = 2;UART4_Start_DMA_Recv((void*)(UART4_DMA_HeadBuf + 4), 8);//再讀取后8個字節(cmdtype+bodylen)}else{DMAReciveState = 0;memset(UART4_DMA_HeadBuf, 0, sizeof(UART4_DMA_HeadBuf));UART4_Start_DMA_Recv((void*)UART4_DMA_HeadBuf, 1);}}else if(2 == DMAReciveState){HOST_MSG_HEADER_T *pMCUMsgHeader;DMAReciveState = 3;pMsgBuffer = (uint8_t*)GetPhoneRecvBuf();//申請一個PhoneRecvBuf接收內存塊if(pMsgBuffer == NULL){DMAReciveState = 0;memset(UART4_DMA_HeadBuf, 0,sizeof(UART4_DMA_HeadBuf));UART4_Start_DMA_Recv((void*)UART4_DMA_HeadBuf, 1);OSIntExit(); //means get out of the inturrept!return;}memcpy(pMsgBuffer,UART4_DMA_HeadBuf, sizeof(HOST_MSG_HEADER_T));//把數組數據(startcode+cmdtype+bodylen)拷貝到內存塊pMCUMsgHeader = (HOST_MSG_HEADER_T*)pMsgBuffer;//指針類型轉換UART4_Start_DMA_Recv((void*)(pMsgBuffer +sizeof(HOST_MSG_HEADER_T)), pMCUMsgHeader->bodyLen + CRC_LEN);//再讀取后面數據(data+crc)到內存塊}else if(3 == DMAReciveState){DMAReciveState = 0;memset(UART4_DMA_HeadBuf, 0,sizeof(UART4_DMA_HeadBuf));UART4_Start_DMA_Recv((void*)UART4_DMA_HeadBuf, 1);//此處再讀1個字節(起始碼第1個字節FF),開始下一輪接收數據if (pMsgBuffer != NULL){PutMsg2PhoneRecvQueue(pMsgBuffer);//把PhoneRecvBuf接收內存塊指針發送到PhoneRecvQ接收消息隊列pMsgBuffer = NULL;}}}OSIntExit();//ucos退出中斷服務函數}
DMA串口發送完成中斷:void DMA2_Channel5_IRQHandler(void)//發送完成中斷
{OSIntEnter();if(DMA_GetITStatus(DMA2_IT_TC5)==SET){DMA_ClearFlag(DMA2_IT_GL5);DMA_Cmd(DMA2_Channel5,DISABLE);gDMA2Channel5Running = false;}OSIntExit();}
?
----------------------------------------------------------------------------------------------------------------------------------
附:
DMA常用庫函數:
?
文章標簽:?STM32UARTDMA
總結
以上是生活随笔為你收集整理的STM32串口+DMA使用1的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。