65 STM32F0系列 串口DMA循环接收实验记录

stm32f103串口接收队列,DMA循环模式+空闲中断 串口通讯最主要的就是要不丢数据,不丢帧,基本设想就是建立一个大的串口缓冲区,串口接收到的数据使用循环队列的方式全部往这个缓冲区放,不过这种方式需要把串口缓冲区弄大一点,防止数据覆盖。在stm32中,利用DMA+空闲中断很容易做到这一点。只需要将DMA设置为循环模式,如下图: 也就是说,在循环模式下,当DMA传输了一个数据,DMA_CNDTRx传输数量寄存器相应减一,当DMA_CNDTRx传输数量寄存器减为0时,DMA_CNDTRx寄存器将恢复为相应的初始值,不用软件干预,那么,这不就是循环队列的方式吗? 阅读详情
AI摘要

针对STM32F030单片机在串口接收数据时遇到的中断冲突导致数据丢失问题,本文介绍了通过使用DMA方式来避免这一情况。详细阐述了配置DMA接收的要点,包括理解DMA的工作模式,选择适当的通道,以及在没有串口空闲中断的情况下,如何在while(1)循环中接收DMA数据。同时提供了具体的STM32F030串口及DMA初始化代码示例。

1.引言

        最近因为中断冲突问题,导致串口接收数据时随机丢失一两个字节。无奈串口的中断优先级不能是最高的,所以中断冲突问题明显存在,因此需要串口使用DMA方式来接收数据,从而规避串口接收数据丢失问题。

2.DMA配置经验

        首次使用dma,需要了解一下dma的知识。

        1.首先最重要要了解的一点就是,dma接收数据一定要接收到指定长度的数据,或指定长度的一半数据才能产生接收中断,如果数据没有达到一半或指定长度,就无法产生dma接收数据通知。

        一般解决这个问题是串口空闲中断IDE方式解决。也就是串口传完数据产生空闲中断后去读取DMA收到的数据,就能接收不定长度的数据了。

        然而现实很悲催,我所使用的cortex-m0芯片,居然没有串口空闲中断,为此需要另寻它法。所以就选择了在while(1)循环中接收DMA数据了。

        2.既然配置了串口的DMA接收,因此就不需要启动串口接收中断了,但串口的收发模式配置还是需要的。如下:

UART_InitStructure.UART_Mode		= UART_Mode_Rx | UART_Mode_Tx; //收发模式

        3.DMA模式选择

        DMA_Mode_Normal和DMA_Mode_Circular模式,指的是单次和多次的问题。如果是DMA_Mode_Normal模式,进行完一次DMA数据传输后,要启动第二次DMA传输,需先关闭该DMA通道,重新设置DMA传输数据个数,再开启DMA通道。而DMA_Mode_Circular模式则不需要,其会自动配置。

         下述代码中有这个体现,DMA_Mode_Normal模式下如果不重新配置,则收发就不正常。

        4.查看串口对应的DMA channel

        对于STM32F030单片机UART1引脚对应的DMA channel通道,可以看STM32F030参考手册,而不是芯片手册!!!!别找错文档了。然后查所使用的的引脚对应的通道选择就行。

在这里插入图片描述         我所使用的是USART1,并且没有重映射RX到其它引脚,因此是channel3,这个实际的时候要注意,别搞错了,当然搞错了也没关系,试一下就好了,花不了什么时间。

 

3.实验代码

#define UART1_RX_LEN		(64)
uint8_t tUart1_Rx[UART1_RX_LEN] = {0};


