找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

帖子
查看: 1010|回復(fù): 9
打印 上一主題 下一主題
收起左側(cè)

25Q32怎么跟二分法查找結(jié)合起來用?

[復(fù)制鏈接]
回帖獎勵 30 黑幣 回復(fù)本帖可獲得 3 黑幣獎勵! 每人限 1 次
跳轉(zhuǎn)到指定樓層
樓主
ID:777254 發(fā)表于 2024-8-15 18:23 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
1.25Q32中保留N條記錄,每條記錄包含時間加數(shù)據(jù),時間是順序保存的。(數(shù)據(jù)量很大,Mbyte級別,不能讀到RAM中操作)
2.上位機發(fā)送指定時間加次數(shù)M,要求上報指定時間后的M次記錄。

想到的是二分法查找,不知道怎么結(jié)合用?大佬們還有更好的方法嗎?
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:309610 發(fā)表于 2024-8-16 10:34 | 只看該作者
我提交GPT給的方案可以參考一下
你提到的需求是在一個大數(shù)據(jù)文件中查找指定時間后的N條記錄,由于數(shù)據(jù)量較大,無法將整個文件加載到內(nèi)存中,直接在磁盤上進行操作。二分法結(jié)合順序讀取是一個合理的解決方案,以下是具體步驟:1. 二分查找定位指定時間由于時間是按順序保存的,二分查找可以幫助我們快速定位到接近目標時間的記錄。讀取文件頭和尾部的記錄,通過它們的時間值計算中間位置(假設(shè)你可以通過文件指針直接跳到中間的位置)。二分查找:將中間位置的時間與目標時間進行比較。如果目標時間大于當前時間,繼續(xù)在后半部分查找;反之在前半部分查找。重復(fù)這個過程,直到找到目標時間或最接近目標時間的位置。2. 順序讀取N條記錄一旦找到了目標時間的位置,接下來需要順序讀取指定數(shù)量的記錄。將文件指針移到二分查找到的位置,順序讀取接下來的N條記錄。由于時間是順序排列的,所以直接讀取M次就可以獲得所需數(shù)據(jù)。

總結(jié)使用二分查找快速定位到目標時間的記錄。順序讀取目標時間之后的N條記錄。這種方法的優(yōu)勢在于只需要在磁盤上進行有限的讀取操作,避免了全量讀取數(shù)據(jù)到內(nèi)存中,可以有效處理大規(guī)模數(shù)據(jù)文件。

在STM32平臺上使用C語言進行二分查找并讀取指定時間后的記錄,結(jié)合存儲器25Q32,可以參考以下方案:1. 環(huán)境準備Flash類型: 25Q32是一種SPI Flash存儲器。你需要在STM32上配置SPI接口,確�?梢酝ㄟ^SPI協(xié)議訪問25Q32存儲器。文件系統(tǒng)或裸操作: 如果數(shù)據(jù)是按照某種結(jié)構(gòu)直接存儲在Flash中的,你可能需要裸操作Flash存儲器,即通過特定的SPI指令讀取數(shù)據(jù)。2. 數(shù)據(jù)組織假設(shè)每條記錄的格式如下:struct Record {
    uint32_t timestamp; // 時間戳,假設(shè)是4字節(jié)
    uint8_t data[DATA_LENGTH]; // 數(shù)據(jù)部分
};假設(shè)每條記錄長度固定為RECORD_SIZE。3. 二分查找算法實現(xiàn)為了從大文件中高效找到指定時間點后的數(shù)據(jù),可以通過二分查找確定目標時間的起始位置。以下是步驟:3.1 計算記錄總數(shù)你可以通過Flash的總?cè)萘砍悦織l記錄的大小來計算出記錄總數(shù)。#define FLASH_SIZE (4 * 1024 * 1024)  // 25Q32容量 4MB
#define RECORD_SIZE sizeof(struct Record)

uint32_t total_records = FLASH_SIZE / RECORD_SIZE;3.2 實現(xiàn)二分查找二分查找用于找到指定時間戳的位置。uint32_t binary_search(uint32_t target_time) {
    uint32_t low = 0;
    uint32_t high = total_records - 1;
   
    while (low <= high) {
        uint32_t mid = (low + high) / 2;
        struct Record record;
        read_record(mid, &record); // 從flash讀取第mid條記錄
        
        if (record.timestamp < target_time) {
            low = mid + 1;
        } else if (record.timestamp > target_time) {
            high = mid - 1;
        } else {
            return mid; // 找到精確時間
        }
    }
   
    return low; // 沒有精確匹配,返回最接近的記錄位置
}3.3 從指定位置讀取M條記錄找到目標位置后,可以順序讀取接下來的M條記錄。void read_next_n_records(uint32_t start_index, uint32_t n) {
    for (uint32_t i = 0; i < n; ++i) {
        struct Record record;
        read_record(start_index + i, &record); // 讀取并處理記錄
        // process_record(&record);
    }
}4. SPI Flash讀操作實現(xiàn)在STM32上實現(xiàn)SPI讀取25Q32 Flash中的數(shù)據(jù),需要使用STM32的HAL庫或直接操作寄存器。4.1 SPI Flash讀記錄的實現(xiàn)void read_record(uint32_t index, struct Record *record) {
    uint32_t address = index * RECORD_SIZE;
   
    // 使用SPI讀取數(shù)據(jù)
    uint8_t cmd[4];
    cmd[0] = READ_COMMAND;           // 讀取命令(通常為0x03)
    cmd[1] = (address >> 16) & 0xFF; // 地址高字節(jié)
    cmd[2] = (address >> 8) & 0xFF;  // 地址中字節(jié)
    cmd[3] = address & 0xFF;         // 地址低字節(jié)
   
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); // 拉低片選(CS)
    HAL_SPI_Transmit(&hspi1, cmd, 4, HAL_MAX_DELAY);       // 發(fā)送讀命令和地址
    HAL_SPI_Receive(&hspi1, (uint8_t*)record, RECORD_SIZE, HAL_MAX_DELAY); // 讀取數(shù)據(jù)
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);   // 拉高片選(CS)
}5. 總結(jié)使用二分查找算法在SPI Flash中查找指定時間戳的位置。從該位置開始順序讀取指定數(shù)量的記錄。在STM32上通過SPI接口實現(xiàn)對25Q32的讀操作。這個方案在STM32平臺上效率較高,能夠處理大規(guī)模數(shù)據(jù)存儲器中的查找和讀取操作。
回復(fù)

