STM32的串口采用DMA方式接收数据测试(转)

STM32的串口采用DMA方式接收数据测试

本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.

 

参考链接:http://www.amobbs.com/forum.PHP?mod=viewthread&tid=5511863&highlight=dma%E6%8E%A5%E6%94%B6

 

环境:

主机:WINXP

开发环境:MDK4.23

MCU:STM32F103CBT6

说明:

串口可以配置成用DMA的方式接收数据,不过DMA需要定长才能产生接收中断,如何接收可变长度的数据呢?

方法有以下3种:

1.将RX脚与一路时钟外部引脚相连,当串口一帧发完,即可利用此定时器产生超时中断.这个实时性较高,可以做到1个字节实时监测.

2.不改变硬件,开启一个定时器监控DMA接收,如果超时则产生中断.这个实时性不高,因为超时时间必须要大于需要接收帧的时间,精度不好控制.

3.STM32单片机有的串口可以监测总线是否处于空闲,如果空闲则产生中断.可以用它来监测DMA接收是否完毕.这种方式实时性很高.

本文采用第3种方式.在波特率576000下大数据包冲击证明可行.

源代码:

[cpp] view plain copy

  1. //串口接收DMA缓存
  2. #define UART_RX_LEN     128
  3. extern uint8_t Uart_Rx[UART_RX_LEN];

[cpp] view plain copy

  1. //串口接收DMA缓存
  2. uint8_t Uart_Rx[UART_RX_LEN] = {0};

[cpp] view plain copy

  1. //---------------------串口功能配置---------------------
  2. //打开串口对应的外设时钟
  3. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);
  4. //串口发DMA配置
  5. //启动DMA时钟
  6. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  7. //DMA发送中断设置
  8. NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
  9. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
  10. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  11. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  12. NVIC_Init(&NVIC_InitStructure);
  13. //DMA1通道4配置
  14. DMA_DeInit(DMA1_Channel4);
  15. //外设地址
  16. DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
  17. //内存地址
  18. DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart_Send_Buffer;
  19. //dma传输方向单向
  20. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  21. //设置DMA在传输时缓冲区的长度
  22. DMA_InitStructure.DMA_BufferSize = 100;
  23. //设置DMA的外设递增模式,一个外设
  24. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  25. //设置DMA的内存递增模式
  26. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  27. //外设数据字长
  28. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  29. //内存数据字长
  30. DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
  31. //设置DMA的传输模式
  32. DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  33. //设置DMA的优先级别
  34. DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  35. //设置DMA的2个memory中的变量互相访问
  36. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  37. DMA_Init(DMA1_Channel4,&DMA_InitStructure);
  38. DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
  39. //使能通道4
  40. //DMA_Cmd(DMA1_Channel4, ENABLE);
  41. //串口收DMA配置
  42. //启动DMA时钟
  43. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  44. //DMA1通道5配置
  45. DMA_DeInit(DMA1_Channel5);
  46. //外设地址
  47. DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
  48. //内存地址
  49. DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart_Rx;
  50. //dma传输方向单向
  51. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  52. //设置DMA在传输时缓冲区的长度
  53. DMA_InitStructure.DMA_BufferSize = UART_RX_LEN;
  54. //设置DMA的外设递增模式,一个外设
  55. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  56. //设置DMA的内存递增模式
  57. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  58. //外设数据字长
  59. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  60. //内存数据字长
  61. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  62. //设置DMA的传输模式
  63. DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  64. //设置DMA的优先级别
  65. DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  66. //设置DMA的2个memory中的变量互相访问
  67. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  68. DMA_Init(DMA1_Channel5,&DMA_InitStructure);
  69. //使能通道5
  70. DMA_Cmd(DMA1_Channel5,ENABLE);
  71. //初始化参数
  72. //USART_InitStructure.USART_BaudRate = DEFAULT_BAUD;
  73. USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  74. USART_InitStructure.USART_StopBits = USART_StopBits_1;
  75. USART_InitStructure.USART_Parity = USART_Parity_No;
  76. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  77. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  78. USART_InitStructure.USART_BaudRate = DEFAULT_BAUD;
  79. //初始化串口
  80. USART_Init(USART1,&USART_InitStructure);
  81. //TXE发送中断,TC传输完成中断,RXNE接收中断,PE奇偶错误中断,可以是多个
  82. //USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
  83. //中断配置
  84. USART_ITConfig(USART1,USART_IT_TC,DISABLE);
  85. USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);
  86. USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
  87. //配置UART1中断
  88. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
  89. NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;               //通道设置为串口1中断
  90. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;       //中断占先等级0
  91. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;              //中断响应优先级0
  92. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 //打开中断
  93. NVIC_Init(&NVIC_InitStructure);
  94. //采用DMA方式发送
  95. USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
  96. //采用DMA方式接收
  97. USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
  98. //启动串口
  99. USART_Cmd(USART1, ENABLE);

[cpp] view plain copy

  1. //串口1接收中断
  2. void USART1_IRQHandler(void)
  3. {
  4. uint32_t temp = 0;
  5. uint16_t i = 0;
  6. if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
  7. {
  8. //USART_ClearFlag(USART1,USART_IT_IDLE);
  9. temp = USART1->SR;
  10. temp = USART1->DR; //清USART_IT_IDLE标志
  11. DMA_Cmd(DMA1_Channel5,DISABLE);
  12. temp = UART_RX_LEN - DMA_GetCurrDataCounter(DMA1_Channel5);
  13. for (i = 0;i < temp;i++)
  14. {
  15. Data_Receive_Usart = Uart_Rx[i];
  16. //启动串口状态机
  17. usart_state_run();
  18. }
  19. //设置传输数据长度
  20. DMA_SetCurrDataCounter(DMA1_Channel5,UART_RX_LEN);
  21. //打开DMA
  22. DMA_Cmd(DMA1_Channel5,ENABLE);
  23. }
  24. __nop();
  25. }

