OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 13044|回复: 14

和大家分享一下利用乒乓缓冲法来管理串口接收数据

[复制链接]

4

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
118
金钱
118
注册时间
2013-10-27
在线时间
23 小时
发表于 2013-11-21 09:21:01 | 显示全部楼层 |阅读模式
一.乒乓缓冲原理 
       一般情况下,串口数据 DMA 传输到 BUF1(内存上的一片连续的缓冲区)的过程中,是不
建议对 BUF1 进行操作的。但由于串口数据是一个连续传输的过程,比如接收 GPS 数据,不
能等待 BUF1 满了才处理数据,你 CPU 在处理数据的同时,串口源源不断接收数据,此时会
造成串口数据丢失,而乒乓缓冲就完美地解决了这个问题。 
       具体过程是:当串口 BUF1 满了时,DMA 的目标地址迅速切换到 BUF2,此时可以处理
BUF1 的数据;当串口 BUF2 满了时,DMA 的目标地址迅速切换到 BUF1,此时可以处理 BUF2
的数据。如此一直循环下去,就像打乒乓球一样,你推我挡,故称作乒乓缓冲。
二 . DMA就不在这里班门弄斧的讲解了,分享一下程序吧。
DMA配置代码:
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                 //外设作源头 
DMA_InitStructure.DMA_BufferSize = dma_len;                               //BUF 大小 
DMA_InitStructure.DMA_PeripheralInc  =  DMA_PeripheralInc_Disable;  //外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;    //内存地址寄存器递增 
这两项的配置还是很好理解的,比如在这里我们是要将内存里边的东西发到 USART1 中去,每次发送 8 位,
那么外设地址当然不能改变,而每一次发送内容都是不一样的,而且数组在内存中的存放就是递增的,所以内存地址寄存器要递增。
下边是设置数据宽度: 
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为 8 位 
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; 
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //正常缓存模式(非连续传输) 
一些基本定义: 
#define dma_len 100    //定义串口 DMA 传输数据长度(如果串口一次接收数据没有达到 dma_len 个 byte,则不会发生 DMA 中断)  
extern u8 USART1_DMA_Buf1[dma_len]; //BUF1 
extern u8 USART1_DMA_Buf2[dma_len];     //BUF2 
typedef enum {BUF_NO1=0,BUF_NO2=1}BUF_NO; 
extern BUF_NO Free_Buf_Now; 
extern bool Buf_Ok; 

乒乓思想在这里体现: 
void DMA1_Channel5_IRQHandler(void) 
       if(DMA_GetITStatus(DMA1_IT_TC5)) 
       { 
               //DataCounter = DMA_GetCurrDataCounter(DMA1_Channel5); 
//获取剩余长度,一般都为 0,调试用 
               DMA_ClearITPendingBit(DMA1_IT_GL5);     //清除全部中断标志                   
                                                     
              //转换可操作 BUF 
              if(Free_Buf_Now==BUF_NO1) //如果 BUF1 空闲,将 DMA 接收数据赋值给 BUF1 
              {       
                     DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1; 
                     DMA_Init(DMA1_Channel5, &DMA_InitStructure); 
                     Free_Buf_Now=BUF_NO2; 
              } 
              else    //如果 BUF2 空闲,将 DMA 接收数据赋值给 BUF2 
              { 
                     DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf2; 
                     DMA_Init(DMA1_Channel5, &DMA_InitStructure); 
                     Free_Buf_Now=BUF_NO1; 
              } 
              Buf_Ok=TRUE;  
       } 

 当发现有一个缓冲接收满的时候,可以上传数据。将另外一个缓冲作为接收数据的目的地,周而复始。屡试不爽。




正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

38

主题

2061

帖子

6

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3273
金钱
3273
注册时间
2012-1-16
在线时间
37 小时
发表于 2013-11-21 09:38:00 | 显示全部楼层
回复【楼主位】liuxuefei11:
---------------------------------
学习了,谢谢分享!
站在巨人的肩膀上不断的前进。。。
回复 支持 反对