void UART1_Init(void)
{
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    NVIC_InitTypeDef NVIC_InitStructure = {0};
	UART_InitTypeDef UART_InitStructure = {0};

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, ENABLE);	//使能UART1,GPIOA时钟
	/////////////////////////////////////////////////////////////////
	//1.引脚初始化
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_0);
	GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_0);

	GPIO_InitStructure.GPIO_Pin		= GPIO_Pin_6; //PA.9
	GPIO_InitStructure.GPIO_Speed	= GPIO_Speed_2MHz;
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_AF_PP; //复用推挽输出
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOA.9
	
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_7;//PA10
	GPIO_InitStructure.GPIO_Speed 	= GPIO_Speed_2MHz;
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_IPU;//浮空输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOA.10 

	/////////////////////////////////////////////////////////////////
	//2.串口初始化
	UART_InitStructure.UART_BaudRate 	= 115200;//串口波特率
	UART_InitStructure.UART_WordLength	= UART_WordLength_8b;//字长为8位数据格式
	UART_InitStructure.UART_StopBits	= UART_StopBits_1;//一个停止位
	UART_InitStructure.UART_Parity		= UART_Parity_No;//无奇偶校验位
	UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;//无硬件数据流控制
	UART_InitStructure.UART_Mode		= UART_Mode_Rx | UART_Mode_Tx; //收发模式
	UART_Init(UART1, &UART_InitStructure); //初始化串口1
	UART_DMACmd(UART1, UART_DMAReq_EN, ENABLE); 
	UART_Cmd(UART1, ENABLE);

	//dma配置
    UART1_DMAInit();
}

void UART1_DMAInit(void)
{
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

	/////////////////////////////////////////////////////////////////
	//dma初始化 p -> m
	DMA_DeInit(DMA1_Channel3);	
	DMA_Cmd(DMA1_Channel3, DISABLE);
	DMA_InitStructure.DMA_PeripheralBaseAddr 	= (uint32_t)&UART1->RDR;//外设数据地址
	DMA_InitStructure.DMA_MemoryBaseAddr 		= (uint32_t)tUart1_Rx;  //自己的接收buf
	DMA_InitStructure.DMA_BufferSize			= UART1_RX_LEN;  // 缓存大小
	DMA_InitStructure.DMA_M2M 					= DMA_M2M_Disable;	 // 内存到内存关闭
	DMA_InitStructure.DMA_Mode 					= DMA_Mode_Normal;	// 普通模式
	DMA_InitStructure.DMA_DIR 					= DMA_DIR_PeripheralSRC;	 // 外设到内存
	DMA_InitStructure.DMA_Priority 				= DMA_Priority_High; // DMA通道优先级
	DMA_InitStructure.DMA_MemoryInc 			= DMA_MemoryInc_Enable;// 内存地址递增
	DMA_InitStructure.DMA_PeripheralInc			= DMA_PeripheralInc_Disable;//外设基地址不需要递增
	DMA_InitStructure.DMA_MemoryDataSize 		= DMA_MemoryDataSize_Byte; 
	DMA_InitStructure.DMA_PeripheralDataSize 	= DMA_PeripheralDataSize_Byte;
	DMA_Init(DMA1_Channel3,&DMA_InitStructure);
	DMA_Cmd(DMA1_Channel3, ENABLE); 
	/////////////////////////////////////////////////////////////////
}

//因为该单片机没有串口空闲中断
//所以只能使用poll接收dma数据
//该函数放在while(1)中即可
void UART1_DMAChannel3_rcvTask(void)
{
	uint16_t rxSize = 0;

	//获取当前接收到的数据大小
	rxSize = UART1_RX_LEN - DMA_GetCurrDataCounter(DMA1_Channel3);
	//如果数据大于0,说明开始接收数据了
	if(rxSize>0)
	{
		//休眠10ms,是因为让串口dma继续接收数据
		//根据115200波特率计算,10ms足够传输1024字节大小的数据
		//所以delay 10ms基本满足单次数据的收
		delay_ms(50);
		DMA_Cmd (DMA1_Channel3,DISABLE);//重新配置DMA时,需要先disableDMA

		//接收完成,再获取一次实际的数据长度
		rxSize = UART1_RX_LEN - DMA_GetCurrDataCounter(DMA1_Channel3);

		//接收数据,写入buf
		BleClient_RcvDataBufIn(tUart1_Rx, rxSize);
		
		memset(tUart1_Rx,0,UART1_RX_LEN);    //清空数组
		DMA_Init(DMA1_Channel3, &DMA_InitStructure); //重新配置一次DMA
		DMA_Cmd (DMA1_Channel3,ENABLE); 
	}
}

