數據處理思想和程序架構: 單片機STM32F407xx/F405xx/F415xx/417xx系列flash存儲方案


<p><iframe name="ifd" src="https://mnifdv.cn/resource/cnblogs/單片機知識點總結/directory.html" frameborder="0" scrolling="auto" width="100%" height="1500"></iframe></p>

 

說明

因為用到了STM32F407系列的單片機的flash存儲數據,所以寫了這套程序.

目的是為了在便於存儲.

關於407的Flash

1.F407xxx系列的flash都是這個樣子

STM32F405xx/407xx and STM32F415xx/417xx 也是這樣子

主存儲區總共12個扇區,Sector0 - Sector11;

Sector0 - Sector3  每個扇區是16KB = 16*1024 = 16384字節; 總共4個扇區 = 16384*4=65536字節

Sector4 扇區是64KB = 64*1024 = 65536字節; 

Sector5 - Sector11  每個扇區是128KB = 128*1024 = 131072字節; 總共7個扇區 = 131072*7=917504字節

這些扇區加起來總共是1M字節

 

2.關於flash的擦除

2.1

F407的flash擦除的時候要求每次只能擦除某個扇區;

擦除函數是: FLASH_EraseSector(uint32_t FLASH_Sector, uint8_t VoltageRange)

函數的第一個參數是扇區編號,第二個參數填寫自己芯片的供電電壓范圍.一般都是填寫 VoltageRange_3

 

 

 

2.2 關於怎么獲取這個編號

 

 

 

 

 

 

所以擦除一般都寫成: FLASH_EraseSector(/*獲取地址對應的扇區編號*/STMFLASH_GetFlashSector(要擦除的地址), VoltageRange_3)

 

2.3 提供給用戶的擦除函數

 

 

 

 

2.關於flash的寫入

用戶只需要記住,寫入的時候寫的地址必須是4的倍數,最少寫入一個字(4字節)

提供給用戶的寫入函數:(一般的數據咱不直接使用這個函數存儲數據,具體接着往下看)

 

 

 

3.關於flash的讀取

 

 

 

關於本節封裝的Flash寫讀函數思路

1.使用其中一個扇區存儲數據,假設使用11扇區,准備一個固定大小(假設是512)的u32類型的數組用來存儲數據

 

 

 

 

 

記住一句話:只要擦除過了的地方,不需要再次擦除就可以寫入數據

在下載程序的時候.默認所有的flash都是已經擦除過的.

2.第一次存儲

把整個數組全部寫到扇區的最前面

 

 

3.第二次存儲(不需要擦除,直接寫入就可以,因為后面都已經擦除過了)

把整個數組緊接着寫到后面

 

 

 

4.第三次存儲(不需要擦除,直接寫入就可以,因為后面都已經擦除過了)

把整個數組緊接着寫到后面

 

 

 

5.假設寫到最后了

我后面空了一點是因為定義的數組大小不一樣,不一定正好占滿.

 

 

6.接着再寫

檢測不夠了以后,擦除下這個扇區,把數據從頭開始存儲.

 

 

源碼使用

1.打開這節的程序

 

 

2.使用下面兩個文件

 

 

 

 

3.提示:存儲數據的時候是把數據放到這個數組里面,然后調用一下刷新函數.

 

 

 

4.存儲數據

 

 

flash_helper_init(ADDR_FLASH_SECTOR_11);

flash_helper_struct.FlashHelperData[0]=12345;
flash_helper_struct.FlashHelperData[1]=6666;

flash_helper_update();

 

 

 

5.讀取存儲的數據(直接從數組獲取) 推薦

因為數組里面的值就是存儲在flash里面的,所以直接從數組里面獲取即可

 

 

flash_helper_struct.FlashHelperData[0]

flash_helper_struct.FlashHelperData[1]

 

 

6.讀取存儲的數據(從flash里面獲取),一般用於查看下存儲的對不對

 

 

 

例如,獲取數組的第一位存儲在flash里面的值

 

u32 data;

flash_helper_get(0,&data,1);
printf("get0=%d\r\n",data);

 

 

 

 

 

 

 

例如,獲取數組的第二位存儲在flash里面的值

 

flash_helper_get(1,&data,1);
printf("get1=%d\r\n",data);

 

 

 

 

 

例如,獲取多個數據

 

u32 data_temp[200];

flash_helper_get(0,data_temp,200);
for(i=0;i<200;i++){
    printf("%d ",data_temp[i]);
}

 

 

 

 

 

提示:前面兩個是存儲的正常的數據,后面全是0.因為數組除了最后一位是0x55555555,其它位置默認是0

 

7.單片機一上電,獲取先前存儲的數據

flash_helper_init 函數會把以前的數據緩存到 flash_helper_struct.FlashHelperData 數組.

所以獲取以前存儲的數據只需要從數組里面獲取即可.

 

 

 

 

 

 

 

推薦使用方式(新建一個falsh_data文件)

1.假設使用數組其中一個位置記錄數據

 

 

 

 

 

 

 

 

 

 

