------------恢复内容开始------------
前言
在上一节只是稍微说了下数据缓存
https://www.cnblogs.com/yangfengwu/p/11769059.html
这节为了可以让大家直接应用起来,我封装了下.
咱们平时发送数据的时候最希望的是可以有个缓存,每次把要发送的数据存到缓存里面
需要发送的时候咱就去缓存里面去取
而且咱希望咱的缓存可以存储多条数据
发送的时候按照先进先出的原则把每条数据提取出来发出去
前要
一,作为一个资深的C语言开发者,应该知道的东西
假设是一个32位的单片机,定义了一个32位的变量int a;
假设变量a的地址是:0x20000000-0x20000003
在32位的单片机中,int型占四字节
然后说一下 memcpy
假设 a = 256
试问调用以下程序,可不可以把a的值拷贝到b里面??
memcpy(&b,&a,1)
首先大家需要明确,memcpy默认拷贝一个字节
所以,并不能把a的值复制给b
如果想把a的值复制给b
memcpy(&b,&a,4)
缓存源码使用
一,注意,这一节是对上一节的封装,请先看上一节
这节增加了 BufferManage 文件
二,定义一个管理变量
buff_manage_struct buff_manage_struct1;
三,定义两个数组
一个用于交给环形队列用于缓存数据:u8 buff[1024];
请必须定义成u8 / uint8_t /char 等等1字节类型的
请必须定义成u8 / uint8_t /char 等等1字节类型的
请必须定义成u8 / uint8_t / char 等等1字节类型的
数组大小是1024字节,最大缓存1024字节数据
另一个交给环形队列用于记录每次缓存数据的个数:u32 Managebuff[10];
请必须定义为 u32 / uint32_t / int32_t 等等4字节类型的
请必须定义为 u32 / uint32_t / int32_t 等等4字节类型的
请必须定义为 u32 / uint32_t / int32_t 等等4字节类型的
数组个数是10个,说明最多可以管理10条数据
u32 类型,说明记录的每条数据个数最大长度是 2^32 个
四, 调用 BufferManageCreate函数
BufferManageCreate(&buff_manage_struct1, buff, 1024, Managebuff, 10*4);
注:
&buff_manage_struct1 :数据缓存管理变量
buff : 传入u8 buff[1024] 数组的首地址
1024 : u8 buff[1024] 数组的长度
Managebuff : 传入u32 Managebuff[10] 数组的首地址
10*4 :u32 Managebuff[10] 的数组长度*空间所占字节数
注:请大家一致定义成 u32类型,最后的参数统一填写: 数组长度*4
本人封装的BufferManage程序默认内部按照u32类型处理
五,定义一个数组,用于提取缓存的数据
注意:提取先前存储的一条数据,然后缓存到一个数组里面:u8 SendBuff[1024];
最后操作这个数组
测试1
说明:我定义了一些通用变量,用户可随意使用
二,每隔3S插入17字节的数据
主循环只要判断插入了数据就取出来用串口发送出去
插入数据
BufferManageWrite(&buff_manage_struct1,temp,17);
提取数据
buff_manage_struct1.SendLen = BufferManageRead(&buff_manage_struct1,SendBuff);
三,测试
#include "include.h" #include "BufferManage.h" buff_manage_struct buff_manage_struct1; u8 buff[1024];//»º´æÊý¾ÝµÄÊý×é u32 Managebuff[10];//¼Ç¼ÿ´Î»º´æ¶àÉÙÊý¾ÝµÄÊý×é u8 SendBuff[1024];//ÌáÈ¡Ò»ÌõÊý¾ÝÖ®ºó´æ´¢µÄÊý×é char temp[17]="111111111111111 "; int main(void) { NVIC_Configuration(); uart_init(115200); //´®¿Ú³õʼ»¯Îª115200 GpioInit(); DelayInit(); BufferManageCreate(&buff_manage_struct1, buff, 1024, Managebuff, 10*4); while(1) { if(SysTickCntMs>=3000) { BufferManageWrite(&buff_manage_struct1,temp,17);//²åÈëÊý¾Ý SysTickCntMs=0; } buff_manage_struct1.SendLen = BufferManageRead(&buff_manage_struct1,SendBuff);//ÌáÈ¡Êý¾Ýµ½SendBuffÊý×é if(buff_manage_struct1.SendLen>0)//ÓÐÊý¾ÝÐèÒª·¢ËÍ { UsartOutStr(SendBuff,buff_manage_struct1.SendLen); } // if(Usart1ReadFlage)//´®¿Ú½ÓÊÕÍêÒ»ÌõÍêÕûµÄÊý¾Ý // { // Usart1ReadFlage=0; // memset(Usart1ReadBuff,NULL, sizeof(Usart1ReadBuff));//ÇåÁã // } } }
测试2
每隔3S插入两份数据:用来模拟不定期插入多份数据
注:提取数据是一条一条的提取
咱可以加点延时让每条数据之间加点延时
注:延时1000ms是控制每隔1000ms从里面提取一条数据
实际应用中直接加延时其实是不可取的.但是咱们又想让每条数据
之间有延时,否则就会当做一条数据
以上测试说明
其实简而言之
在需要发送数据的地方
只需要调用
BufferManageWrite(&buff_manage_struct1,temp,17);//插入数据
在需要提取发送的地方调用一下函数
Len = BufferManageRead(&buff_manage_struct1,SendBuff);//提取数据到SendBuff数组
if(Len>0)
{
操作发送的数据:SendBuff 数据长度:Len
}
这样便会一条数据一条数据的提取出来,然后最终如何操作如何应用自行发挥.
扩展:使用串口中断发送缓存的数据
一,首先先说明处理思路
如果缓存区没有数据,则每隔1ms查询一次
如果查询到了有数据,则提取出来,然后交由中断处理
然后查询间隔变为10ms (该间隔可调节)
10ms便是发送每一条数据之间的时间间隔
二,1Ms定时器增加以下程序
if(Usart1ManageSendDatLen == 0)//没有在发送数据 { Usart1ManageSendDelayCnt++; if(Usart1ManageSendDelayCnt>=1000)//延迟10Ms { Usart1ManageSendDelayCnt = 0; if(rbCanRead(&Uart1rbManage)>0)//是不是有需要发送的数据 { //取出这次要发送的数据个数 rbRead(&Uart1rbManage, &Usart1ManageSendDatLen, 1); USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//打开发送中断 } else { //没有数据发送的时候1Ms判断一次,延迟1Ms Usart1ManageSendDelayCnt=10; } } }
三,串口中断里面
if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET) { if(buff_manage_struct1.SendLen>0)//发送的数据个数大于0 { USART_SendData(USART1, Usart1SendBuff[buff_manage_struct1.Count]);//发送 buff_manage_struct1.Count++; buff_manage_struct1.SendLen -- ;//发送的数据个数减一 } else//发送字节结束 { USART_ClearITPendingBit(USART1,USART_IT_TXE); USART_ITConfig(USART1, USART_IT_TXE, DISABLE); USART_ITConfig(USART1, USART_IT_TC, ENABLE); } } //发送完成 if (USART_GetITStatus(USART1, USART_IT_TC) != RESET) { USART_ClearITPendingBit(USART1,USART_IT_TC); USART_ITConfig(USART1, USART_IT_TC, DISABLE); }
四:测试
主函数还是每隔3S插入两条数据
扩展:使用DMA串口发送缓存的数据
一,我先留给大家去完善,我给大家一些提示
简而言之:如果有数据需要发送,就设置下数据地址和数据个数,然后启动DMA
详细方案1:
每次存入数据以后,判断下DMA是否传输完成,如果传输完成,则重新赋值以后启动
在DMA发送完成中断里面判断是否有数据需要发送
如果有,则重新赋值以后启动
详细方案2:
上述方案有个问题在于每条数据之间没有了固定的时间间隔
有可能造成粘包.
咱还是利用定时器,把以下红框改为:
重新赋值DMA以后启动DMA.
别忘了在DMA发送完成中断里面: buff_manage_struct1.SendLen = 0;
提醒:
大家使用缓存的时候需要多考虑一件事情:中断打断
为避免存和取之间由于中断打断而造成以外情况,设置了中断保护