Discuz! Board

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2729|回复: 0

10-数据缓存封装-内存管理实现

[复制链接]

56

主题

56

帖子

224

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
224
发表于 2020-9-21 09:53:21 | 显示全部楼层 |阅读模式



前言
  上一节使用的是环形队列实现的数据缓存
  这节使用内存管理实现
  内存管理使用的是 μC/OS-II 里面的内存管理程序

使用说明
  一,内存管理意味着有许多的内存块
    内存块的长度假设定义的足够大,可以放入每条数据
  二,定义一个数组,作为内存分区
    data_type_t CommTxPart[BlocksNumber][BlocksSize];
    所有的封装到了 MemManage文件里面,如果用户想了解实质
    请自行学习,我只说明怎么应用!
     819239-20200130001538744-1238890482.png




    注意:

    data_type_t : 代表内存 存储的数据类型 ,请定义成这种类型

      默认按照char型数据存储,请自行修改
    BlocksNumber : 数组的行数(内存块数量)
    BlocksSize : 数组的列数(每个内存块长度)
     819239-20200130002037897-1539766631.png

  提醒:
  提醒:
  提醒:
  BlocksNumber  :也代表最大管理的数据的条数,当前是3
  BlocksSize : 代表着每条数据最大存储的数据个数,不得超过
  此个数,否则数组溢出,造成程序崩溃
  实际上就是用多维的数组存储数据
  数组的行数代表最大储存的数据条数
  数组的列用于存储每一条数据,一条数据最大500个
   819239-20200130003433172-1478234612.png


  三,定义一个管理变量

    mem_manage_struct mem_manage_struct1;

     819239-20200130002358069-878288994.png




  四,创建

     819239-20200130002537570-908576975.png


     819239-20200130002629432-306124066.png




  五,插入数据

    MemManageWrite(&mem_manage_struct1,temp,17,&err);

   819239-20200130005025774-129329159.png


   819239-20200130005102495-1763501541.png




  五,如果缓存区有数据,则取出来打印

   819239-20200130005408819-943572910.png
  
   819239-20200130005751666-432941432.png


  六:整体程序

    
#include "include.h"
#include "MemManage.h"




data_type_t CommTxPart[BlocksNumber][BlocksSize];
mem_manage_struct mem_manage_struct1;
INT8U err;
char temp[17]="111111111111111\r\n";
data_type_t *Data;
uint32_t DataLen;
int main(void)
{
  NVIC_Configuration();
    uart_init(115200);     //串口初始化为115200
    GpioInit();
    DelayInit();
    MemManageCreate(&mem_manage_struct1,CommTxPart,BlocksNumber,BlocksSize,&err);
    if(err!=0){printf("MemManageCreate err=%d\r\n",err);}
    while(1)
    {
        if(SysTickCntMs>=3000)
        {
            MemManageWrite(&mem_manage_struct1,temp,17,&err);
            SysTickCntMs=0;
        }
        Data = MemManageRead(&mem_manage_struct1,&DataLen);
        if(DataLen>0)
        {
            UsartOutStr(Data,DataLen);
            MemManageFree(&mem_manage_struct1);
        }
        
        
//    if(Usart1ReadFlage)//串口接收到数据
//        {
//          Usart1ReadFlage=0;
//        }
    }
}







运行测试
  一直判断是否缓存了数据,如果有缓存的数据,则打印缓存的数据
  因为是每隔3S插入一次数据,所以每隔3S打印一次
   819239-20200130010026166-116101687.png





测试2
每隔3S插入两份数据:用来模拟不定期插入多份数据
为看出是一条数据一条数据取出来的,加了500ms延时
   819239-20200130011228198-1128037779.png




   819239-20200130011327135-1961605175.png



扩展:使用串口中断发送缓存的数据
  一,首先先说明处理思路
    如果缓存区没有数据,则每隔1ms查询一次
    如果查询到了有数据,则提取出来,然后交由中断处理
    然后查询间隔变为10ms (该间隔可调节)
    10ms便是发送每一条数据之间的时间间隔
  二,1Ms定时器增加以下程序
     819239-20200131234747424-1212820703.png



if(mem_manage_struct1.SendLen == 0)//没有数据正在发送
    {
        mem_manage_struct1.Cnt++;
        if(mem_manage_struct1.Cnt>=10)//10Ms
        {
            mem_manage_struct1.Cnt = 0;
   
            //查询是不是有数据需要发送
            mem_manage_struct1.DataPtr = MemManageRead(&mem_manage_struct1,&(mem_manage_struct1.SendLen));
            
            if(mem_manage_struct1.SendLen>0)//有数据需要发送
            {
                USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//使能串口发送
            }
            else//没有数据需要发送的时候降低检测时间
            {
                mem_manage_struct1.Cnt=10;
            }
        }
    }

  三,串口中断里面
     819239-20200131234902733-1122695516.png



if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
    {        
        if(mem_manage_struct1.SendLen>0)//发送的数据个数大于0
        {
            USART_SendData(USART1, *mem_manage_struct1.DataPtr);//发送
            mem_manage_struct1.DataPtr++;
            mem_manage_struct1.SendLen -- ;//发送的数据个数减一
        }
        else//发送字节结束
        {
            mem_manage_struct1.SendLen = 0;
            MemManageFree(&mem_manage_struct1);
            
            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插入两条数据
   819239-20200131235041942-1312999635.png


   819239-20200131235123967-1933158840.png







扩展:使用DMA串口发送缓存的数据
  一,我先留给大家去完善,我给大家一些提示
  简而言之:如果有数据需要发送,就设置下数据地址和数据个数,然后启动DMA
  详细方案1:
  每次存入数据以后,判断下DMA是否传输完成,如果传输完成,则重新赋值以后启动
  在DMA发送完成中断里面判断是否有数据需要发送
  如果有,则重新赋值以后启动
  详细方案2:
  上述方案有个问题在于每条数据之间没有了固定的时间间隔
  有可能造成粘包.
  咱还是利用定时器,把以下红框改为:
  重新赋值DMA以后启动DMA.
  别忘了在DMA发送完成中断里面:
  mem_manage_struct1.SendLen = 0;
  MemManageFree(&mem_manage_struct1);

   819239-20200201003002136-123416222.png

copycode.gif
回复

使用道具 举报

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

本版积分规则

Archiver|手机版|小黑屋|DiscuzX

GMT+8, 2020-10-31 18:47 , Processed in 0.088823 second(s), 21 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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