over!

STM32F0 USART 常用配置,DMA不定长接收,pingpong接收,硬件流控制,过采样,接收超时中断和空闲中断 STM32F0 USART 通信 1.DMA不定长接收 2.硬件流控制 3.过采样率 4. 阅读详情

相关推荐

STM32本质是嵌入式操作系统底座,不是高级51单片机

STM32并非传统意义上的MCU,而是基于Cortex-M架构的可裁剪嵌入式操作系统底座,其统一寻址空间、NVIC中断调度器和总线矩阵设计,决定了它必须以系统级思维进行开发。理解这一本质,才能规避‘stm32 adc切换通道卡死’‘stm32 can通信突然连不上’等高频问题——它们往往源于对内存布局、中断优先级或外设时序的误判,而非代码逻辑错误。技术价值在于支撑FreeRTOS、LwIP等实时系统稳定运行;典型应用场景包括物联网网关、电机PID控制与工业传感终端;本文聚焦真实项目中反复验证的底层原理与协同

weixin_34301132的博客 422

STM32串口DMA方式向上位机连续发送接收数据

STM32串口DMA方式向上位机连续发送接收数据

qq_53088119的博客 2612

STM32F407VET6深度解析:性能、选型与实战项目指南

单片机与嵌入式系统开发中,芯片选型往往决定了项目的成本与成败。ARM Cortex-M4内核作为嵌入式领域的主流架构,凭借其平衡的性能与功耗表现,成为众多工程师的首选。STM32F407VET6正是这一架构下的典型代表,它集成了丰富的通信接口与模拟外设,适用于工业控制、物联网节点、数据采集等多种应用场景。理解MCU的性能指标与外设资源,掌握最小系统板设计要点,并借助HAL库快速搭建工程,是提升开发效率的关键。本文从芯片资源与命名规则出发,介绍开发环境搭建、调试技巧及CAN总线实战案例,帮助开发者系统化掌握这

weixin_34195142的博客 515

STM32实现DMA接收串口数据

我们可以串口打印出收到的数据和数据中的数据,验证DMA是否正常工作。可以到数据处理那个地方进行处理。USART1在初始化中就已经波特率为115200.我们可以与上位机相连,进行测试。一..首先我们得配置DMA和USARAT,我们的原理是DMA1的通道5为USART1的RX引脚。二.中断进行数据处理(stm32f10x_it.c)然后有什么不懂的地方可以在评论区留言。1.USART1的配置。

嵌入式 7486

基于STM32F042的NTC热敏电阻测温方案:硬件设计到标定实践

热敏电阻作为温度传感的核心元件,其阻值随温度非线性变化;通过分压电路将电阻变化转换为电压信号,再由MCU内置ADC进行采样,即可实现低成本高精度的温度测量。STM32F042等主流MCU集成了12位ADC与丰富的通信接口,配合软件滤波和B值方程或查表法,能在工业控制、汽车电子等领域稳定完成温度采集任务。针对汽车冷却液温度监测场景,从分压电阻选型、ADC采样时间配置、限幅平均滤波到两点标定,完整呈现了一套可落地的NTC测温工程方案,为开发者提供了兼顾精度与可靠性的实践参考。

weixin_34268310的博客 399

国产MCU替代STM32的五大隐藏坑与系统性避坑指南

Pin-to-Pin兼容是国产MCU替代STM32的常见起点,但其本质仅指物理封装与基础引脚功能对齐,并非电气特性、时序逻辑、复位行为或寄存器映射的全等价。真正影响稳定性的关键在于调试接口时序差异、时钟树启动机制变异、GPIO驱动能力衰减、中断向量表错位及ADC模拟前端温漂等底层细节。这些‘隐藏坑’往往藏于Errata勘误表、兼容性白皮书附录或FAE口头提示中,导致首次上电失败、通信异常、HardFault频发或高温下精度骤降。工程实践中,必须将替代视为系统级重构——从选型阶段交叉验证勘误表,到硬件预留跳线

