標題: C語言算法求助,關于保留最新的N次數(shù)據(jù) [打印本頁]

作者: bstljq    時間: 2024-6-17 16:40
標題: C語言算法求助,關于保留最新的N次數(shù)據(jù)
使用場景:需要在外接FLASH存儲最新的10次數(shù)據(jù),每次存儲的數(shù)據(jù)有點大(4Kbyte),按照更新的時間排序,次數(shù)越小,時間越新。
比如,昨天存完10次后,今天又需要存一次數(shù)據(jù)了,昨天的次數(shù)10舍棄,全部次數(shù)往后挪一個單位,今天的次數(shù)存在次數(shù)1位置。

我能想到的是使用鏈表,但是搞單片機好久沒碰過鏈表方面的知識了,還有其它方法嗎?

作者: bstljq    時間: 2024-6-17 16:45
之前簡單的排序可以在數(shù)組實現(xiàn),但是這個邏輯感覺不適合在FLASH中操作,因為又要讀,擦寫,既花時間,又要一直擦除會影響壽命。
作者: LaoYuTou    時間: 2024-6-18 08:25
鏈表和索引表都可以,隊列也可以,控制頭尾,不在頭尾的都是空閑空間。
作者: Y_G_G    時間: 2024-6-18 09:40
增加一個斷電檢測或者寫入動作,如果沒有斷電,最新的數(shù)據(jù)是保留在單片機上的,不用寫入FLASH
把寫入FLASH地址的記錄單獨放到一個頁面,每次寫入的時候,把已經(jīng)寫入的地址寫到這個頁面中
數(shù)據(jù)存放在其它的頁面,頁面是循環(huán)使用的,比如先寫1頁面,然后是2頁面
這樣的話,每次寫入就只要擦寫地址頁面就可以了
FLASH不是普通存儲器,一個地址只能寫入一次,你想再寫入第二次就擦寫整個頁面了
作者: devcang    時間: 2024-6-18 10:08
使用這樣的方法
固定的第1個位置是保存索引,每次保存完索引+1到第10、復位。表示一下個該寫入的索引。
固定的第2個位置是保存是開始索引。表示從該索引開始讀、到第10回0、讀夠10個。
后面是數(shù)據(jù)。
這樣讀寫最少。

作者: bstljq    時間: 2024-6-18 18:14
devcang 發(fā)表于 2024-6-18 10:08
使用這樣的方法
固定的第1個位置是保存索引,每次保存完索引+1到第10、復位。表示一下個該寫入的索引。
...

好的,我也有這個思路,在索引里面更改FLASH的地址偏移,指向不同地址,好像指針啊
作者: bstljq    時間: 2024-6-18 18:21
Y_G_G 發(fā)表于 2024-6-18 09:40
增加一個斷電檢測或者寫入動作,如果沒有斷電,最新的數(shù)據(jù)是保留在單片機上的,不用寫入FLASH
把寫入FLASH地 ...

謝謝,我打算做個外部超級電容了,掉電檢測再保存FLASH,平時保存RAM。目前是舊數(shù)據(jù)的刪除和新數(shù)據(jù)的插入有點想不通,還有就是加了電容,上電緩慢又怕出問題,感覺要加復位芯片啊
作者: bstljq    時間: 2024-6-18 18:23
LaoYuTou 發(fā)表于 2024-6-18 08:25
鏈表和索引表都可以,隊列也可以,控制頭尾,不在頭尾的都是空閑空間。

