一般32位单片机的内部FALSH是不支持字节操作的,有的可以按字节读取,但是不能按字节写入。

而且,一般单片机内部FALSH擦除的最小单位都是页,如果向某页中的某个位置写入数据,恰好这个位置的前面存了其他数据,那么就必须把这页擦除,存的其他数据也会丢失。

实际上就是说内部的FALSH不好做改写的操作,如果有很多数据需要存放,最好是分页存储。这也是FALSH与E2PROM最大的区别,后者支持按字节操作且无需擦除,即使某一个地址写坏了,也不影响其他地址。

下面介绍一种方法让内部FLASH"支持"字节操作,且同一页的其他数据不受影响。

方法原理很简单,下面简单介绍下原理:

1.根据要写入地址,计算出该地址位于哪一页;

2.读出整个页,存入缓存BUF;

3.将要写入的数据按位置更新到BUF中;

4.擦除该页;

5.写入整个BUF。

可以看出这种方法弊端很明显:

1.耗时长  每次写都要读整个BUF,然后还要先把数据存到BUF里,然后再写入整个BUF;

2.FALSH擦写次数增加,降低使用寿命;

下面给出测试代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>//C语言标准库
#include "flash.h"#define USER_FLASH_START_ADDR   0x01070000   //FLASH最后两个扇区  供用户使用u32tou8 u32data;//定义一个联合体//==================================================================================
// 获取某个地址所在的页首地址
// addr:FLASH地址
// 返回:该地址所在的页 共128页(0~127)
//==================================================================================
unsigned int FLASH_GetFlashPage(unsigned int addr)
{if (IS_FLASH_ADDRESS(addr)){return  (addr&(~0xFFF));//清0低12位就是该页的起始地址}
}
//==================================================================================
// 从FLASH中读取 一个字(32位)
// addr:读取地址
// 返回: 读到的字数据
//备注: 地址为4字节对齐
//==================================================================================
unsigned int FLSAH_ReadWord(unsigned int addr)
{return (*(unsigned int *)addr);
}//==================================================================================
//从FLASH指定地址 读取数据
//备注: 读取数据类型为32位  读取地址为4字节对齐
//==================================================================================
void  FLASH_Read(unsigned int   ReadAddr,unsigned char *pBuffer,unsigned int NumToRead)
{unsigned int i;u32tobyte cache;for(i=0; i<NumToRead; i+=4){cache.u32data=FLSAH_ReadWord(ReadAddr+i);pBuffer[i]=cache.buf[0];pBuffer[i+1]=cache.buf[1];pBuffer[i+2]=cache.buf[2];pBuffer[i+3]=cache.buf[3];}
}//==================================================================================
// 向FLASH指定地址 写入大量数据
// WriteAddr:写入首地址
// pBuffer:数据首地址
// NumToWrite:需要写入数据的大小
// 返回: 4=成功  1,2,3,5=失败
// 备注:
//==================================================================================
FLASH_Status  FLASH_Write(unsigned int  WriteAddr,unsigned char *pBuffer,unsigned int NumToWrite)
{FLASH_Status status = FLASH_COMPLETE;u32tobyte cache;//联合体定义unsigned int startaddr,endaddr,pageaddr=0;unsigned char buffer[4096];//4K缓冲区 对应FALSH 1页unsigned int i;unsigned int index,remain;startaddr = WriteAddr;endaddr = startaddr+NumToWrite;//结束地址FLASH_Unlock();FCU->RO = 0;//去掉所有扇区写保护//==================================================================================// 判断写入地址是否非法  起始地址或者结束地址不在FALSH范围内则退出//==================================================================================if(!(IS_FLASH_ADDRESS(startaddr)&& IS_FLASH_ADDRESS(endaddr))) return FLASH_ERROR_PG;while(startaddr < endaddr){//==================================================================================//1.计算起始地址在FALSH哪一页,并获取该页的首地址//2.计算起始地址在该页的偏移量//3.计算该页还剩余多少字节没写入数据          //==================================================================================pageaddr = FLASH_GetFlashPage(startaddr);//获取起始地址所在页的页首地址index = startaddr-pageaddr;//4K缓冲区内偏移地址remain=4096-index;//缓存区剩余大小//==================================================================================// 将该页数据读入4K缓冲数组,后面读写都是对该缓冲数组操作//==================================================================================          for(i=0;i<4096;i+=4)//读取一页到缓冲buff{cache.u32data=FLSAH_ReadWord(pageaddr+i);buffer[i]=cache.buf[0];buffer[i+1]=cache.buf[1];buffer[i+2]=cache.buf[2];buffer[i+3]=cache.buf[3];} //==================================================================================// 擦除FALSH对应的页,FLASH只能按页擦除,// 这一页数据已经被读到缓冲数组中了 之前的数据也保留下来了      //==================================================================================              status = FLASH_ErasePage(startaddr);if(status != FLASH_COMPLETE) return status;//擦除1页 4K字节                    //==================================================================================//1.判断要写入的数据是否大于该页剩余容量(即计算写入的数据长度是否跨多页) //2.将需要写入的数据转存到缓冲数据       //==================================================================================              if(NumToWrite > remain)//需要写入的数据量大于缓冲buf剩余字节数{for(i=index;i<4096;i++)//将需要写入FALSH的数据写入缓冲buff{buffer[i]=*(pBuffer++);                }NumToWrite-=remain;//需要写入的数据长度-本次已经写入的数据长度    startaddr+=remain;//地址向后偏移本次写入的字节数                    }else{for(i=index;i<NumToWrite+index;i++)//将需要写入FALSH的数据写入缓冲buff{buffer[i]=*(pBuffer++);              } startaddr+=NumToWrite;//地址向后偏移本次写入的字节数                              }   //==================================================================================// 将缓冲数组(4K)写入FLASH 对应的页// 此处必须从页首写入,因为缓冲数组正好4K,对应FALSH 1页   //==================================================================================              for(i=0;i<4096;i+=4)//将缓冲buffer写入 FALSH{cache.buf[0]=buffer[i];cache.buf[1]=buffer[i+1];cache.buf[2]=buffer[i+2];cache.buf[3]=buffer[i+3];if((status=FLASH_ProgramWord(pageaddr+i,cache.u32data))!= FLASH_COMPLETE){FLASH_Lock();return status;//写入失败 FLASH上锁 }                                     }           }FLASH_Lock();
}

其中还有个联合体的定义: 

typedef union
{unsigned int  data;unsigned char buf[4];
}
u32tou8;

FLASH_ErasePage、FLASH_ProgramWord、IS_FLASH_ADDRESS 这三个都是单片机FLASH的库函数

各家单片机不同,但功能基本相同,这里不再提供源码。

最后提供以下两个FLASH接口即可:

FLASH_Write(unsigned int    WriteAddr,unsigned char *pBuffer,unsigned int NumToWrite);FLASH_Read(unsigned int    ReadAddr,unsigned char *pBuffer,unsigned int NumToRead)

演示:

1.为方便查看结果,测试从0x1070FFC的位置开始写入数据,FLASH地址分布如下图所示:

这里展示了FLASH连续两页的地址,首先将这两页全部擦除。

2.接着从1070FFC的位置开始写入56个1,这样就保证了数据跨越了1页。 

unsigned char write[]= {"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111"};
FLASH_Write(0x01070FFC,write,sizeof(write));

 注意:最后的00是因为字符串的结尾字符是“\0”

3.紧接着,在0x1070FFE位置写入新的字符串,也要保证写入长度跨越1页

unsigned char write2[]={"23456789"};
FLASH_Write(0x01070FFE,write2,sizeof(write2));

可以看出,0x1070FFE~0x1071006的位置被写入了新的字节,但这两页的其他位置数据保持不变。

总结:

1.实际使用时,如果不是受限于成本或者FLASH大小,不建议这样读写内部FLASH,以为stm32内部FLASH也就

10W次寿命,这样频繁擦写会大大降低FLASH寿命。

2.如果保存的数据不多,建议每个数据都单独存1页,这样不用考虑擦除时会把其他数据也一并擦除。

单片机内部FLASH的字节操作相关推荐

  1. STM32单片机内部FLASH使用注意事项

    目录 1.前言 2.STM32 F1.F4.L1系列内部FLASH分区及大小 1.STM32F1系列 2.STM32F4系列 3.STM32L1系列 3.STM32 F1.F4.L1系列内部FLASH ...

  2. 单片机编程php,STC单片机内部FLASH读写程序(最新整理)

    <STC单片机内部FLASH读写程序(最新整理)>由会员分享,可在线阅读,更多相关<STC单片机内部FLASH读写程序(最新整理)(6页珍藏版)>请在人人文库网上搜索. 1.S ...

  3. STM32F系列单片机内部FLASH编程

    STM32F系列单片机内部含有较大容量的FLASH存储器,但没有EEPROM存储器,有时候对于参数的保存不得不另外加一片EEPROM芯片.这对于现如今大部分MCU都是FLASH+EEPROM的配置而言 ...

  4. HC32F460 内部flash驱动

    内部flash写入的时候,需要将代码分配到内存中执行,烧写flash时,程序无法从flash执行的,这一点确实比STM32差一些: /********************************* ...

  5. STC89C52单片机内部EEPROM驱动

    STC89C52单片机内部带有4K的EEPROM,严格来说,应该是4K的FLASH,它分为8个扇区,每个扇区有512个字节.读写数据只能按字节操作,擦除数据只能按扇区操作. 由于它掉电不易失的特性,可 ...

  6. STM32F103使用内部Flash保存参数

     在我们应用开发时,经常会有一些程序运行参数需要保存,如一些修正系数.这些数据的特点是:数量少而且不需要经常修改,但又不能定义为常量,因为每台设备可能不一样而且在以后还有修改的可能.将这类数据存在 ...

  7. 【STM32H7教程】第70章 STM32H7的内部Flash基础知识和HAL库API

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第70章       STM32H7的内部Flash基础知识和 ...

  8. 第50章 读写内部FLASH—零死角玩转STM32-F429系列

    第50章     读写内部FLASH 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fire ...

  9. STM32F103标准库开发:内部Flash的读写

    本文章技术信息均出自:STM32F103系列超详细参考手册-中文版 STM32F103标准库开发-目录 一.STM32存储器介绍 STM32存储器分为以下两种: 1. 随机存储器-RAM RAM是与C ...

  10. STM32F4读写内部FLASH【使用库函数】

    STM32F4Discovery开发帮使用的STM32F407VGT6芯片,内部FLASH有1M之多.平时写的代码,烧写完之后还有大量的剩余.有效利用这剩余的FLASH能存储不少数据.因此研究了一下S ...

最新文章

  1. 独家 | 基于TextRank算法的文本摘要(附Python代码)
  2. SpringBoot中常见的错误
  3. hdu 4667 Building Fence 计算几何模板
  4. 在Ubuntu中永久添加DNS
  5. C++二叉树的建立与遍历
  6. python redis 操作_使用Python操作redis
  7. prometheus 发送恢复 值_Prometheus监控神器-Rules篇
  8. 第8章-常用优先级和css3
  9. Fence Repair(POJ-3253)
  10. nb-iot 华为云_海曼NB-IoT智慧消防解决方案通过华为云资格审核,正式入驻华为云市场...
  11. 嵌入式工作笔记0006---半导体中的IP核是什么意思
  12. colordialog通过哪属性取其颜色_IT兄弟连 HTML5教程 CSS3揭秘 CSS常见的样式属性和值1...
  13. 经典排序算法(十三)--奇偶排序Odd-even Sort
  14. 态势感知平台分析流程
  15. Nmap端口扫描windows版
  16. maikr博客伴侣全新发布,支持博客备份和博客搬家
  17. 【PS4开发】如何通过unity3d发布ps4应用
  18. 书单(三)-从小到大课外阅读书籍顺序
  19. IE浏览器设置UserAgent
  20. printf 和 puts

热门文章

  1. 咖说 | 隐私何在?区块链是隐私保护的安全阀门
  2. Vscode运行Demo程序出现错误
  3. msxml6 x86.msi v6.10.1129.0
  4. lpush rpush 区别_lpush(lpush和rpush)
  5. java设计模式--01类图UML图箭头含义
  6. Git 使用源代码包编译、配置部署和使用 使用包管理工具安装
  7. 文献解读-物理信息深度学习(PINN)
  8. ESP32 学习笔记(二十一)电源管理
  9. 服务器运维实习周记,设备维护实习周记 - 实习周记 - 书业网.doc
  10. 各个国家的货币符号和英文缩写全解析