weixin_34238633的博客 889

AM32电调遥测功能实现:DMA+USART与CRC8校验

在嵌入式系统开发中,遥测技术是实现设备状态监控与反馈的关键。其原理是通过通信协议将传感器数据从设备端回传至控制端,技术价值在于提升系统可靠性与可调试性。应用场景广泛,如无人机电调实时监测电压、电流、温度等参数。本文以AM32开源电调固件为例,详细阐述基于DMA和USART的异步遥测发送方案,涵盖帧格式设计、CRC8校验算法、双缓冲管理及调试优化,为嵌入式遥测开发提供实践参考。

weixin_34341117的博客 373

APM32F072移植moonglow/kvaser开源固件:USB-CAN适配器实战

在嵌入式开发中,USB-CAN分析仪是汽车电子与工业控制调试的关键工具。开源固件moonglow通过模拟kvaser Leaf硬件协议,使低成本MCU也能被主机识别为专业CAN设备。然而,将固件从STM32F072移植到国产Cortex-M0+芯片APM32F072,并非简单的重新编译,而是涉及时钟树配置、USB端点映射、CAN控制器寄存器适配与中断向量表核对等底层细节。本文从系统时钟初始化入手,讲解PLL倍频、USB描述符与缓冲区对齐、CAN位时序与过滤器设置等核心原理,并结合SWD/ISP刷机与总线验证

weixin_33896726的博客 378

STM32从入门到精通:内核、外设、开发实战与选型避坑指南

在嵌入式系统开发中,32位微控制器(MCU)凭借更强的数据处理能力和丰富外设,逐步取代8位单片机成为主流。其核心原理在于采用ARM Cortex-M内核架构,通过统一的内核生态与可扩展的外设集,实现从低功耗控制到高性能信号处理的平滑覆盖。这种技术价值使得开发者能够以更低的门槛构建电机控制、物联网终端、工业自动化等应用。STM32作为基于Cortex-M内核的典型产品家族,将内核、外设、开发工具链与软件库整合为完整生态,让嵌入式开发从资源受限的寄存器操作转向应用层快速实现。理解其内核差异、外设特性与选型逻辑,

weixin_34122604的博客 287

CW32L012滑动窗口协议解析库设计与实战

滑动窗口是一种面向协议语义的字节流处理机制,区别于无状态的ring buffer,其核心在于将时间序列的UART接收数据映射为空间对齐的有效帧视图。在资源受限的MCU(如CW32L012)上,传统环形缓冲易引发边界撕裂、状态漂移和内存错配等问题,而滑动窗口通过协议感知型缓冲区裁剪、双缓冲硬件协同与事件驱动状态机,实现高可靠、低开销的自定义协议解析。该技术广泛应用于传感器节点、工业IO模块及低功耗通信场景,尤其适配无DMA UART、小SRAM(16KB)、高速串口(921600bps)等典型嵌入式约束条件。

weixin_33991418的博客 563

USB 2.0 Full Speed:被低估的物理层基石与枚举关键

USB 2.0并非单一速率标准,而是一套分层兼容的通信体系;Full Speed(12 Mbps)作为其向后兼容锚点与高速协商起点,在物理层(如NRZI编码、终端匹配、25Ω单端阻抗)、协议层(复位握手、地址分配、描述符校验)及系统级(时钟精度±0.25%、SOF帧同步)均构成硬性约束。它决定设备能否通过枚举、维持稳定通信,并支撑High-Speed链路建立与回退机制。理解Full Speed,是开展USB固件开发、PHY电路设计及一致性调试的前提——尤其在嵌入式、工业与医疗设备等对可靠性要求严苛的场景中,

weixin_34212762的博客 613

UART串口通信原理与嵌入式实战指南

