一種隨機起始地址迴圈連續存取資料的的機制
問題描述
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方法二、指標描述控制法 1、定義指標描述控制機構 typedef struct { unsigned char *pwrite; /* 當前資料寫指標 */ unsigned char *pread; /* 當前資料讀指標 */ unsigned int validDataLength =0; /* 可供讀取的有效資料長度 */ }DataMemCtrl_t; 2、處理過程 1> 六種資料讀取狀態 圖一為初始狀態,讀寫指標都指向儲存區起始地址 圖二為已寫入一部分資料還未開始讀取,寫指標與讀指標之差則為可供有效讀取的資料長度 圖一 圖二 圖三為在繼續存資料的同時讀取了一部分資料 圖四為讀取資料已至當前寫資料的位置了,表示當前已無可供讀取的有效資料了 圖三 圖四 圖五為存資料已超前讀資料至下一輪了,當前可供讀取的有效資料為當前讀指標至儲存區末尾 + 儲存區首地址至當前寫指標 圖六為存資料已超前讀資料至下一輪了,恰好讀指標在儲存區末尾,可供讀取的有效資料長度為寫指標至資料儲存區首地址 圖五 圖六 2>附部分程式碼:]+(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 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 }