使用道具 舉報

板凳
ID:910662 發(fā)表于 2024-8-16 11:07 | 只看該作者
如果時間是均勻的,計算即可;如果是隨機的,除了二分法,還有黃金分割法更優(yōu),你不妨試試。不過Mbyte也不是很大,二分法也不錯。
回復(fù)

使用道具 舉報

地板
ID:777254 發(fā)表于 2024-8-16 11:53 | 只看該作者
dhjmw 發(fā)表于 2024-8-16 11:07
如果時間是均勻的,計算即可;如果是隨機的,除了二分法,還有黃金分割法更優(yōu),你不妨試試。不過Mbyte也不 ...

時間不是規(guī)律增加的,因為外部可以設(shè)置這個時間間隔,間隔在1-99內(nèi)。
回復(fù)

使用道具 舉報

5#
ID:844772 發(fā)表于 2024-8-19 15:12 | 只看該作者
1、我覺得二分法就不錯的;
2、但更建議使用插值法,因為雖然時間間隔可調(diào)但估計不會頻繁調(diào)整所以時間隨機性不那么大適合插值法;
3、前邊提的黃金分割法是不是需要構(gòu)建斐波那契數(shù)列啊,這在單片機上需要消耗不少內(nèi)存�。�
4、如果插值法不能滿足要求,還可以試試先用分塊法粗篩,再用插值法。
回復(fù)

使用道具 舉報

6#
ID:777254 發(fā)表于 2024-8-19 20:36 | 只看該作者
glinfei 發(fā)表于 2024-8-19 15:12
1、我覺得二分法就不錯的;
2、但更建議使用插值法,因為雖然時間間隔可調(diào)但估計不會頻繁調(diào)整所以時間隨機 ...

目前遇到個難題,就是在FLASH空間內(nèi),如果存儲到盡頭,會從起始地址開始覆蓋回滾覆蓋存,這樣就會出現(xiàn)整個存儲空間,地址從小到大的數(shù)據(jù),其記錄的時間并不是按先后順序的,總不能把所有記錄數(shù)據(jù)讀出來排序吧
回復(fù)

使用道具 舉報

7#
ID:1034262 發(fā)表于 2024-8-20 15:42 | 只看該作者
二分法用于間隔恒定的單調(diào)參數(shù)有效,時間順序雖然單調(diào),但是間隔不恒定,效果欠佳,但還是可以用。
更好的辦法是時間和數(shù)據(jù)分開存放(類似電腦文件系統(tǒng)的目錄項、鏈表、數(shù)據(jù)),特別是數(shù)據(jù)比較大時特別有效,讀出時間查找,然后讀出對應(yīng)的數(shù)據(jù)、
回復(fù)

使用道具 舉報

8#
ID:844772 發(fā)表于 2024-8-21 08:56 | 只看該作者
li1069136863 發(fā)表于 2024-8-19 20:36
目前遇到個難題,就是在FLASH空間內(nèi),如果存儲到盡頭,會從起始地址開始覆蓋回滾覆蓋存,這樣就會出現(xiàn)整 ...

運行一段時間,必然一直按你說的這種情況存儲,可以理解順序是 CDAB ,A<B<C<D,而且C=B+1;如果沒有做數(shù)據(jù)索引,那就先看在AB段還是在CD段 即(X>C還是X<B),然后再二分法去找,當然分后的新中點要先對分段,比如X在AB段,二分后的新點E如果大于B,那就丟棄再找。這里有很多可以優(yōu)化的地方,比如利用一次是刪除多少等條件,迅速發(fā)現(xiàn)DA點,及其X是否在記錄中;或者刪除舊數(shù)據(jù)時直接記錄一下,可以省不少時間。
回復(fù)

使用道具 舉報

9#
ID:777254 發(fā)表于 2024-8-21 14:19 | 只看該作者
glinfei 發(fā)表于 2024-8-21 08:56
運行一段時間,必然一直按你說的這種情況存儲,可以理解順序是 CDAB ,A

是做了索引,索引保存的是記錄的總次數(shù),還有最新的一條記錄跟基地址的偏移量,主要是這兩個變量。我先按照你的思路捋一下
回復(fù)

使用道具 舉報

10#
ID:844772 發(fā)表于 2024-8-21 15:51 | 只看該作者
li1069136863 發(fā)表于 2024-8-21 14:19
是做了索引,索引保存的是記錄的總次數(shù),還有最新的一條記錄跟基地址的偏移量,主要是這兩個變量。我先按 ...

那就相當于分兩個塊,分別搜索啊,但有個問題,查找A的偏移要注意,因為刪除是按頁面刪的,所以會有空白區(qū),可以理解DA之間有空白區(qū),
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表