目前計劃是打算使用索引表,索引保存FLASH的偏移地址,每次刪除或者增加數(shù)據(jù),舊偏移索引里面的地址,這樣可以實現(xiàn)吧
作者: LaoYuTou    時間: 2024-6-19 08:41
是的,但是flash是按扇區(qū)操作的,一次寫一個扇區(qū),而且讀寫不快,影響壽命,不建議頻繁讀寫。
作者: SUNYAO    時間: 2024-6-19 12:07
對于在外接FLASH上存儲最新的10次數(shù)據(jù),可以采用循環(huán)緩沖區(qū)(環(huán)形隊列)的方式,這種方法比鏈表更加簡單高效,非常適合在單片機上使用。下面是實現(xiàn)這一方案的步驟:  ### 1. 設計存儲結構 假設每次數(shù)據(jù)的大小為4Kbyte,需要存儲10次數(shù)據(jù),因此需要的存儲空間為40Kbyte。  ### 2. 初始化環(huán)形緩沖區(qū) 環(huán)形緩沖區(qū)的概念是使用一個固定大小的數(shù)組,通過一個指針來跟蹤最新的數(shù)據(jù)位置,并循環(huán)使用數(shù)組空間。  ### 3. 寫入數(shù)據(jù) 每次寫入新的數(shù)據(jù)時,將指針移動到下一個位置。如果指針超出數(shù)組范圍,則回到數(shù)組的起點。  ### 4. 讀取數(shù)據(jù) 讀取數(shù)據(jù)時,根據(jù)指針和偏移量來獲取最新的數(shù)據(jù)。  ### 具體實現(xiàn) 下面是一個示例代碼,假設使用C語言來實現(xiàn)這一功能:  ```c #define DATA_SIZE 4096       // 每次數(shù)據(jù)大小為4Kbyte #define BUFFER_SIZE 10       // 環(huán)形緩沖區(qū)大小為10 #define FLASH_START_ADDRESS 0x00000000  // 外接FLASH起始地址,根據(jù)具體情況修改  // 環(huán)形緩沖區(qū)的當前索引 unsigned int currentIndex = 0;  // 寫入數(shù)據(jù)到FLASH的函數(shù) void writeDataToFlash(unsigned int index, const char* data) {     unsigned int address = FLASH_START_ADDRESS + (index * DATA_SIZE);     // 寫入數(shù)據(jù)到指定地址,具體的FLASH寫入函數(shù)根據(jù)芯片手冊實現(xiàn)     Flash_Write(address, data, DATA_SIZE); }  // 讀取FLASH中的數(shù)據(jù)到內(nèi)存 void readDataFromFlash(unsigned int index, char* data) {     unsigned int address = FLASH_START_ADDRESS + (index * DATA_SIZE);     // 從指定地址讀取數(shù)據(jù),具體的FLASH讀取函數(shù)根據(jù)芯片手冊實現(xiàn)     Flash_Read(address, data, DATA_SIZE); }  // 存儲新數(shù)據(jù) void storeNewData(const char* newData) {     // 寫入新數(shù)據(jù)到當前索引位置     writeDataToFlash(currentIndex, newData);          // 更新索引,循環(huán)使用緩沖區(qū)     currentIndex = (currentIndex + 1) % BUFFER_SIZE; }  // 獲取最新的n次數(shù)據(jù),n從1到10 void getLatestData(unsigned int n, char* data) {     if (n == 0 || n > BUFFER_SIZE) {         return; // 無效參數(shù)     }          int index = (currentIndex + BUFFER_SIZE - n) % BUFFER_SIZE;     readDataFromFlash(index, data); }  void Flash_Write(unsigned int address, const char* data, unsigned int size) {     // 具體的FLASH寫入實現(xiàn) }  void Flash_Read(unsigned int address, char* data, unsigned int size) {     // 具體的FLASH讀取實現(xiàn) } ```  ### 代碼解釋 - `currentIndex`:記錄當前最新數(shù)據(jù)在緩沖區(qū)中的位置。 - `writeDataToFlash`:將數(shù)據(jù)寫入FLASH的指定位置。 - `readDataFromFlash`:從FLASH的指定位置讀取數(shù)據(jù)。 - `storeNewData`:存儲新數(shù)據(jù)到環(huán)形緩沖區(qū),并更新索引。 - `getLatestData`:獲取最新的n次數(shù)據(jù)。  這種方法避免了復雜的鏈表操作,使用一個固定大小的數(shù)組來存儲數(shù)據(jù),通過簡單的索引操作實現(xiàn)數(shù)據(jù)的循環(huán)存儲和讀取,適合單片機環(huán)境下的使用。