串口通信(UART)是嵌入式系统中最基础、最广泛使用的异步通信机制,其核心在于将并行数据按时间序列编码为单线传输的帧结构,通过起始位、数据位、校验位和停止位实现可靠同步。它不依赖复杂协议栈,凭借低资源占用、确定性时序和硬件级简单性,在工业控制、传感器网络、固件升级等场景中不可替代。理解波特率容差、电平标准(TTL/RS-232/RS-485)差异、信号完整性约束及环形缓冲区+状态机软件架构,是保障长距离、抗干扰、高稳定通信的关键。本文聚焦真实工程痛点,覆盖从物理层布线、电平转换选型到中断/DMA驱动、协议解

weixin_33863087的博客 369

STM32F0标准外设库实战:工程搭建到FreeModbus移植全攻略

嵌入式开发中,基于ARM Cortex-M0内核的STM32F0系列以低成本、低功耗和丰富外设成为入门级控制应用的热门选择。与之配套的ST官方固件库包括标准外设库和HAL库两种形态,前者以寄存器映射薄封装著称,后者依赖CubeMX生态抽象。理解两者的设计原理与适用场景,有助于在资源受限的工控、传感采集等场景中做出合理选型。标准外设库凭借代码透明、调试直接的优势,至今仍在众多成熟项目中占据一席之地。从GPIO点灯、串口中断到定时器配置,再到FreeModbus RTU协议栈的底层移植,涉及时钟初始化、NVIC

weixin_34413802的博客 385

物联网开发环境配置全指南:Keil、Qt、EMQX实战避坑

物联网开发涉及硬件驱动、嵌入式编译、串口通信与MQTT消息中间件等多层技术栈,其环境配置本质是跨平台、跨工具链的系统性工程。理解Keil MDK芯片包管理机制、Qt SerialPort模块加载原理及EMQX 5.0 WebSocket调试能力,是保障STM32与Qt端稳定通信的基础技术前提。这些环境要素共同决定了固件烧录成功率、串口数据完整性与MQTT连接可靠性,直接影响温湿度监测、工业网关等典型应用场景的快速验证与部署效率。本文聚焦真实项目中高频复现的环境断点问题,提供可复用的安装校验清单与版本兼容方案

weixin_34208283的博客 482

STM32智慧行李箱工程实践:从裸机状态机到量产级代码规范

嵌入式系统中的‘智能硬件’本质是资源受限下的确定性实时控制。其核心原理在于裸机或轻量RTOS环境下,通过状态机调度、硬件闭环(如PID+编码器+IMU)与寄存器级外设配置,实现高鲁棒性响应。技术价值体现在低功耗、抗干扰、故障可诊断与产线可维护——这正是STM32在移动终端类项目中不可替代的关键能力。典型应用场景包括智能行李箱、AGV底盘、协作机器人关节控制器等具身智能终端。本文以真实量产项目为蓝本,深度解析电机驱动选型、IMU校准、电源协同策略及‘完整代码’的七道验证关卡,覆盖STM32F407裸机开发全链

weixin_34208283的博客 416

stm32f070 HALL库 dma+Uart+不定长接收数据

stm32f070 stm32cubeMX 串口接收不定长度程序,初始化ltc2942库仑计。读取电压,温度,库伦。

超集成MCU:单芯片系统设计原理与工程落地指南

超集成MCU并非营销概念,而是嵌入式系统向硅片级集成演进的必然路径——它将传统PCB上分散的USB PHY、高精度ADC、硬件加密引擎等模块统一整合至单颗芯片内,本质是SoC-on-a-Chip的工程实现。其技术驱动力源于先进制程(40nm以下混合工艺)、BOM与PCB成本压缩需求,以及医疗、工业等场景对功能安全与电磁鲁棒性的刚性要求。在实际应用中,需重点关注模拟电源完整性、启动时序约束、高速接口阻抗匹配等物理层挑战,同时重构开发范式:从代码编写转向资源契约管理与全栈验证。本文围绕GD32H7、STM32H

优快云头条 520

STM32F0xx_DMA收发USART数据配置详细过程 - 中断方式.zip

STM32F0xx_DMA收发USART数据配置详细过程 - 中断方式

上一篇: 64 串口测速工具及实验
下一篇: 66 ESP32 ethernet\basic实验记录
Chasing_Chasing
博客等级 码龄10年 233粉丝 87原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值