Flash闪存

15.Flash

FLASH简介:

  1. STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,
    通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程
  1. 读写FLASH的用途:
    利用程序存储器的剩余空间来保存掉电不丢失的用户数据
    通过在程序中编程(IAP),实现程序的自我更新
  2. 在线编程(In-Circuit Programming-ICP)用于更新程序存储器的全部内容,它通过JTAG、SWD协议或系统加载程序(Bootloader)下载程序
  3. 在程序中编程(In-Application Programming-IAP)可以使用微控制器支持的任一种通信接口下载程序

15.1 读写内部Flash

MyFlash--> Store--> main

#ifndef __MYFLASH_H
#define __MYFLASH_H
uint32_t MyFLASH_ReadWord(uint32_t Address);
uint16_t MyFLASH_ReadHalfWord(uint32_t Address);
uint8_t MyFLASH_ReadByte(uint32_t Address);

void MyFLASH_EraseAllPages(void);
void MyFLASH_ErasePage(uint32_t PageAddress);
void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data);
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);
#endif


#include "stm32f10x.h"                  // Device header

/**
  * 函    数:FLASH读取一个32位的字
  * 参    数:Address 要读取数据的字地址
  * 返 回 值:指定地址下的数据
  */
uint32_t MyFLASH_ReadWord(uint32_t Address)
{
    return *((__IO uint32_t *)(Address));   //使用指针访问指定地址下的数据并返回
}

/**
  * 函    数:FLASH读取一个16位的半字
  * 参    数:Address 要读取数据的半字地址
  * 返 回 值:指定地址下的数据
  */
uint16_t MyFLASH_ReadHalfWord(uint32_t Address)
{
    return *((__IO uint16_t *)(Address));   //使用指针访问指定地址下的数据并返回
}

/**
  * 函    数:FLASH读取一个8位的字节
  * 参    数:Address 要读取数据的字节地址
  * 返 回 值:指定地址下的数据
  */
uint8_t MyFLASH_ReadByte(uint32_t Address)
{
    return *((__IO uint8_t *)(Address));    //使用指针访问指定地址下的数据并返回
}

/**
  * 函    数:FLASH全擦除
  * 参    数:无
  * 返 回 值:无
  * 说    明:调用此函数后,FLASH的所有页都会被擦除,包括程序文件本身,擦除后,程序将不复存在
  */
void MyFLASH_EraseAllPages(void)
{
    FLASH_Unlock();                 //解锁
    FLASH_EraseAllPages();          //全擦除
    FLASH_Lock();                   //加锁
}
/**
  * 函    数:FLASH页擦除
  * 参    数:PageAddress 要擦除页的页地址
  * 返 回 值:无
  */
void MyFLASH_ErasePage(uint32_t PageAddress)
{
    FLASH_Unlock();                 //解锁
    FLASH_ErasePage(PageAddress);   //页擦除
    FLASH_Lock();                   //加锁
}

/**
  * 函    数:FLASH编程字
  * 参    数:Address 要写入数据的字地址
  * 参    数:Data 要写入的32位数据
  * 返 回 值:无
  */
void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data)
{
    FLASH_Unlock();                         //解锁
    FLASH_ProgramWord(Address, Data);       //编程字
    FLASH_Lock();                           //加锁
}

/**
  * 函    数:FLASH编程半字
  * 参    数:Address 要写入数据的半字地址
  * 参    数:Data 要写入的16位数据
  * 返 回 值:无
  */
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{
    FLASH_Unlock();                         //解锁
    FLASH_ProgramHalfWord(Address, Data);   //编程半字
    FLASH_Lock();                           //加锁
}

//Store.h Store.c

#ifndef __STORE_H
#define __STORE_H
extern uint16_t Store_Data[];
void Store_Init(void);
void Store_Save(void);
void Store_Clear(void);
#endif


#include "stm32f10x.h"                  // Device header
#include "MyFLASH.h"   //继承于MyFlash
#define STORE_START_ADDRESS     0x0800FC00      //存储的起始地址,存储到最后一页.
#define STORE_COUNT             512             //存储数据的个数

uint16_t Store_Data[STORE_COUNT];               //定义SRAM数组
/**
  * 函    数:参数存储模块初始化
  * 参    数:无
  * 返 回 值:无
  */
