STM32F051stm32串口发送数据DMA方式发送中的几点注意

没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!STM32 USART 串口 DMA 接收和发送的源码详解!_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
赠送免券下载特权
10W篇文档免费专享
部分付费文档8折起
每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
STM32 USART 串口 DMA 接收和发送的源码详解!
&&STM32 USART 串口 DMA 接收和发送的源码详解!
阅读已结束,下载本文需要
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
加入VIP
还剩7页未读,
定制HR最喜欢的简历
你可能喜欢查看: 13506|回复: 104
STM32使用串口1配合DMA接收不定长数据,大大减轻CPU载荷。
主题帖子精华
金牌会员, 积分 1431, 距离下一级还需 1569 积分
在线时间169 小时
&&&&&&&&最近经常看见坛友在论坛上问串口接收的问题,我之前刚好由于项目需要用到PLC的PPI协议,需要不停地利用串口接收数据,一开始的时候采用单字节中断的方式接收判断。但是用来做通信的时候需要不停的产生串口接收中断,会严重影响主程序的运行。后来采用DMA接收的方式,但是一般情况下配置的DMA都是接定长的串口数据,对于未知长度的串口数据接收并不适用。后来在网上发现了一种方法可以利用串口的空闲中断+DMA接收的方法完美解决此类问题,特别适用于不需要每个就收字节都判断的串口数据接收,下面说一下事实现思路和程序。
实现思路:采用STM32F103的串口1,并配置成空闲中断模式且使能DMA接收,并同时设置接收缓冲区和初始化DMA。那么初始化完成之后,当外部给单片机发送数据的时候,假设这帧数据长度是100个字节,那么在单片机接收到一个字节的时候并不会产生串口中断,而是DMA在后台把数据默默地搬运到你指定的缓冲区里面。当整帧数据发送完毕之后串口才会产生一次中断,此时可以利用DMA_GetCurrDataCounter();函数计算出本次的数据接受长度,从而进行数据处理。
应用对象:适用于各种串口相关的通信协议,如:MODBUS,PPI ;还有类似于GPS数据接收解析,串口WIFI的数据接收等,都是很好的应用对象。
关键代码分析:
#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "sys.h"&
#define DMA_Rec_Len 200 & & &//定义一个长度为200个字节的数据缓冲区。(建议定义的长度比你可能接收到的最长单帧数据长度长!)
void uart_init(u32 bound);
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx);
//初始化IO 串口1&
//bound:波特率
void uart_init(u32 bound)
& & //GPIO端口设置
& & GPIO_InitTypeDef GPIO_InitS
& & USART_InitTypeDef USART_InitS
& & NVIC_InitTypeDef NVIC_InitS
&&&&DMA_InitTypeDef DMA_InitS
& &RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
& &RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输
& &RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2时钟
&USART_DeInit(USART1); &//复位串口1
& &//USART1_TX & PA.9
& & GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
& & GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
& & GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
& & GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9
& & //USART1_RX
& & GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
& & GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
& & GPIO_Init(GPIOA, &GPIO_InitStructure); &//初始化PA10
& & //Usart1 NVIC 配置
& & NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
& & NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
& & NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
//子优先级3
& &&NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//IRQ通道使能
& & NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
& &//USART 初始化设置
& USART_InitStructure.USART_BaudRate =//一般设置为9600;
& USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
& USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
& USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
& USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_N//无硬件数据流控制
& USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
& & USART_Init(USART1, &USART_InitStructure); //初始化串口
& & USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启空闲中断
& & USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); & //使能串口1 DMA接收
& & USART_Cmd(USART1, ENABLE); & & & & & & & & & &//使能串口&
& & //相应的DMA配置
&&DMA_DeInit(DMA1_Channel5); & //将DMA的通道5寄存器重设为缺省值 &串口1对应的是DMA通道5
& DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1-&DR; &//DMA外设ADC基地址
& DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DMA_Rece_B &//DMA内存基地址
& DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; &//数据传输方向,从外设读取发送到内存
& DMA_InitStructure.DMA_BufferSize = DMA_Rec_L &//DMA通道的DMA缓存的大小
& DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_D &//外设地址寄存器不变
& DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_E &//内存地址寄存器递增
& DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_B &//数据宽度为8位
&&DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_B //数据宽度为8位
& DMA_InitStructure.DMA_Mode = DMA_Mode_N &//工作在正常缓存模式
& DMA_InitStructure.DMA_Priority = DMA_Priority_M //DMA通道 x拥有中优先级&
& DMA_InitStructure.DMA_M2M = DMA_M2M_D &//DMA通道x没有设置为内存到内存传输
& DMA_Init(DMA1_Channel5, &DMA_InitStructure); &//根据DMA_InitStruct中指定的参数初始化DMA的通道
& & DMA_Cmd(DMA1_Channel5, ENABLE); &//正式驱动DMA传输
//串口中断函数
void USART1_IRQHandler(void) & & & & & & & & //串口1中断服务程序
& & &if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) &//接收中断(接收到的数据必须是0x0d 0x0a结尾)
& & & & & USART_ReceiveData(USART1);//读取数据 注意:这句必须要,否则不能够清除中断标志位。
& & & & & Usart1_Rec_Cnt = DMA_Rec_Len-DMA_GetCurrDataCounter(DMA1_Channel5); //算出接本帧数据长度
& & & & &//***********帧数据处理函数************//
& & & & & printf ("The lenght:%d\r\n",Usart1_Rec_Cnt);
& & & & & printf ("The data:\r\n");
& & & & & Usart1_Send(DMA_Rece_Buf,Usart1_Rec_Cnt);
& & & & &printf ("\r\nOver! \r\n");
& & & &&//*************************************//
& & & & &USART_ClearITPendingBit(USART1, USART_IT_IDLE); & & & & //清除中断标志
&&&&& & &MYDMA_Enable(DMA1_Channel5); & & & & & & & & & //恢复DMA指针,等待下一次的接收
ad76f43c801c_953.png (0 Bytes, 下载次数: 0)
22:54 上传
完整工程工程在附件里面。
15:14 上传
点击文件名下载附件
306.21 KB, 下载次数: 4966
主题帖子精华
初级会员, 积分 119, 距离下一级还需 81 积分
在线时间8 小时
这个真心有用。谢谢啦。
耐心做事,好好做人。O(∩_∩)O!
主题帖子精华
中级会员, 积分 242, 距离下一级还需 258 积分
在线时间20 小时
nice!学习了
主题帖子精华
在线时间771 小时
赞一个!有没有试过超出缓冲区是什么效果
机器生汇编,汇编生B,B生C,C生万物.... 经过长期对C语言的研究,目前只有两个方面不懂:这也不懂,那也不懂
https://github.com/ianhom
主题帖子精华
金牌会员, 积分 1431, 距离下一级还需 1569 积分
在线时间169 小时
回复【3楼】ianhom:
---------------------------------
试过,循环覆盖了。要是接收的数据实在是很长,可以也把DMA的接收完成中断打开,先把缓冲区的数据读出来处理,或者更换缓冲区。
主题帖子精华
金牌会员, 积分 1981, 距离下一级还需 1019 积分
在线时间283 小时
谢谢分享!!
活着才是王道!健康是一切的前提!
主题帖子精华
高级会员, 积分 514, 距离下一级还需 486 积分
在线时间12 小时
很不错的样子~
主题帖子精华
初级会员, 积分 131, 距离下一级还需 69 积分
在线时间9 小时
nice,值得学习
主题帖子精华
金牌会员, 积分 2226, 距离下一级还需 774 积分
在线时间393 小时
高手,我都没想过用空闲中断
主题帖子精华
初级会员, 积分 77, 距离下一级还需 123 积分
在线时间8 小时
主题帖子精华
在线时间585 小时
这么好的东西居然现在才发现............顶
我的博客:http://blog.csdn.net/itdo_just
主题帖子精华
在线时间585 小时
空闲中断估计很少人用过,科普一下吧(网上资料显示):
总线空闲中断是在检测到在接收数据后,数据总线上一个字节的时间内,没有再接到数据后发生。也就是RXNE位被置位之后,才开始检测,只被置位一次,除非再次检测到RXNE位被置位,然后才开始检测下一次的总线空闲。
我的博客:http://blog.csdn.net/itdo_just
主题帖子精华
中级会员, 积分 293, 距离下一级还需 207 积分
在线时间24 小时
好东西,赞!
主题帖子精华
金牌会员, 积分 1431, 距离下一级还需 1569 积分
在线时间169 小时
空闲中断估计很少人用过,科普一下吧(网上资料显示):
总线空闲中断是在检测到在接收数据后,数据总线上一 ...
谢谢普及。
主题帖子精华
初级会员, 积分 138, 距离下一级还需 62 积分
在线时间35 小时
主题帖子精华
初级会员, 积分 195, 距离下一级还需 5 积分
在线时间24 小时
怎么判断包结束?
主题帖子精华
初级会员, 积分 185, 距离下一级还需 15 积分
在线时间42 小时
空闲模式认为一个字符的时间为空闲中断modbus协议认为3.5倍的字符时间为接受完成。请问空闲中断的时间是不是和配置的?
主题帖子精华
初级会员, 积分 185, 距离下一级还需 15 积分
在线时间42 小时
如果把发送也改成DMA模式那就最好了。
主题帖子精华
金牌会员, 积分 1431, 距离下一级还需 1569 积分
在线时间169 小时
如果把发送也改成DMA模式那就最好了。
这个有的,后来没有吧代码上传上来,配置方式一样的
主题帖子精华
金牌会员, 积分 1519, 距离下一级还需 1481 积分
在线时间259 小时
收藏了,很有用,目前项目中正好需要,谢谢啦。。。。。
主题帖子精华
中级会员, 积分 452, 距离下一级还需 48 积分
在线时间49 小时
发生 接收全都是dma&&串口空闲有个问题就是只有一个字符的时间&&这样的话发送如果不进行延时就可能导致前后两帧无法定界
主题帖子精华
金牌会员, 积分 1198, 距离下一级还需 1802 积分
在线时间241 小时
GOOD,好样的
主题帖子精华
金牌会员, 积分 1574, 距离下一级还需 1426 积分
在线时间399 小时
主题帖子精华
初级会员, 积分 199, 距离下一级还需 1 积分
在线时间21 小时
学习了,感谢楼主。
主题帖子精华
高级会员, 积分 870, 距离下一级还需 130 积分
在线时间151 小时
不错,很好的总结
主题帖子精华
金牌会员, 积分 2226, 距离下一级还需 774 积分
在线时间393 小时
我怎么进不了空闲中断,必须是DMA方式才可以用空闲中断的吗?
主题帖子精华
金牌会员, 积分 1431, 距离下一级还需 1569 积分
在线时间169 小时
我怎么进不了空闲中断,必须是DMA方式才可以用空闲中断的吗?
不是的,跟接收中断没什么区别的
主题帖子精华
金牌会员, 积分 2226, 距离下一级还需 774 积分
在线时间393 小时
我在配置串口时使能空闲中断和接收中断,然后进不了空闲中断
主题帖子精华
金钱127932
在线时间1121 小时
主题帖子精华
金牌会员, 积分 2226, 距离下一级还需 774 积分
在线时间393 小时
用了接收中断貌似用不了空闲中断了
主题帖子精华
中级会员, 积分 293, 距离下一级还需 207 积分
在线时间54 小时
支持,最近也普及了串口不等长的知识,COOL
主题帖子精华
初级会员, 积分 183, 距离下一级还需 17 积分
在线时间32 小时
主题帖子精华
金牌会员, 积分 1431, 距离下一级还需 1569 积分
在线时间169 小时
哎呀,原子哥给cool了啊,赞。
主题帖子精华
金牌会员, 积分 1431, 距离下一级还需 1569 积分
在线时间169 小时
我在配置串口时使能空闲中断和接收中断,然后进不了空闲中断
你就仅仅配置成空闲中断试试能不能进入中断。最后加上DMA
主题帖子精华
金牌会员, 积分 2226, 距离下一级还需 774 积分
在线时间393 小时
试验了两个晚上的结果:1,开启了串口接收完成中断则无法进入空闲中断,2,在DMA中设立DMA接收完成中断,并且在中断中关闭DMA接收通道,不然数据帧长度超过DMA接收缓冲区设定长度会发现虽然进入了中断但是缓冲区的数据还是在写着。3.在空闲中断中重置DMA指针。这样最可靠,不然数据溢出后会影响通信
主题帖子精华
金牌会员, 积分 1431, 距离下一级还需 1569 积分
在线时间169 小时
试验了两个晚上的结果:1,开启了串口接收完成中断则无法进入空闲中断,2,在DMA中设立DMA接收完成中断,并 ...
嗯嗯,调试出来了就好
主题帖子精华
高级会员, 积分 597, 距离下一级还需 403 积分
在线时间53 小时
好帖!谢谢分享!
主题帖子精华
新手入门, 积分 6, 距离下一级还需 14 积分
在线时间0 小时
顶顶顶顶顶顶顶顶
主题帖子精华
初级会员, 积分 156, 距离下一级还需 44 积分
在线时间16 小时
认真的看完了,还是有所收获,之前这个也弄得挺久的,
主题帖子精华
初级会员, 积分 68, 距离下一级还需 132 积分
在线时间36 小时
这个是stm32f107?
主题帖子精华
金牌会员, 积分 1431, 距离下一级还需 1569 积分
在线时间169 小时
这个是stm32f107?
tranits 该用户已被删除
提示: 作者被禁止或删除 内容自动屏蔽
主题帖子精华
初级会员, 积分 193, 距离下一级还需 7 积分
在线时间44 小时
好文,严重学习。
逆水行舟不进则退
主题帖子精华
金牌会员, 积分 1553, 距离下一级还需 1447 积分
在线时间252 小时
你好,请问 这个有没有 使用 最新的库,cube / hal 的库制作的 ??
主题帖子精华
金牌会员, 积分 1463, 距离下一级还需 1537 积分
在线时间181 小时
好样的!后面试下。
主题帖子精华
金牌会员, 积分 2846, 距离下一级还需 154 积分
在线时间621 小时
很好,这样就比较容易实现非阻塞传输模式了,真好
主题帖子精华
新手入门, 积分 21, 距离下一级还需 -1 积分
在线时间2 小时
能不能不用IDIE+DMA方式接收数据,而用DMA中断接收数据。
主题帖子精华
初级会员, 积分 170, 距离下一级还需 30 积分
在线时间39 小时
coolcoolcool
主题帖子精华
中级会员, 积分 318, 距离下一级还需 182 积分
在线时间37 小时
非常好的学习资料!享受中。。多谢楼主的无私奉献
主题帖子精华
中级会员, 积分 244, 距离下一级还需 256 积分
在线时间44 小时
给楼主,顶一个,多谢了。
Powered by没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!}

我要回帖

更多关于 c 串口发送数据 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信