使用道具 举报

12

主题

432

帖子

0

精华

高级会员

Rank: 4

积分
729
金钱
729
注册时间
2012-6-21
在线时间
59 小时
发表于 2013-11-21 09:57:37 | 显示全部楼层
mark。
好。
呵呵。
回复 支持 反对

使用道具 举报

31

主题

270

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
450
金钱
450
注册时间
2012-5-18
在线时间
6 小时
发表于 2013-11-21 10:20:43 | 显示全部楼层
乒乓操作在FPGA数据处理中用得较多,特别是数据位较宽的时候。
谁来买我的火柴.....
回复 支持 反对

使用道具 举报

19

主题

64

帖子

0

精华

初级会员

Rank: 2

积分
160
金钱
160
注册时间
2014-5-23
在线时间
0 小时
发表于 2015-6-23 11:06:01 | 显示全部楼层
谢谢分享。。。
回复 支持 反对

使用道具 举报

8

主题

67

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
226
金钱
226
注册时间
2013-9-27
在线时间
26 小时
发表于 2015-6-23 15:46:05 | 显示全部楼层
我以前做数据采集写过类似的,不过自己琢磨的,都不知道还有这个名字
回复 支持 反对

使用道具 举报

13

主题

123

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
242
金钱
242
注册时间
2013-1-6
在线时间
20 小时
发表于 2015-6-23 17:09:10 | 显示全部楼层
好贴,感谢楼猪分享
回复 支持 反对

使用道具 举报

4

主题

38

帖子

0

精华

初级会员

Rank: 2

积分
160
金钱
160
注册时间
2014-11-28
在线时间
27 小时
发表于 2016-4-29 14:04:07 | 显示全部楼层
GOODGOODGOODGOODGOODGOODGOODGOODGOOD
回复 支持 反对

使用道具 举报

7

主题

333

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1838
金钱
1838
注册时间
2012-7-16
在线时间
504 小时
发表于 2016-4-29 14:27:44 | 显示全部楼层
非常好。
回复 支持 反对

使用道具 举报

26

主题

201

帖子

0

精华

高级会员

Rank: 4

积分
606
金钱
606
注册时间
2013-12-14
在线时间
125 小时
发表于 2016-4-29 17:37:12 | 显示全部楼层
在单片机中,开辟两个小buf,为啥不合并起来开辟一个大的buf?你两个buf永远不会同时满,那一个大的应该也不会满吧?
回复 支持 反对

使用道具 举报

9

主题

80

帖子

0

精华

初级会员

Rank: 2

积分
192
金钱
192
注册时间
2015-2-9
在线时间
51 小时
发表于 2016-4-29 21:08:23 | 显示全部楼层
哥以为多高深呢
回复 支持 反对

使用道具 举报

头像被屏蔽

88

主题

231

帖子

2

精华

高级会员

Rank: 4

积分
844
金钱
844
注册时间
2013-4-11
在线时间
40 小时
发表于 2016-4-30 08:10:34 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

7

主题

31

帖子

0

精华

初级会员

Rank: 2

积分
130
金钱
130
注册时间
2013-10-9
在线时间
21 小时
发表于 2016-6-5 01:21:55 | 显示全部楼层
lialong1989 发表于 2016-4-29 17:37
在单片机中,开辟两个小buf,为啥不合并起来开辟一个大的buf?你两个buf永远不会同时满,那一个大的应该也 ...

楼主这样做就是为了乒乓操作。
乒乓操作的作用就是切换缓存后,主循环就可以处理已满的缓存。
交替切换,交替处理。
回复 支持 反对

使用道具 举报

1

主题

42

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
317
金钱
317
注册时间
2018-4-24
在线时间
53 小时
发表于 2019-7-23 17:26:49 | 显示全部楼层
学习了 多谢卤煮分享
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
3
金钱
3
注册时间
2021-7-8
在线时间
0 小时
发表于 2021-7-8 22:46:15 | 显示全部楼层
解释的很清晰
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-23 15:54

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表