zoukankan      html  css  js  c++  java
  • 数据处理思想和程序架构: 单片机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
    ",data);

    例如,获取数组的第二位存储在flash里面的值

    flash_helper_get(1,&data,1);
    printf("get1=%d
    ",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
    ",flash_data_get_water_humidity_xxx_xxxx(0,0));
            printf("´æ´¢µÄʪ¶ÈÖµ:%d
    ",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);
    }

    移植使用

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

     

  • 相关阅读:
    2016年3月9日~10日,杨学明老师为武汉某著名通信企业提供内训课程服务!
    打造高效率产品测试体系--产品测试管理(深圳,2016.3.18~19)
    互联网产品上线前,做些什么——产品、开发、测试的视角
    2016年1月16日,《互联网项目管理高级实务》内训在上海某高科技企业成功举办!
    用C++对C++语法格式进行分析
    mysql主从配置
    Windows Zip/CentOS/Radhat系统安装Mysql5.7.x方法
    c++预声明类引发的无法解析外部符号问题
    解决VS2015单元测试“未能设置用于运行测试的执行上下文”问题
    扩展Linux磁盘空间
  • 原文地址:https://www.cnblogs.com/yangfengwu/p/14476294.html
Copyright © 2011-2022 走看看