1. 程式人生 > 實用技巧 >一種隨機起始地址迴圈連續存取資料的的機制

一種隨機起始地址迴圈連續存取資料的的機制

問題描述

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 處,這樣就保證了讀取資料的連續性。

附部分程式碼:

unsigned char dataBuf[3120*6];
*startaddr = &dataBuf[3120];

/**
 * @brief    : calculate next start-addr
 * @param : 指向儲存區所取資料得地址的地址
 * @retval  : none
 */
void addroffset(float **startaddr)
{
    uint16_t num, offsetnum, newnum;
    /* 取資料至最後一包資料處,開始地址接續 */
    if((*startaddr) > (dataBuf[0
]+(3120*5) - 1)) // 判斷取資料是否已到最後一包 { offsetnum = ((dataBuf[0]+(3120*6)-1) - (*startaddr)) >> 2; newnum = 3120 - offsetnum; (*startaddr) = (&dataBuf[newnum]); memcpy(&dataBuff[0] + newnum-1, &dataBuf[0] +(3120*5+newnum-1), offsetnum*4); } /* 取資料未到最後一包 */ else { (*paddr) += n; // n 位演算法返回值 } }

方法二、指標描述控制法 1、定義指標描述控制機構 typedef struct { unsigned char *pwrite; /* 當前資料寫指標 */ unsigned char *pread; /* 當前資料讀指標 */ unsigned int validDataLength =0; /* 可供讀取的有效資料長度 */ }DataMemCtrl_t; 2、處理過程 1> 六種資料讀取狀態 圖一為初始狀態,讀寫指標都指向儲存區起始地址 圖二為已寫入一部分資料還未開始讀取,寫指標與讀指標之差則為可供有效讀取的資料長度 圖一 圖二 圖三為在繼續存資料的同時讀取了一部分資料 圖四為讀取資料已至當前寫資料的位置了,表示當前已無可供讀取的有效資料了 圖三 圖四 圖五為存資料已超前讀資料至下一輪了,當前可供讀取的有效資料為當前讀指標至儲存區末尾 + 儲存區首地址至當前寫指標 圖六為存資料已超前讀資料至下一輪了,恰好讀指標在儲存區末尾,可供讀取的有效資料長度為寫指標至資料儲存區首地址 圖五 圖六 2>附部分程式碼:
 1 unsigned char dataBuf[3120*6];
 2 DataMemCtrl_t data_mem_ctrl;
 3 
 4 int data_process(unsigned char * buf, int length)
 5 {
 6     unsigned short temp =0;
 7     unsigned int dataBuf_len =sizeof(dataBuf);
 8     /* 有效資料長度不夠讀 */
 9     if (data_mem_ctrl.validDataLength < length)
10     {
11         return -1;
12     }
13     /* 讀指標與寫指標同在一輪資料中 */
14     if (data_mem_ctrl.pread < data_mem_ctrl.pwrite)
15     {
16         memcpy(buf, &dataBuf[0]+data_mem_ctrl.pread, length);
17         /* 更新讀指標 */
18         data_mem_ctrl.pread +=length;
19         /* 讀資料至末尾,讀指標歸0 */
20         if (data_mem_ctrl.pread == dataBuf_len)
21         {
22               data_mem_ctrl.pread=0;
23         }
24         /* 計算可待讀資料長度 */
25         data_mem_ctrl.validDataLength -=length;
26         return length;
27     }
28     /* 寫指標已超前讀指標至一輪 */
29     else if (data_mem_ctrl.pread > data_mem_ctrl.pwrite)
30     {
31         /* 計算可待讀取的資料長度 */
32         temp =dataBuf_len - data_mem_ctrl.pread;
33         /* 資料長度夠本次讀取 */
34         if (temp >= length)
35         {
36             memcpy(buf, &dataBuf[0]+data_mem_ctrl.pread, length);
37             data_mem_ctrl.pread +=length;
38         }
39         /* 資料長度不夠本次讀取 */
40         else
41         {
42             /* 讀取該輪中可讀取的資料 */
43             memcpy(buf, &dataBuf[0]+data_mem_ctrl.pread, temp);
44             /* 在下一輪中讀取剩餘的資料 */
45             memcpy(buf+temp, &dataBuf[0]+data_mem_ctrl.pread, length-temp);
46             data_mem_ctrl.pread =length -temp;
47         }
48         /* 資料讀指標恰好已至末尾 */
49         if (data_mem_ctrl.pread == dataBuf_len)
50         {
51             data_mem_ctrl.pread =0;
52         }
53         data_mem_ctrl.validDataLength -=length;
54         return count;
55     }
56     /* 讀寫指標位置一致,無資料可讀 */
57     else
58     {
59         return 0;
60     }
61 }