完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
3个回答
|
|
一般32位单片机的内部FALSH是不支持字节操作的,有的可以按字节读取,但是不能按字节写入。
而且,一般单片机内部FALSH擦除的最小单位都是页,如果向某页中的某个位置写入数据,恰好这个位置的前面存了其他数据,那么就必须把这页擦除,存的其他数据也会丢失。 实际上就是说内部的FALSH不好做改写的操作,如果有很多数据需要存放,最好是分页存储。这也是FALSH与E2PROM最大的区别,后者支持按字节操作且无需擦除,即使某一个地址写坏了,也不影响其他地址。 |
|
|
|
介绍一种方法让内部FLASH“支持”字节操作,且同一页的其他数据不受影响。
方法原理很简单,下面简单介绍下原理: 1.根据要写入地址,计算出该地址位于哪一页; 2.读出整个页,存入缓存BUF; 3.将要写入的数据按位置更新到BUF中; 4.擦除该页; 5.写入整个BUF。 可以看出这种方法弊端很明显: 1.耗时长 每次写都要读整个BUF,然后还要先把数据存到BUF里,然后再写入整个BUF; 2.FALSH擦写次数增加,降低使用寿命; 下面给出测试代码: #include #include #include //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; iRO = 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 其中还有个联合体的定义: 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是因为字符串的结尾字符是“ ” 3.紧接着,在0x1070FFE位置写入新的字符串,也要保证写入长度跨越1页。 unsigned char write2[]={“23456789”}; FLASH_Write(0x01070FFE,write2,sizeof(write2)); 可以看出,0x1070FFE~0x1071006的位置被写入了新的字节,但这两页的其他位置数据保持不变。 1.实际使用时,如果不是受限于成本或者FLASH大小,不建议这样读写内部FLASH,以为stm32内部FLASH也就 10W次寿命,这样频繁擦写会大大降低FLASH寿命。 2.如果保存的数据不多,建议每个数据都单独存1页,这样不用考虑擦除时会把其他数据也一并擦除。 |
|
|
|
只有小组成员才能发言,加入小组>>
23459个成员聚集在这个小组
加入小组1016 浏览 1 评论
1172 浏览 1 评论
12573 浏览 0 评论
5974 浏览 3 评论
17768 浏览 6 评论
1056浏览 1评论
1073浏览 1评论
40mR/650V SiC 碳化硅MOSFET,替代30mR 超结MOSFET或者20-30mR的GaN!
451浏览 1评论
1020浏览 1评论
5647浏览 1评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-1-23 10:41 , Processed in 0.779943 second(s), Total 83, Slave 65 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号