完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
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_HeadBuf DMA_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通道3 DMA_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通道5 DMA_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);//正式开启DMA gDMA2Channel5Running = 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常用库函数: 文章标签: STM32 UART DMA |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1760 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1613 浏览 1 评论
1058 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
721 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1670 浏览 2 评论
1932浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
724浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
564浏览 3评论
591浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
549浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-20 19:02 , Processed in 0.591384 second(s), Total 46, Slave 40 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号