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相关推荐

  1. STM32 串口DMA接收 Openmv / K210 整数、小数字符串数据 (基于HAL库)

    目录 前言 一.工程配置 二.串口DMA部分代码 1.源文件UART_DMA.c 2.头文件UART_DMA.h 3.stm32f1xx_it.c的修改 4.串口收发DMA测试 三.字符串数字提取代码 ...

  2. STM32 串口DMA收发(二)

    STM32 串口DMA收发数据 一.STM32 DMA简介与功能说明 1.STM32F4 DMA简介 DMA(Direct memory access),即直接存储器访问.用于在外设与存储器之间以及存 ...

  3. STM32串口DMA接收双缓冲

    STM32高端MCU(F4.F7等)才支持DMA双缓冲,低端MCU(F1)不支持DMA双缓冲,不过有替代方案可实现类型效果. 一.MCU支持DMA双缓冲的情形 不再赘述,参见博客 STM32 串口DM ...

  4. dma接收双缓存 stm32_容易被大多数人忽视的STM32串口DMA问题

    讨论三个问题: 1.什么叫串口DMA 请求: 2.串口简要复习: 3.串口DMA发送流程. 第一 什么叫串口DMA 请求(战舰STM32开发板) 说这个问题之前先简单回顾DMA的基本特性.先导出原子哥 ...

  5. FPGA 串口中断_一个严谨的STM32串口DMA发送amp;接收(1.5Mbps波特率)机制

    昨天分享的<嵌入式大杂烩读者福利:第一期>大家有去抽奖吗,没抽的可参与抽奖,碰碰运气.我最喜欢抽奖了,还记得前几个月疫情严重时期连抽中了3包口罩,真刺激,哈哈.之后多多安排抽奖,敬请期待. ...

  6. 一个严谨的STM32串口DMA发送接收(1.5Mbps波特率)机制

    文章目录 1 前言 2 串口有必要使用DMA吗 3 实现方式 4 STM32串口使用DMA 5 串口DMA接收 5.1 基本流程 5.2 相关配置 5.3 接收处理 5.3 .1 接收数据大小 5.3 ...

  7. 巧用STM32串口DMA的normal和circular模式,达到并行执行效果

    芯片型号:stm32f103rct6:SPI接口ADC; 代码功能描述:有xyz3路数据,每路1个双通道adc采集,从x路依次数据并用串口发送出去,14字节,2250000bps: 方案1:按照顺序执 ...

  8. 【32单片机学习】(6)STM32串口+DMA收发不定长数据

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 1.DMA介绍 2.串口接收数据 3.实验现象 1.实验电路图 2.串口收发不定长数据视频演示 3.OLED 显示接收数据 ...

  9. # 项目一:‍‍‍STM32+串口DMA+RS485+MODBUS+传感器实现SO2的测试

    ✨简介: 通过STM32控制传感器实现气体浓度的测量:RS485+MODBUS+串口DMA+定时器. 其中,USART2负责控制数据的发送和接受,USART3负责将询问帧.应答帧以及处理后数据打印出来 ...

最新文章

  1. php怎么接受,如何使php://input接收到另一个php的数据
  2. 独家 | 手把手教你怎样用Python生成漂亮且精辟的图像(附教程代码)
  3. asp.net MVC 路由机制 Route
  4. 转:STL:string 大小(Size)和容量(Capacity)
  5. SpringMVC_4.请求数据
  6. php signature解密,openssl RSA非对称加密、解密、签名、验签
  7. uva 12222——Mountain Road
  8. 上市公司行情查询站点
  9. redux入门指南(一)
  10. isight2019安装教程_DS SIMULIA Suite 2019 (Abaqus/Isight/Fe-safe/Tosca) Win/Linux x64
  11. oozie中管理datax脚本方法实践
  12. QT 字符乱码的原因
  13. 区块链简介与PMD投资方式
  14. 对立与统一(期货反向跟单-交易员培训法则)
  15. 服务器假死 http 状态码,关于golang:Golang之HTTP服务『假死』问题排查
  16. 如何确定scrum的story之一:识别利益相关者和目标
  17. 简单排序算法时间空间复杂度分析及应用(4)-二分插入排序
  18. 加法要遍历两遍所有元素,那就用减法,只遍历一遍即可(思想)
  19. 利用背景流量数据(contexual flow data) 识别TLS加密恶意流量
  20. android studio真机测试不生成apk,Android应用开发Android Studio编译出来的APK无法安装如何解决?...

热门文章

  1. Subversion基本操作
  2. mysql复制模式第四部分-----环形复制
  3. 【BZOJ4004】装备购买(线性基)
  4. Linux 2.6 内核定时器
  5. Matlab GUI 设计(4):不同控件之间的数据传递
  6. B树、B+树其实很简单,看不懂你找我
  7. 目标文件(.o)结构的简单了解
  8. 你不知道的JavaScript运算符
  9. WebApi_基于Token的身份验证——JWT
  10. vue2.0中引入wangEditor2 步骤与坑