void Store_Init(void)
{
    /*判断是不是第一次使用*/
    if (MyFLASH_ReadHalfWord(STORE_START_ADDRESS) != 0xA5A5)    //读取第一个半字的标志位,if成立,则执行第一次使用的初始化
    {
        MyFLASH_ErasePage(STORE_START_ADDRESS);                 //擦除指定页
        MyFLASH_ProgramHalfWord(STORE_START_ADDRESS, 0xA5A5);   //在第一个半字写入自己规定的标志位,用于判断是不是第一次使用
        for (uint16_t i = 1; i < STORE_COUNT; i ++)             //循环STORE_COUNT次,除了第一个标志位
        {
            MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, 0x0000);       //除了标志位的有效数据全部清0
        }
    }
    
    /*上电时,将闪存数据加载回SRAM数组,实现SRAM数组的掉电不丢失*/
    for (uint16_t i = 0; i < STORE_COUNT; i ++)                 //循环STORE_COUNT次,包括第一个标志位
    {
        Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS + i * 2);      //将闪存的数据加载回SRAM数组
    }
}

/**
  * 函    数:参数存储模块保存数据到闪存
  * 参    数:无
  * 返 回 值:无
  */
void Store_Save(void)
{
    MyFLASH_ErasePage(STORE_START_ADDRESS);             //擦除指定页
    for (uint16_t i = 0; i < STORE_COUNT; i ++)         //循环STORE_COUNT次,包括第一个标志位
    {
        MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, Store_Data[i]);    //将SRAM数组的数据备份保存到闪存
    }
}

/**
  * 函    数:参数存储模块将所有有效数据清0
  * 参    数:无
  * 返 回 值:无
  */
void Store_Clear(void)
{
    for (uint16_t i = 1; i < STORE_COUNT; i ++)         //循环STORE_COUNT次,除了第一个标志位
    {
        Store_Data[i] = 0x0000;                         //SRAM数组有效数据清0
    }
    Store_Save();                                       //保存数据到闪存
}
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Store.h"
#include "Key.h"

uint8_t KeyNum;                 //定义用于接收按键键码的变量

int main(void)
{
    /*模块初始化*/
    OLED_Init();                //OLED初始化
    Key_Init();                 //按键初始化
    Store_Init();               //参数存储模块初始化,在上电的时候将闪存的数据加载回Store_Data,实现掉电不丢失
    
    /*显示静态字符串*/
    OLED_ShowString(1, 1, "Flag:");
    OLED_ShowString(2, 1, "Data:");
    
    while (1)
    {
        KeyNum = Key_GetNum();      //获取按键键码    
        if (KeyNum == 1)            //按键1按下
        {
            Store_Data[1] ++;       //变换测试数据
            Store_Data[2] += 2;
            Store_Data[3] += 3;
            Store_Data[4] += 4;
            Store_Save();           //将Store_Data的数据备份保存到闪存,实现掉电不丢失
        }
        if (KeyNum == 2)            //按键2按下
        {
            Store_Clear();          //将Store_Data的数据全部清0
        }
        
        OLED_ShowHexNum(1, 6, Store_Data[0], 4);    //显示Store_Data的第一位标志位
        OLED_ShowHexNum(3, 1, Store_Data[1], 4);    //显示Store_Data的有效存储数据
        OLED_ShowHexNum(3, 6, Store_Data[2], 4);
        OLED_ShowHexNum(4, 1, Store_Data[3], 4);
        OLED_ShowHexNum(4, 6, Store_Data[4], 4);
    }
}

2. 读取芯片ID

int main(void)
{
    OLED_Init();                        //OLED初始化
    
    OLED_ShowString(1, 1, "F_SIZE:");   //显示静态字符串
    OLED_ShowHexNum(1, 8, *((__IO uint16_t *)(0x1FFFF7E0)), 4);     //使用指针读取指定地址下的闪存容量寄存器
    
    OLED_ShowString(2, 1, "U_ID:");     //显示静态字符串
    OLED_ShowHexNum(2, 6, *((__IO uint16_t *)(0x1FFFF7E8)), 4);     //使用指针读取指定地址下的产品唯一身份标识寄存器
    OLED_ShowHexNum(2, 11, *((__IO uint16_t *)(0x1FFFF7E8 + 0x02)), 4);
    OLED_ShowHexNum(3, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x04)), 8);
    OLED_ShowHexNum(4, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x08)), 8);
    
    while (1)
    {
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容