STM32串口DMA接收数据错位——暴力解决方法
背景:两片STM32通过串口通信,为了减小CPU负担,采用DMA进行通信,发送端为STM32F103C8T6,接收端为STM32F407VET6。在调试的过程中发现,一直出现数据错位的问题,接收端尝试了串口空闲中断和串口DMA传输完成中断,错位问题依旧,其实我之前遇到过这个问题,那次发送端没有使用DMA,而是直接用串口发送,接收端采用DMA接收完成中断,检测到错位后,延时重置DMA,直到DMA接收同步后,不再重置,此后DMA便会保持同步,不会错位。但是这次不知道为什么采用上次的方法没有解决,因此决定直接用最简单粗暴的方法——查找,但是弊端是会在中断中运行一段比较占空时间的代码。
说明:主要部分在接收中断(本文最后的代码段),发送端发送的DMA数据长度为a,接收端DMA配置的BufferSize为2a,这样即使错位,在2a的数据长度中也一定会存在一段完整的有效数据。接收中断中,在接收buffer的前半段查找帧头,找到之后,判断帧头+a-1的位置是否是帧尾,如果是,则基本可以认为中间即为有效数据,将该段数据拷贝到一个新的数组中,等待解析。
配置部分:发送端 STM32F103C8T6
/* uart3 for communicate with the master */
void vUart3Config(void)
{
        GPIO_InitTypeDef 	GPIO_InitStructure;
	USART_InitTypeDef       USART_InitStructure;
	NVIC_InitTypeDef 	NVIC_InitStructure;
	DMA_InitTypeDef		DMA_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	/* USART3_RX	  GPIOB.11 */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_Init(GPIOB, &GPIO_InitStructure);  
	/* USART3_TX   GPIOB.10 */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	USART_InitStructure.USART_BaudRate = 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_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;
        USART_Init(USART3, &USART_InitStructure);
        USART_Cmd(USART3, ENABLE);
        USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
	{ /* send dma */
		USART_DMACmd(USART3,USART_DMAReq_Tx,ENABLE);
		DMA_DeInit(DMA1_Channel2);
		DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(USART3->DR));
		DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SendToMaster_Buff;
		DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
		DMA_InitStructure.DMA_BufferSize = USART3_DMA_send_buffersize;
		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_MemoryDataSize_Byte;
		DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
		DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
		DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
		DMA_Init(DMA1_Channel2,&DMA_InitStructure);
		NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init(&NVIC_InitStructure);
		DMA_ITConfig(DMA1_Channel2,DMA_IT_TC,ENABLE);
		DMA_Cmd(DMA1_Channel2,ENABLE);
	}
}
配置部分:接收端 STM32F407VET6
void vUTConfig(void)
{
	USART_InitTypeDef usart;
	GPIO_InitTypeDef  gpio;
	NVIC_InitTypeDef  nvic;
	DMA_InitTypeDef   dma;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9 ,GPIO_AF_USART1);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); 
	/* USART1_RX	  GPIOA.10 */
	gpio.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
	gpio.GPIO_Mode = GPIO_Mode_AF;
	gpio.GPIO_OType = GPIO_OType_PP;
	gpio.GPIO_Speed = GPIO_Speed_100MHz;
	gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOA,&gpio);
	usart.USART_BaudRate = 115200;
	usart.USART_WordLength = USART_WordLength_8b;
	usart.USART_StopBits = USART_StopBits_1;
	usart.USART_Parity = USART_Parity_No;
	usart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_Init(USART1,&usart);
	USART_Cmd(USART1,ENABLE);
	{ /* receive dma */
		USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
		DMA_DeInit(DMA2_Stream2);
		dma.DMA_Channel= DMA_Channel_4;
		dma.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR);
		dma.DMA_Memory0BaseAddr = (uint32_t)ReceiveFromUT_Buffer;
		dma.DMA_DIR = DMA_DIR_PeripheralToMemory;
		dma.DMA_BufferSize = USART1_UT_DMA_receive_buffersize;
		dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
		dma.DMA_MemoryInc = DMA_MemoryInc_Enable;
		dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
		dma.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
		dma.DMA_Mode = DMA_Mode_Circular;
		dma.DMA_Priority = DMA_Priority_VeryHigh;
		dma.DMA_FIFOMode = DMA_FIFOMode_Disable;
		dma.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
		dma.DMA_MemoryBurst = DMA_MemoryBurst_Single;
		dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
		DMA_Init(DMA2_Stream2,&dma);
		nvic.NVIC_IRQChannel = DMA2_Stream2_IRQn;
		nvic.NVIC_IRQChannelPreemptionPriority = 1;
		nvic.NVIC_IRQChannelSubPriority = 1;
		nvic.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init(&nvic);
		DMA_ITConfig(DMA2_Stream2,DMA_IT_TC,ENABLE);
		DMA_Cmd(DMA2_Stream2,ENABLE);
	}
}
中断部分:发送中断
/* USART3 DMA send interrupt */
void DMA1_Channel2_IRQHandler(void)
{
	if(DMA_GetITStatus(DMA1_IT_TC2))
	{
		DMA_ClearFlag(DMA1_IT_TC2);
		DMA_ClearITPendingBit(DMA1_IT_TC2);
//		DMA_Cmd(DMA1_Channel2,DISABLE);
//		DMA_SetCurrDataCounter(DMA1_Channel2,USART3_DMA_send_buffersize);
//		DMA_Cmd(DMA1_Channel2, ENABLE);
	}
}
中断部分:接收中断
/* USART1 dma receive for ut */
void DMA2_Stream2_IRQHandler(void)
{
	uint8_t i = 0;
	if(DMA_GetFlagStatus(DMA2_Stream2,DMA_IT_TCIF2) == SET)
	{
		/* 在前半部分查找帧头并校验对应位置是否为帧尾 */
		for(i=0;i<(USART1_UT_DMA_receive_buffersize/2);i++)
		{
			if((ReceiveFromUT_Buffer[i] == 0x05)&&(ReceiveFromUT_Buffer[i+USART1_UT_DMA_receive_buffersize-1] == 0x06))
			{
				/* 拷贝有效数据段到待解析数组 */
				memcpy(ReceiveFromUT_Data,&ReceiveFromUT_Buffer[i],USART1_UT_DMA_receive_buffersize/2);
				/* 数据解析 */
				UTReceive();
			}
		}
		/* 没有有效数据 */
		if(i >= USART1_UT_DMA_receive_buffersize/2)
		{
			/* 重置DMA */
			DMA_Cmd(DMA2_Stream2,DISABLE);
			DMA_SetCurrDataCounter(DMA2_Stream2,USART1_UT_DMA_receive_buffersize);
			DMA_Cmd(DMA2_Stream2,ENABLE);
		}
		DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2);
		DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2);
	}
}
——cloudos
——2020/4/17
STM32串口DMA接收数据错位——暴力解决方法的更多相关文章
- STM32之串口DMA接收不定长数据
		STM32之串口DMA接收不定长数据 引言 在使用stm32或者其他单片机的时候,会经常使用到串口通讯,那么如何有效地接收数据呢?假如这段数据是不定长的有如何高效接收呢? 同学A:数据来了就会进入串口 ... 
- STM32 串口DMA方式接收(转)
		STM32 是一款基于ARM Cortex-M3内核的32位MCU,主频最高可达72M.最近因为要在车机上集成TPMS功能, 便开始着手STM32的开发工作,STM32F10x系列共有5个串口(USA ... 
- STM32输入捕获模式设置并用DMA接收数据
		参考: STM32的PWM输入模式设置并用DMA接收数据 Input capture mode The input stage samples the corresponding TIx input ... 
- STM32的PWM输入模式设置并用DMA接收数据
		参考 :STM32输入捕获模式设置并用DMA接收数据 PWM input mode This mode is a particular case of input capture mode. The ... 
- STM32库函数void USART_SendData的缺陷和解决方法
		void USART_SendData()函数在快速发送时存在问题 有丢数据的可能 转自https://blog.csdn.net/qq_27114397/article/details/506015 ... 
- PHP file_get_contents函数读取远程数据超时的解决方法
		PHP file_get_contents函数读取远程数据超时的解决方法 投稿:junjie 字体:[增加 减小] 类型:转载 这篇文章主要介绍了PHP file_get_contents函数读取 ... 
- [转]mysql导入导出数据中文乱码解决方法小结
		本文章总结了mysql导入导出数据中文乱码解决方法,出现中文乱码一般情况是导入导入时编码的设置问题,我们只要把编码调整一致即可解决此方法,下面是搜索到的一些方法总结,方便需要的朋友. linux系统中 ... 
- Android - "已安装了存在签名冲突的同名数据包",解决方法!
		错误提示:已安装了存在签名冲突的同名数据包. 解决方法:打开Android Studio,打开logcat,用usb线连接你出错的手机,识别出手机之后,在你的项目后面,点击“run”按钮,随后AS会提 ... 
- Qt串口通信接收数据不完整的解决方法
		在使用串口接收数据时,当数据量大的时候会出现数据接收不完整的情况.因为串口数据获取函数readAll()由readyRead()信号触发,但readyRead()信号在串口读到起始标志时立即发送,并不 ... 
随机推荐
- ES[7.6.x]学习笔记(六)分析器
			在前面的章节中,我们给大家介绍了索引中的映射类型,也就是每一个字段都有一个类型,比如:long,text,date等.这和我们的数据库非常的相似,那么它的不同之处是什么呢?对了,就是全文索引,在ES当 ... 
- Alink漫谈(二) : 从源码看机器学习平台Alink设计和架构
			Alink漫谈(二) : 从源码看机器学习平台Alink设计和架构 目录 Alink漫谈(二) : 从源码看机器学习平台Alink设计和架构 0x00 摘要 0x01 Alink设计原则 0x02 A ... 
- 带你看看Java的锁(一)-ReentrantLock
			前言 AQS一共花了5篇文章,对里面实现的核心源码都做了注解 也和大家详细描述了下,后面的几篇文字我将和大家聊聊一下AQS的实际使用,主要会聊几张锁,第一篇我会和大家聊下ReentrantLock 重 ... 
- [hdu5164]ac自动机
			中文题目:http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=563&pid=1003 首先贴一下bc的题解 ... 
- Linux学习第二道坎——系统目录结构及其作用
			如果说Linux学习的第一道坎是系统安装及对磁盘分区的理解,那么第二道坎就应该是对Linux系统目录结构及其作用的掌握了(这里主要指根目录 / 下的一级目录)! 随着Linux的不断发展,Linux的 ... 
- HTTP Status完整枚举
			HTTP Status完整枚举 public enum HttpStatus { // 1xx Informational 1xx信息类的 继续 CONTINUE(100, "C ... 
- 2018-06-19 js DOM对象
			DOM对象: Doucument Object Model即文档对象 DOM对象的操作: 1.找元素 返回元素对象: var obj=document.getElementById();//通过Id查 ... 
- 微服务框架 ketchup 介绍
			1.背景 在ketchup诞生之前.期间也是用surging开发了两个项目.奈何surging没有文档,升级之后,只能从头在读一遍源码,了解新功能,会消耗大量的时间.商业化也使一些 想学习微服务的人望 ... 
- pytest——pycharm中右击运行(run)没有问题,在terminal中运行pytest报错:E  ModuleNotFoundError: No module named
			参考了这个解决办法:https://blog.csdn.net/qq_36829091/article/details/82180866 我的是Windows,linux的和Windows的解决办法有 ... 
- nodejs上使用sql
			1.首先本地要安装mysql, https://www.mysql.com/downloads/. 2.在node中连接mysql,要安装mysql驱动,也就是npm安装mysql模块:npm i m ... 
