• 一种环形数据区存取机制的实现


    一种随机起始地址循环连续取数据的的机制

    问题描述

    1) 需要开辟一片缓存区以存储 ADC 采集的数据,数据连续不间断存储,按首地址--->末地址--->首地址的存储顺序。

    2) 数据算法要对采集后的数据做处理,也是按照ADC数据的存储顺序做循环取数据的,要求每次取一包数据 (长度3120byte) 做处理,数据处理后会返回一个数值 n,该数值 n 作为下一包取数据的起始地址偏移量,且该数值n每次返回值随机,由算法得出。

    3) 从数据缓存区取出的数据必须是有效数据,即取数据时存数据已存超过 3120 个点,这一要求可通过当前存地址与当前取地址做差 >= 3120 来保证。

    解决方法

    方法一、搬移数据接续法

      使用场合:尤其适用于某个算法函数只需接收起始地址这一个参数,而进行的数据块读取,这个起始地址在外部通过搬移数据接续法计算获得

    方法二、指针描述控制法

      使用场合:设某个算法函数需要数据块读取,则要求其需要拿到读写指针参数进行数据块读取实现,即算法函数本身兼具指针描述控制法读数据功能

    具体实现

    方法一、搬移数据接续法

    1、 如下图所示开辟 6 包(3120个点/包) 数据大小的缓存区

    2、 ADC 采集数据的存储首地址从包2起始,以包6为末地址终止, 数据存满包6后跳转至包2开启新一轮数据存储,以此形成环形缓存区机制

    3、 从首地址包 2 开始取数据,按首地址--->add1(3119-n1)--->addr2(add1+3119-n2)--->addrn 模式取数据,当下一次读取数据的地址 addrn+3119 > 包 6末地址,即剩余数据不够 3120 个点,需要切换至地址头包2读取剩余的数据。设本次数据读取至地址 addrn 为包 6 的 P 地址处,P 地址处距包6首的的偏移为 offsetnum = addrn - 包 5 末地址,要做的就是将 P地址处往后直到包 6 末尾的剩余数搬移到包 1 缓存中,以接续包2中的数据,搬移数据在包 1 中的存放位置也是距包 1 首地址偏移 offsetnum 处,这样就保证了读取数据的连续性。

    附部分代码:

     1 unsigned char dataBuf[3120*6];
     2 *startaddr = &dataBuf[3120];
     3 /**
     4 * @brief   : calculate next start-addr
     5 * @param   : 指向存储区所取数据得地址的地址
     6 * @retval  : none
     7 **/
     8 void addroffset(float **startaddr)
     9 {
    10     u16 num, offsetnum, newnum;
    11     /* 取数据至最后一包数据处,开始地址接续 */
    12     if((*startaddr) > (dataBuf[0]+(3120*5) - 1))  // 判断取数据是否已到最后一包
    13     {
    14         offsetnum = ((dataBuf[0]+(3120*6)-1) - (*startaddr)) >> 2;
    15         newnum = 3120 - offsetnum;
    16         (*startaddr) = (&dataBuf[newnum]);
    17         memcpy(&dataBuff[0] + newnum-1,  &dataBuf[0] +(3120*5+newnum-1),  offsetnum*4);
    18     }
    19     /* 取数据未到最后一包 */
    20     else
    21     {
    22          (*paddr) += n;  // n 位算法返回值
    23     }
    24 }

     

     
    方法二、指针描述控制法
     
    1、定义指针描述控制机构
    typedef struct
    {
        unsigned char *pwrite;                   /* 当前数据写指针 */
        unsigned char *pread;                    /* 当前数据读指针 */
        unsigned int validDataLength =0; /* 可供读取的有效数据长度 */
    }DataMemCtrl_t;
     
    2、处理过程
     
    1> 六种数据读取状态
     
    图一为初始状态,读写指针都指向存储区起始地址 
     
    图二为已写入一部分数据还未开始读取,写指针与读指针之差则为可供有效读取的数据长度                                
    1.PNG                  2.PNG
                                        图一                                                                                                   图二
     
    图三为在继续存数据的同时读取了一部分数据
     
    图四为读取数据已至当前写数据的位置了,表示当前已无可供读取的有效数据了
    3.PNG                       4.PNG
                                          图三                                                                                                    图四
     
    图五为存数据已超前读数据至下一轮了,当前可供读取的有效数据为当前读指针至存储区末尾 + 存储区首地址至当前写指针
     
    图六为存数据已超前读数据至下一轮了,恰好读指针在存储区末尾,可供读取的有效数据长度为写指针至数据存储区首地址
    5.PNG                      6.PNG
                                          图五                                                                                                    图六
     
    2> 附部分代码:
     
     1 unsigned char dataBuf[3120*6];
     2 DataMemCtrl_t data_mem_ctrl;
     3 int data_process(unsigned char * buf, int length)
     4 {
     5     unsigned short temp =0;
     6     unsigned int dataBuf_len =sizeof(dataBuf);
     7     /* 有效数据长度不够读 */
     8     if(data_mem_ctrl.validDataLength < length)
     9     {
    10         return -1;
    11     }
    12     /* 读指针与写指针同在一轮数据中 */
    13     if(data_mem_ctrl.pread < data_mem_ctrl.pwrite)
    14     {
    15         memcpy(buf, &dataBuf[0]+data_mem_ctrl.pread, length);
    16         /* 更新读指针 */
    17         data_mem_ctrl.pread +=length;
    18         /* 读数据至末尾,读指针归0 */
    19         if(data_mem_ctrl.pread == dataBuf_len)
    20         {
    21               data_mem_ctrl.pread=0;
    22         }
    23         /* 计算可待读数据长度 */
    24         data_mem_ctrl.validDataLength -=length;
    25         return length;
    26     }
    27     /* 写指针已超前读指针至一轮 */
    28     else if(data_mem_ctrl.pread > data_mem_ctrl.pwrite)
    29     {
    30         /* 计算可待读取的数据长度 */
    31         temp =dataBuf_len - data_mem_ctrl.pread;
    32         /* 数据长度够本次读取 */
    33         if(temp >= length)
    34         {
    35             memcpy(buf, &dataBuf[0]+data_mem_ctrl.pread, length);
    36             data_mem_ctrl.pread +=length;
    37         }
    38         /* 数据长度不够本次读取 */
    39         else
    40         {
    41             /* 读取该轮中可读取的数据 */
    42             memcpy(buf, &dataBuf[0]+data_mem_ctrl.pread, temp);
    43             /* 在下一轮中读取剩余的数据 */
    44             memcpy(buf+temp, &dataBuf[0]+data_mem_ctrl.pread, length-temp);
    45             data_mem_ctrl.pread =length -temp;
    46         }
    47         /* 数据读指针恰好已至末尾 */
    48         if(data_mem_ctrl.pread == dataBuf_len)
    49         {
    50             data_mem_ctrl.pread =0;
    51         }
    52         data_mem_ctrl.validDataLength -=length;
    53         return count;
    54     }
    55     /* 读写指针位置一致,无数据可读 */
    56     else
    57     {
    58         return 0;
    59     }
    60 }
  • 相关阅读:
    四则运算3
    结对编程
    2016年秋季-软件需求分析-UML图
    2016年秋季-学习进度条
    2016年秋季-学习进度条
    2016年秋季-《UML大战需求分析》-阅读笔记1
    2016年秋季-课堂练习1-Liz开发问题账户分析系统
    2016年秋季-《UML大战需求分析》-个人阅读计划
    2016年秋季-软件需求与分析-基本知识
    用户体验
  • 原文地址:https://www.cnblogs.com/skullboyer/p/9102236.html
Copyright © 2020-2023  润新知