测试结果:

条件:单片机运行于72M,与PC通信速率为460800.PC每隔100ms发送一个9个字节的包:c5 5c 6 0 6F 10 5 4e f7.

测试:单片机每次收到此包,一个IO作电平跳转,然后处理返回一包.

示波器显示:

放大显示:

时间: 2024-10-15 08:43:34

STM32的串口采用DMA方式接收数据测试(转)的相关文章

STM32F407的串口采用DMA收发数据

?? STM32F407的串口采用DMA收发数据 本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 环境: 主机:WIN8 开发环境:MDK5.13 mcu: stm32f407VGT6 说明: 之前用STM32F103实现DMA收发串口数据,现在项目中采用STM32F407,所以将此机制移植到F4上. STM32F103上用DMA收发串口数据文章: STM32的串口采用DMA方式发送数据测试 STM32的串口采用DMA方式接收数据测试 源代码: 串

【STM32H7教程】第46章 STM32H7的ADC应用之DMA方式多通道采样

完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第46章       STM32H7的ADC应用之DMA方式多通道采样 本章教程为大家讲解ADC+DMA方式的多通道数据采集,实际项目中有一定的使用价值,使用一路ADC就可以采集多个通道的数据. 46.1 初学者重要提示 46.2 ADC稳压基准硬件设计 46.3 ADC驱动设计 46.4 ADC板级支持包(bsp_adc.c) 46.5 ADC驱动移植和使用 46.

STM32的串口DMA收发以及双缓冲区的实现

在使用STM32的UART的DMA功能总结如下: 首先上代码,这里采用STM32 的USART1作为Demo,RX的DMA为DMA1_Channel5,TX的DMA为DMA1_Channel4.初始化如下,红色的标记需要注意: RX-DMA初始化 1 // DMA Rx 2 USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); 3 DMA_Cmd(DMA1_Channel5,DISABLE); 4 DMA_InitStruct.DMA_PeripheralBa

关于STM32 USART(串口)发送数据丢失第一帧的真实原因探索

自我介绍 为什么要写个自我介绍?俗话说,光说不练假把式,光练不说傻把式, 因为本人一直很自负,感觉什么东西都可以很快上手(当然非对口专业知识要求高的技能除外),如果我不把这自负表现出来,感觉会憋出内伤. 本人于2015年毕业于电子科技大学,开始的理想是进入一家国外的游戏公司,但理想很丰满,现实很骨感,给育碧.2k Game.Gameloft.EA都投了简历,但都被无情pass掉了(在此吐槽一下,这些公司真的是想在校园里招本科生吗?明明是研究生的计算机图形学却成了这些公司对本科生的要求).后来毕业

【STM32H7教程】第60章 STM32H7的DAC应用之定时器触发实现DMA方式双通道波形

完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第60章       STM32H7的DAC应用之定时器触发实现DMA方式双通道波形 本章节为大家讲解DAC采用定时器触发方式实现DMA双通道波形输出,实际输出效果也比较好,项目使用价值也比较大. 60.1 初学者重要提示 60.2 H7和F4的DAC输出效果对比 60.3 DAC驱动设计 60.4 DAC驱动移植和使用 60.5 实验例程设计框架 60.6 实验例程

DMA方式的数据传送过程

DMA方式具有如下特点: 1. 外部设备的输入输出请求直接发给主储存器. 主存储器既可以被CPU访问,也可以被外围设备访问.因此,在主存储器中通常要有一个存储管理部件来为各种访问主存储器的申请排队,一般计算机系统把外围设备的访问申请安排在最高优先级. 2. 不需要做保存现场和恢复现场等工作,从而使DMA方式的工作速度大大加快. 由于在外围设备与主存储器之间传送数据不需要执行程序,因此,也不动用CPU中的数据寄存器和指令计数器等. 3.在DMA控制器中,除了需要设置数据缓冲寄存器.设备状态寄存器或

单片机第11课:串口通信查询方式---从计算机接受数据

如何用计算机给单片机发送数据,单片机如何接收数据呢? JP3与P0口相连接.从计算机给单片机发送一个十六进制数据,然后看数码管的显示. #include<reg51.h> /* *给单片机发送一个十六进制的数据,用来显示数码管 */ void initSer(); void main() {<span> </span>initSer(); while(1) { //查询RI的值,如果是1,那么接收到了数据,此时应该软件清零,RI = 0 if(RI == 1) { RI

【黑马Android】(05)短信/查询和添加/内容观察者使用/子线程网络图片查看器和Handler消息处理器/html查看器/使用HttpURLConnection采用Post方式请求数据/开源项目

备份短信和添加短信 操作系统短信的uri: content://sms/ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.itheima28.backupsms" android:versionCode="1

消息队列技术终结者(四)—消息消费者以何种方式接收消息

消息消费者可以同步接收消息,也可以异步接收消息,一般而言,采用异步的方式接受消息优于采用同步的方式接受消息,体现在:        1.异步方式创建的网络流量比较小,单向推送消息并使之通过管道进入消息监听器.管道操作支持将多条消息聚合为一个网络调用.        2.异步方式使用线程比较少.异步方式在消息接收者不活动期间不使用线程.同步方式的消息接收者在接收调用期间内使用线程,结果线程可能会长时间保持空闲,尤其是该调用中指定了阻塞超时.        3.使用异步方式可以规避阻塞服务器上运行的