2.再來一個這種的

 

 

 

 

3.假設使用數組的其中一個位置記錄四個單字節數據

數組是4字節的,如果當做一個使用就有點浪費了.

為了4字節和單字節快速分離出來,我直接使用了共用體

如果不使用共用體,就要寫什么右移24位,16位,8位啥的轉換為單字節.太麻煩.

關於轉換的詳細使用看下面鏈接文章

單片機模塊化程序: IEEE754規約,浮點數和16進制之間的轉換

 

 

 

 

用數組的其中一位記錄水位,濕度,XXX,XXXX

 

 

 

 

//ÉèÖÃˮλ0,ʪ¶È1,xxxÖµ2,xxxxÖµ3
void flash_data_set_water_humidity_xxx_xxxx(char type,char data)
{
    /*ÏȰÑÀïÃæµÄÊý¾ÝÈ«²¿»ñÈ¡³öÀ´*/
    union_resolve_value.u32_data = flash_helper_struct.FlashHelperData[2];
    if(type==0){//ÉèÖÃˮλ
        union_resolve_value.char_table[0] = data;/*ÖØÐÂÐÞ¸ÄÏÂˮλ*/
    }
    else if(type==1){//ÉèÖÃʪ¶È
        union_resolve_value.char_table[1] = data;/*ÖØÐÂÐÞ¸ÄÏÂʪ¶È*/
    }
    else if(type==2){//ÉèÖÃxxxÖµ
        union_resolve_value.char_table[2] = data;/*ÖØÐÂÐÞ¸ÄÏÂxxxÖµ*/
    }
    else if(type==3){//ÉèÖÃxxxxÖµ
        union_resolve_value.char_table[3] = data;/*ÖØÐÂÐÞ¸ÄÏÂxxxxÖµ*/
    }
    /*ÖØÐÂÉèÖÃÏÂÈ«²¿Êý¾Ý*/
    flash_helper_struct.FlashHelperData[2] = union_resolve_value.u32_data;
}

//»ñȡˮλ0,ʪ¶È1,xxxÖµ2,xxxxÖµ3
//·µ»Ø255,˵Ã÷´íÎó
char flash_data_get_water_humidity_xxx_xxxx(char type,char mode)
{    
    u32 value;
    if(mode) flash_helper_get(2,&value,1); //´ÓfalshÀïÃæ»ñÈ¡
    else value = flash_helper_struct.FlashHelperData[2];
    
    /*ת»»*/
    union_resolve_value.u32_data = value;
    
    if(type==0) return union_resolve_value.char_table[0]; //ˮλ
    else if(type==1)return union_resolve_value.char_table[1];//ʪ¶È
    else if(type==2)return union_resolve_value.char_table[2];//xxxÖµ
    else if(type==3)return union_resolve_value.char_table[3];//xxxxÖµ
    else return 255;
}

 

 

 

 

 

 

        //ÑÓʱֻÊDZÜÃâ´òÓ¡µÄÌ«¿ì
        delay_ms(3000);
        
        //ÉèÖÃеÄˮλֵ
        flash_data_set_water_humidity_xxx_xxxx(0,50);
        //ÉèÖÃеÄʪ¶ÈÖµ
        flash_data_set_water_humidity_xxx_xxxx(1,60);
        /*Ë¢ÐÂÒ»ÏÂÈÃÊý¾Ý´æ´¢µ½flash*/
        flash_helper_update();
        
        //ÑÓʱֻÊDZÜÃâ´òÓ¡µÄÌ«¿ì
        delay_ms(1000);
        
        printf("´æ´¢µÄˮλֵ:%d\r\n",flash_data_get_water_humidity_xxx_xxxx(0,0));
        printf("´æ´¢µÄʪ¶ÈÖµ:%d\r\n",flash_data_get_water_humidity_xxx_xxxx(1,0));

 

 

 

 

 

4.假設需要記錄最大1000個字節的數據

我加大了些緩存,2000個字節

 

 

 

 

 

 

 

//ÉèÖÃÒ»¸ö×²»µ½1000×Ö½ÚµÄ×Ö·û´®
void flash_data_set_1000bytes(char *data,u32 data_len)
{
    //Çå¿Õ
    memset(&flash_helper_struct.FlashHelperData[3],0,1000);
    //¸´ÖÆ
    memcpy(&flash_helper_struct.FlashHelperData[3],data,data_len);
}

//»ñȡһ¸ö×²»µ½1000×Ö½ÚµÄ×Ö·û´®
//data µÄ³¤¶ÈÊÇ1000×Ö½Ú
void flash_data_get_1000bytes(char *data,char mode)
{
    if(mode) flash_helper_get(3,(u32*)data,250); //´ÓfalshÀïÃæ»ñÈ¡
    else memcpy(data,&flash_helper_struct.FlashHelperData[3],1000);
}

 

 

 

移植使用

把下面文件放到自己的工程里面,按照上面的說明使用即可.

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM