背景:两片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接收数据错位——暴力解决方法的更多相关文章

  1. STM32之串口DMA接收不定长数据

    STM32之串口DMA接收不定长数据 引言 在使用stm32或者其他单片机的时候,会经常使用到串口通讯,那么如何有效地接收数据呢?假如这段数据是不定长的有如何高效接收呢? 同学A:数据来了就会进入串口 ...

  2. STM32 串口DMA方式接收(转)

    STM32 是一款基于ARM Cortex-M3内核的32位MCU,主频最高可达72M.最近因为要在车机上集成TPMS功能, 便开始着手STM32的开发工作,STM32F10x系列共有5个串口(USA ...

  3. STM32输入捕获模式设置并用DMA接收数据

    参考: STM32的PWM输入模式设置并用DMA接收数据 Input capture mode The input stage samples the corresponding TIx input ...

  4. STM32的PWM输入模式设置并用DMA接收数据

    参考 :STM32输入捕获模式设置并用DMA接收数据 PWM input mode This mode is a particular case of input capture mode. The ...

  5. STM32库函数void USART_SendData的缺陷和解决方法

    void USART_SendData()函数在快速发送时存在问题 有丢数据的可能 转自https://blog.csdn.net/qq_27114397/article/details/506015 ...

  6. PHP file_get_contents函数读取远程数据超时的解决方法

    PHP file_get_contents函数读取远程数据超时的解决方法 投稿:junjie 字体:[增加 减小] 类型:转载   这篇文章主要介绍了PHP file_get_contents函数读取 ...

  7. [转]mysql导入导出数据中文乱码解决方法小结

    本文章总结了mysql导入导出数据中文乱码解决方法,出现中文乱码一般情况是导入导入时编码的设置问题,我们只要把编码调整一致即可解决此方法,下面是搜索到的一些方法总结,方便需要的朋友. linux系统中 ...

  8. Android - "已安装了存在签名冲突的同名数据包",解决方法!

    错误提示:已安装了存在签名冲突的同名数据包. 解决方法:打开Android Studio,打开logcat,用usb线连接你出错的手机,识别出手机之后,在你的项目后面,点击“run”按钮,随后AS会提 ...

  9. Qt串口通信接收数据不完整的解决方法

    在使用串口接收数据时,当数据量大的时候会出现数据接收不完整的情况.因为串口数据获取函数readAll()由readyRead()信号触发,但readyRead()信号在串口读到起始标志时立即发送,并不 ...

随机推荐

  1. startUML简单使用教程

    最近在startUML上画图搞得我一个头两个大,找了一些比较实用的小方法分享给大家. 类图是可视化地表现类的属性和方法,以及类与类之间的关系. 1.类 a.类 普通实体类,它有对应的属性和方法: 双击 ...

  2. Three Blocks Palindrome (easy version)[暴力-预处理]

    给定一个数组,找出最长的子序列,满足 a,a,..a,b,b,..b,a,a,..a 前面的a和后面的a都要是x个,中间的b是y个. 其中,x>=0且y>=0. \(\color{Red} ...

  3. mybatis添加信息自动生成主键

    一.使用Oracle数据库 举例:添加员工的时候自动生成主键 1.在dao接口中声明方法 2.在mapper中实现该方法 需要先在数据表中创建序列 3.测试 注意:在调用过save方法之后,emp对象 ...

  4. Excel 函数 常见错误

    excel公式出错的值. 常见错误值类型: #N/A #VALUE! #NAME? #REF! #NUM! #NULL! #N/A 找不到指定内容,比如查找根本不存在的内容,便显示该错误值 比如在使用 ...

  5. 第十章:Python高级编程-多线程、多进程和线程池编程

    第十章:Python高级编程-多线程.多进程和线程池编程 Python3高级核心技术97讲 笔记 目录 第十章:Python高级编程-多线程.多进程和线程池编程 10.1 Python中的GIL 10 ...

  6. vue+.netcore可支持业务代码扩展的开发框架 VOL.Vue 2.0版本发布

    框架介绍 这是一个基于vue.element-ui.iview..netcore3.1 可支持前端.后台动态扩展业务代码快速开发框架. 框架内置定制开发的代码生成器,生成的代码不需要复制也不需要更改, ...

  7. STM32 时钟树配置快速入门

    layout: post tags: [STM32] comments: true 文章目录 layout: post tags: [STM32] comments: true 为什么要了解时钟树? ...

  8. C:简单实现BaseCode64编码

    What is Base64? 前言 目前来看遇到过Base 16.Base 32.Base 64的编解码,这种编码格式是二进制和文本编码转化,是对称并且可逆的转化.Base 64总共有64个ASCI ...

  9. Git管理修改、撤销修改、删除文件

    什么是修改?比如你新增了一行,这就是一个修改,删除了一行,也是一个修改,更改了某些字符,也是一个修改,删了一些又加了一些,也是一个修改,甚至创建一个新文件,也算一个修改. a.管理修改 对于提交修改, ...

  10. 聊聊 TypeScript 中的类型保护

    聊聊 TypeScript 中的类型保护 在 TypeScript 中使用联合类型时,往往会碰到这种尴尬的情况: interface Bird { // 独有方法 fly(); // 共有方法 lay ...