介绍一种方法让内部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)
介绍一种方法让内部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)
举报