STM32CubeMX—串口空闲中断+DMA接收
一.串口中断通信
串口中断方式的特点
- 发送数据时,将一字节数据放入数据寄存器DR;接收数据时,将DR的内容存放到用户存储区;
- 中断方式不必等待数据的传输过程,只需要在每字节数据收发完成后,由中断标志位触发中断,在中断服务程序中放入新的一字数据或者读取接收到 的一字节数据;
- 在传输数据量较大,且通信波特率较高(大于38400)时,如果采用中断方式,每收发一个字节的数据,CPU都会被打断,造成CPU无法处理其他事务。因此在批量数据传输,通信波特率较高时,建议采用DMA方式。
中断代码如下
void USART1_IRQHandler(void)
{/* USER CODE BEGIN USART1_IRQn 0 */if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET){if (rxReceiveCount1 < 20){rxBuffer1[rxReceiveCount1]=(uint8_t)(huart1.Instance->DR);++rxReceiveCount1;}else{rxReceiveCount1 = 0;}__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);}else if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET){__HAL_UART_CLEAR_IDLEFLAG(&huart1);uint32_t tmp1;tmp1 = huart1.Instance->SR;tmp1 = huart1.Instance->DR;rxFrameFlag1 = 1;}/* USER CODE END USART1_IRQn 0 *//* USER CODE BEGIN USART1_IRQn 1 *//* USER CODE END USART1_IRQn 1 */
}/**
HAL_UART_Receive_IT(&huart1, (uint8_t *)&rc_data, 1)
的作用是:
启动UART1的中断接收模式:该代码将启动UART1的中断接收模式,使UART1开始等待接收数据。
指定接收缓冲区:将
rc_data
变量的地址作为接收数据的缓冲区地址。这意味着当UART1接收到数据时,数据将存储在rc_data
变量中。指定缓冲区大小:
1
表示接收数据的大小为1个字节。这意味着当UART1接收到1个字节的数据时,将触发一个接收中断,并将数据存储在rc_data
变量中。
需要注意的是,在初始化UART1时,需要先调用一次该函数,来启动UART1的中断接收模式;再接受完一个数据后,也需要再调用该函数来重新启动UART1的中断接收模式,以等待接收下一个字节的数据。
二.串口空闲中断+DMA
1.空闲中断接收
空闲中断接收,当一帧数据接收完成之后,串口会进入到空闲中断中去,然后在空闲中断中处理收到的数据。这种模式对处理不定长数据帧带来很大的便利,我们不必频繁的进入接收中断处理数据,但是弊端也是明显的,由于每次都要接收完一个完整的数据帧后才空闲中断,所以当一帧数据出错时,我们也不得不接收这帧错误的数据。在通讯可靠的场合,使用空闲中断接收模式接收串口数据,将会大大提高系统的性能。
2.DMA
1.简介
2、使用场景
DMA用在只需要传输数据,不需要处理数据的地方,有三种传输方式:
- 外设→存储器(例:从串口RDR寄存器写入某数据buf)
- 存储器→外设(例:从某数据buf写入串口TDR寄存器)
- 存储器→存储器(例:复制某特别大的数据buf)
3、指针递增
在传输数据时,可以配置指向传输双方数据的指针是否自动向后递增。通过单个寄存器访问外设源或目标数据时,禁止递增模式十分有用。
通常如下图配置:
Cubemx配置
串口设置
DMA设置
开启全局中断
最后直接生成文件
代码编写
1.在usart.c文件中添加
定义变量
/* USER CODE BEGIN 0 */
volatile uint8_t rx_len=0; //接收到的数据长度
volatile uint8_t recv_end_flag=0;//接收完成标志
uint8_t rx_buffer[200];//缓存数组
/* USER CODE END 0 */
开启空闲中断和dma接收
/* USER CODE BEGIN USART1_Init 2 */__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE); //使能空闲中断HAL_UARTEx_ReceiveToIdle_DMA(&huart1,rx_buffer,200); //开启DMA接收/* USER CODE END USART1_Init 2 */
重定义fputc,是为了能使用printf函数
/* USER CODE BEGIN 1 */
//重定向fputc函数
int fputc(int ch, FILE *f)
{HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);return ch;
}
/* USER CODE END 1 */
2.在usart.h文件中添加
#include <stdio.h>/* USER CODE BEGIN Includes */
extern volatile uint8_t rx_len ; //接收一帧数据的长度
extern volatile uint8_t recv_end_flag; //一帧数据接收完成标志
extern uint8_t rx_buffer[200]; //接收数据缓存数组
注意这里的#include <stdio.h>,不添加的话重定向fputc函数那里会报错
3.在中断函数中添加
void USART1_IRQHandler(void)
{/* USER CODE BEGIN USART1_IRQn 0 */ uint32_t tmp_flag = 0;uint32_t temp;tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位if((tmp_flag != RESET)){ __HAL_UART_CLEAR_IDLEFLAG(&huart1);//temp = huart1.Instance->SR; temp = huart1.Instance->DR; HAL_UART_DMAStop(&huart1); temp = hdma_usart1_rx.Instance->CNDTR;//获取此时DMA中未传输的数据个数rx_len = 200 - temp; //总计数减去未传输的数据个数,得到此次接收到的数据个数recv_end_flag = 1; }HAL_UART_IRQHandler(&huart1); /* USER CODE END USART1_IRQn 0 *//* USER CODE BEGIN USART1_IRQn 1 *//* USER CODE END USART1_IRQn 1 */
}
这里不使用回调函数
4.在main.c中添加
while (1){/* USER CODE END WHILE */if(recv_end_flag ==1) { printf("接收到的数据长度为%d\r\n",rx_len);HAL_UART_Transmit(&huart1,rx_buffer, rx_len,200);for(uint8_t i=0;i<rx_len;i++){rx_buffer[i]=0;}printf("\r\n");rx_len=0;recv_end_flag=0;}HAL_UARTEx_ReceiveToIdle_DMA(&huart1,rx_buffer,200);//再次开启DMA接收 /* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
这里只是测试代码,将接收到的数据再利用串口输出到串口助手
5.结果
当数据接收间隔时间很短的情况下,这里是1ms,数据接收会出错;在10ms后就正常
注意事项
1.程序下载到板子上没反应,只有在一步一步调试时才有输出。最后勾选了Use MicoLIB后程序就正常运行了
2.输出中文时串口助手上显示乱码,代码格式要改为GB 2312,但直接在keil上修改没什么用,我这里是在vscode上修改格式后保存,在keil上运行就行了。
STM32CubeMX—串口空闲中断+DMA接收相关推荐
- stm32LL库串口空闲中断+DMA接收
stm32LL库串口空闲中断+DMA接收 俺用的STM32F407VGT6,cubemx生成的代码. cubemx的串口配置 这里就按默认参数配就行,主要是要打开后面的DMA 在这里点添加就完事了,如 ...
- STM32单片机串口空闲中断+DMA接收不定长数据
在上一篇文章STM32单片机串口空闲中断接收不定长数据中介绍了利用串口空闲中断接收不定长数据,这种方式有一个问题就是串口每接收到一个字节就会进入一次中断,如果发送的数据比较频繁,那么串口中断就会不停打 ...
- 【无标题】STM32F767串口空闲中断+DMA实现不定帧长度的接收
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.配置串口与DMA 二.空闲中断服务函数 二.串口+DMA发送 三.主函数 总结 前言 提示:这里可以添加本文要记录 ...
- 华大HC32F460串口空闲中断+DMA收发配置,记录一下自己遇到的坑
华大HC32F460串口空闲中断+DMA收发配置,记录一下自己遇到的坑 华大HC32F460串口空闲中断+DMA收发配置,记录一下自己遇到的坑 注:个人笔记,如有错误,还望谅解. STM32 在STM ...
- 串口的空闲中断+DMA接收(附F4代码)
传统串口接受与发送: 串口接受一个很长的帧,接受帧时依靠串口中断每次只能传输8位,传一个帧要进入好多次中断,每次进入中断都要判断是否接收完毕. DMA串口接收与发送: 1,电脑通过串口1给STM32F ...
- GD32F303RET6 串口空闲中断+DMA数据发送接收+环形缓冲区方式保存数据
GD32F303RET6 DMA 通道映射关系 串口 源文件 #include "uart.h" #include "stdio.h" #include &qu ...
- MM32F3277空闲中断+DMA接收不定长数据
摘要:在实际项目中经常用到串口接收一些不定长的数据,怎么判断这一帧数据接收完成了呢?通常使用UART非空中断配合简单的数据协议,在数据中加入帧头.帧尾,在程序中判断是否接收到帧尾来确定数据接收完毕,对 ...
- CH32V3xx USART 空闲中断+DMA接收
目录 1.CH32V3xx USART简介 2.测试程序 2.1 USART 初始化配置 2.1 发送函数 2.1 接收中断 1.CH32V3xx USART简介 CH32V3xx系列MCU包含3 ...
- GD32F470之串口空闲中断+DMA篇
先申请,本栏目用的都是GD32F470芯片240M,软件用的是keil,编写用的是C++(其实和C没有区别). C++格式下怎么使用printf 因为keil下使用C++,要把Micro LIB去掉 ...
最新文章
- dpkg: 处理软件包 update-notifier-common (--configure)时出错:
- Spring中的p标签(转)good
- 坚持不放弃,修得好结果。
- kafka副本数据同步策略
- 滚动加载数据 php,无刷新动态加载数据 滚动条加载适合评论等页面
- 使用dropwizard(3)-加入DI-dagger2
- ORA-06550 PLS-00172 字符串太长 超过3W 处理方式
- 【Python】万花筒
- 白盒测试方法_软件测试的种类:白盒测试和黑盒测试
- STM32 定时器输出pwm的频率计算方法 PWM 频率检测方法 直流电机的位置控制
- 《算法分析与设计》课程任务
- python 下采样和上采样
- vue-router路由的使用
- 最近好颓废啊,改过自新就从收拾自己的东西开始吧
- Python随机生成6位数密码
- 鸽笼原理 c语言,抽屉原理的三个公式,抽屉问题经典例题10道
- 【gfs】google file system 之重点剖析
- 高质量解读《互联网企业安全高级指南》——目录
- 【SAM】51Nod1647 小Z的Trie
- 当前没有源代码管理提供程序进行注册
热门文章
- 安卓android刷机工具!2021大厂Android面试经历,值得收藏!
- ajax xmlhttp.responsetext,用ajax实现异步刷新,xmlHttp.responseText接到的值不对
- 3D 渲染过程:逼真的 3D 渲染的分步指南_棋盘格渲染
- 全国职业院校技能大赛网络建设与运维赛项赛题(一)
- 民法典实施后,婚前、婚后买房区别很大
- 归并排序和快速排序的浅析
- 鹰眼系统;全链路监控系统;分布式监控系统
- HTML5 Canvas 绘制星条旗
- 反诈宣传互动答题小程序及其三种玩法
- 通过Alexa API获取Alexa排名