作者: Y_G_G    時間: 2024-6-19 12:41
bstljq 發(fā)表于 2024-6-18 18:21
謝謝,我打算做個外部超級電容了,掉電檢測再保存FLASH,平時保存RAM。目前是舊數(shù)據(jù)的刪除和新數(shù)據(jù)的插入 ...

單片機本身工作電流并不大,超級電容可以串聯(lián)一個100歐的電阻或者是另外加一個LDO給超級電容充電
充電的電壓不要超過超級電容的耐壓
作者: cnos    時間: 2024-6-19 19:31
每次存儲扇區(qū)往后移動,用到最后一個扇區(qū)再擦除前面的扇區(qū),可以節(jié)約FLASH壽命。循環(huán)滾動,只要記得上次是從哪里存起的就行了。
作者: 人中狼    時間: 2024-6-19 21:05
應該不是數(shù)據(jù)存儲區(qū)的操作問題吧,單獨加個EEPROM用來存儲指針或鏈表什么的都可以

作者: 宇宙男子矮東瓜    時間: 2024-6-23 22:51
在單片機環(huán)境下,由于資源有限,使用鏈表可能不是最理想的解決方案,因為它需要額外的內(nèi)存空間來存儲節(jié)點?紤]到數(shù)據(jù)量較大(4Kbyte)且需要頻繁操作,可以考慮以下幾種方法:  1.  **循環(huán)數(shù)組(Circular Buffer)**:          *   使用一個固定大小的數(shù)組(例如,10個元素,每個元素4Kbyte),數(shù)組的最后一個元素和第一個元素相連,形成循環(huán)。     *   當新的數(shù)據(jù)到來時,替換數(shù)組的第一個元素(次數(shù)為1),然后更新次數(shù)(例如,使用一個寄存器記錄當前次數(shù))。     *   當需要訪問數(shù)據(jù)時,根據(jù)次數(shù)索引到數(shù)組的相應位置。 2.  **堆棧(Stack)**:          *   如果單片機支持堆棧操作,可以使用堆棧來存儲數(shù)據(jù)和次數(shù)。每次新數(shù)據(jù)到來,將數(shù)據(jù)壓入堆棧,同時更新堆棧頂部的次數(shù)(如果堆棧已滿,可能需要先彈出最舊的數(shù)據(jù))。     *   訪問數(shù)據(jù)時,從堆棧頂部獲取。 3.  **帶計數(shù)的順序存儲**:          *   如果內(nèi)存空間允許,可以將數(shù)據(jù)和次數(shù)連續(xù)存儲,每個數(shù)據(jù)塊后面緊跟著一個表示次數(shù)的字節(jié)。當新數(shù)據(jù)到來時,直接插入到數(shù)據(jù)末尾,次數(shù)加1。需要訪問時,根據(jù)次數(shù)找到對應的數(shù)據(jù)。 4.  **文件系統(tǒng)(如SD卡)**:          *   如果你的應用支持外部存儲,可以使用文件系統(tǒng)(如FatFS或YottaDB)將數(shù)據(jù)存儲為文件,每個文件代表一次數(shù)據(jù),文件名或文件屬性可以包含次數(shù)信息。每次新數(shù)據(jù)寫入一個新文件,舊文件保持,次數(shù)遞增。  在選擇方法時,要考慮單片機的內(nèi)存限制、操作速度和數(shù)據(jù)持久性等因素。循環(huán)數(shù)組和順序存儲通常更適用于資源有限的情況,而堆棧和文件系統(tǒng)則需要更高級的硬件支持。




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1