生活随笔
收集整理的這篇文章主要介紹了
STM32串口+DMA使用1
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
STM32串口+DMA使用
? ? ? ? STM32有5個(gè)串口資源(USART1,USART2,USART3及UART4,UART5)。其中3個(gè)USART(通用同步/異步收/發(fā)器universalsynchronous asynchronous receiver and transmitter);2個(gè)UART(通用異步收/發(fā)器universalasynchronous receiver and transmitter);至于USART與UART的區(qū)別,如果只是拿來做串口用,沒什么區(qū)別,在車載項(xiàng)目里,我們拿來做串口用,USART與UART在編程上并沒有區(qū)別。
? ? ? ? 其中USART1,USART2,USART3,UART4支持DMA方式,UART5不支持DMA。(詳見數(shù)據(jù)手冊stm32f105&107_datesheet_English的P18/2.3.17)。
? ? ? ? DMA(Derect MemoryAcess直接存儲(chǔ)器存取),STM32有2個(gè)DMA,DMA1有7個(gè)通道,DMA2有5和通道,每個(gè)通道對應(yīng)不同的外設(shè)(詳見數(shù)據(jù)手冊P272/13.3.7)。
1.時(shí)鐘RCC配置:串口時(shí)鐘 + DMA時(shí)鐘 + IO時(shí)鐘static void RCC_Configuration(void){RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE); //串口時(shí)鐘 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2,ENABLE); //DMA2時(shí)鐘 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC| RCC_APB2Periph_AFIO, ENABLE);//IO時(shí)鐘} 2.GPIO配置:UART4的TX為PC10腳,發(fā)送端配置為復(fù)用推挽輸出模式(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復(fù)用推挽輸出模式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配置:配置兩個(gè)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.串口配置:即填充串口配置結(jié)構(gòu)體static void UART4_Configuration(void){USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate =115200;USART_InitStructure.USART_WordLength =USART_WordLength_8b;//數(shù)據(jù)位8位USART_InitStructure.USART_StopBits =USART_StopBits_1;//停止位1位USART_InitStructure.USART_Parity = USART_Parity_No;//無奇偶校驗(yàn)位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外設(shè)}5.DMA配置:DMA可以把數(shù)據(jù)從外設(shè)轉(zhuǎn)移到內(nèi)存(如串口接收的時(shí)候),也可以從內(nèi)存轉(zhuǎn)移到外設(shè)(如串口發(fā)送的時(shí)候);不同方向的數(shù)據(jù)轉(zhuǎn)移要各做相應(yīng)的配置串口接收: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);//外設(shè)基地址,串口4數(shù)據(jù)寄存器DMA_InitStructure.DMA_MemoryBaseAddr =(u32)recvBuf;//內(nèi)存基地址,數(shù)組UART4_DMA_HeadBufDMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralSRC;//SRC外設(shè)到內(nèi)存DMA_InitStructure.DMA_BufferSize =bufLen;//DMA數(shù)據(jù)傳輸長度DMA_InitStructure.DMA_PeripheralInc =DMA_PeripheralInc_Disable;//外設(shè)地址不自增DMA_InitStructure.DMA_MemoryInc =DMA_MemoryInc_Enable;//內(nèi)存地址自增DMA_InitStructure.DMA_PeripheralDataSize =DMA_PeripheralDataSize_Byte;//外設(shè)數(shù)據(jù)單位為1字節(jié)DMA_InitStructure.DMA_MemoryDataSize =DMA_MemoryDataSize_Byte;//內(nèi)存數(shù)據(jù)單位為1字節(jié)DMA_InitStructure.DMA_Mode =DMA_Mode_Normal;//DMA傳輸數(shù)據(jù)模式,正常模式,傳一輪DMA_InitStructure.DMA_Priority =DMA_Priority_High;//DMA通道優(yōu)先級(jí)DMA_InitStructure.DMA_M2M =DMA_M2M_Disable;//禁止DMA內(nèi)存到內(nèi)存?zhèn)鬏擠MA_DeInit(DMA2_Channel3);//UART4的RX為DMA2通道3DMA_Init(DMA2_Channel3,&DMA_InitStructure);DMA_ITConfig(DMA2_Channel3, DMA_IT_TC,ENABLE);//配置DMA2發(fā)送完成后產(chǎn)生中斷USART_DMACmd(UART4, USART_DMAReq_Rx,ENABLE);//配置串口向DMA發(fā)出Tx請求,請求傳輸數(shù)據(jù)DMA_Cmd(DMA2_Channel3, ENABLE);//正式開啟DMA}串口發(fā)送: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);//外設(shè)基地址,串口4數(shù)據(jù)寄存器DMA_InitStructure.DMA_MemoryBaseAddr =(uint32_t)UART4_DMA_SendBuf; DMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralDST;//DST內(nèi)存到外設(shè) 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發(fā)送完成后產(chǎn)生中斷USART_DMACmd(UART4,USART_DMAReq_Tx,ENABLE);//配置串口向DMA發(fā)出Tx請求,請求傳輸數(shù)據(jù)DMA_Cmd(DMA2_Channel5, ENABLE);//正式開啟DMAgDMA2Channel5Running = true;}6.DMA中斷函數(shù):串口接收或發(fā)送的時(shí)候,DMA數(shù)據(jù)傳輸完成后會(huì)產(chǎn)生中斷,在相應(yīng)中斷函數(shù)編寫代碼(注意中斷函數(shù)名一定要與啟動(dòng)文件中斷向量表一致)DMA串口接收完成中斷:void DMA2_Channel3_IRQHandler(void)//接收完成中斷{ OSIntEnter();//ucos進(jìn)入中斷服務(wù)函數(shù)if(DMA_GetITStatus(DMA2_IT_TC3)){//獲取剩余長度,一般都為0,調(diào)試用DMA_ClearITPendingBit(DMA2_IT_GL3); //清除全部中斷標(biāo)志 DMA_Cmd(DMA2_Channel3, DISABLE);if(0 == DMAReciveState){if(HOST_MSG_START_CODE_FIRST_BYTE== UART4_DMA_HeadBuf[0])//比較讀取的第1個(gè)字節(jié)FF{DMAReciveState = 1;UART4_Start_DMA_Recv((void*)(UART4_DMA_HeadBuf + 1), 3);//再讀取后3個(gè)字節(jié)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)//比較整個(gè)起始碼FFFFFFFF{DMAReciveState = 2;UART4_Start_DMA_Recv((void*)(UART4_DMA_HeadBuf + 4), 8);//再讀取后8個(gè)字節(jié)(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();//申請一個(gè)PhoneRecvBuf接收內(nèi)存塊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));//把數(shù)組數(shù)據(jù)(startcode+cmdtype+bodylen)拷貝到內(nèi)存塊pMCUMsgHeader = (HOST_MSG_HEADER_T*)pMsgBuffer;//指針類型轉(zhuǎn)換UART4_Start_DMA_Recv((void*)(pMsgBuffer +sizeof(HOST_MSG_HEADER_T)), pMCUMsgHeader->bodyLen + CRC_LEN);//再讀取后面數(shù)據(jù)(data+crc)到內(nèi)存塊}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個(gè)字節(jié)(起始碼第1個(gè)字節(jié)FF),開始下一輪接收數(shù)據(jù)if (pMsgBuffer != NULL){PutMsg2PhoneRecvQueue(pMsgBuffer);//把PhoneRecvBuf接收內(nèi)存塊指針發(fā)送到PhoneRecvQ接收消息隊(duì)列pMsgBuffer = NULL;}}}OSIntExit();//ucos退出中斷服務(wù)函數(shù)}
DMA串口發(fā)送完成中斷:void DMA2_Channel5_IRQHandler(void)//發(fā)送完成中斷
{OSIntEnter();if(DMA_GetITStatus(DMA2_IT_TC5)==SET){DMA_ClearFlag(DMA2_IT_GL5);DMA_Cmd(DMA2_Channel5,DISABLE);gDMA2Channel5Running = false;}OSIntExit();}
?
----------------------------------------------------------------------------------------------------------------------------------
附:
DMA常用庫函數(shù):
?
文章標(biāo)簽:?STM32UARTDMA
總結(jié)
以上是生活随笔為你收集整理的STM32串口+DMA使用1的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。