在之前的8051的帖子中,分享了串口的一些知识,今天和大家分享一下使用串口对芯片内部的EEPROM进行一些读取,写入操作。
一:AI8051 EEPROM知识分享:
Ai8051U 系列单片机内部集成了大容量的 EEPROM。利用 ISP/IAP 技术可将内部 Data Flash 当EEPROM,擦写次数在 10 万次以上。EEPROM 可分为若干个扇区,每个扇区包含 512 字节。
注意:EEPROM 的写操作只能将字节中的1写为0,当需要将字节中的0写为1,则必须执行扇区擦除操作。EEPROM 的读/写操作是以1字节为单位进行,而EEPROM擦除操作是以1扇区(512 字节)为单位进行,在执行擦除操作时,如果目标扇区中有需要保留的数据,则必须预先将这些数据读取到RAM中暂存,待擦除完成后再将保存的数据和需要更新的数据一起再写回 EEPROMIDATA-FLASH。
所以在使用 EEPROM 时,建议同一次修改的数据放在同一个扇区,不是同一次修改的数据放在不同的扇区,不一定要用满。数据存储器的擦除操作是按扇区进行的(每扇区 512 字节)。
EEPROM 可用于保存一些需要在应用过程中修改并且掉电不丢失的参数数据。在用户程序中,可以对 EEPROM 进行字节读/字节编程/扇区擦除操作。在工作电压偏低时,建议不要进行 EEPROM 操作,以免发送数据丢失的情况。
可见,我们在操作AI8051内部的EEPROM时候,每次在写入数据之前需要注意以下几点:
1:对扇区进行删除指令,否则会导致数据存储失败;
2:写入时候注意每次操作的时候,需要一个以每个扇区进行操作。
3:EEPROM操作需要时间:是硬件自动控制的,用户只需要正确设置IAP_TPS寄存器即可。
二:软件代码如下所示:
2.1 擦除整个扇区
void EEPROM_SectorErase(u32 EE_address)
{
IAP_ENABLE(); //设置等待时间,允许IAP操作,送一次就够
IAP_ERASE(); //宏调用, 送扇区擦除命令,命令不需改变时,不需重新送命令
//只有扇区擦除,没有字节擦除,512字节/扇区。
//扇区中任意一个字节地址都是扇区地址。
IAP_ADDRE = (u8)(EE_address >> 16); //送扇区地址高字节(地址需要改变时才需重新送地址)
IAP_ADDRH = (u8)(EE_address >> 8); //送扇区地址中字节(地址需要改变时才需重新送地址)
IAP_ADDRL = (u8)EE_address; //送扇区地址低字节(地址需要改变时才需重新送地址)
EEPROM_Trig(); //触发EEPROM操作
DisableEEPROM(); //禁止EEPROM操作
}2.2 写入数据:
u8 EEPROM_write_n(u32 EE_address,u8 *DataAddress,u8 length)
{
u8 i;
u16 j;
u8 *p;
if(length == 0) return 1; //长度为0错误
IAP_ENABLE(); //设置等待时间,允许IAP操作,送一次就够
i = length;
j = EE_address;
p = DataAddress;
IAP_WRITE(); //宏调用, 送字节写命令
do
{
IAP_ADDRE = (u8)(EE_address >> 16); //送地址高字节(地址需要改变时才需重新送地址)
IAP_ADDRH = (u8)(EE_address >> 8); //送地址中字节(地址需要改变时才需重新送地址)
IAP_ADDRL = (u8)EE_address; //送地址低字节(地址需要改变时才需重新送地址)
IAP_DATA = *DataAddress; //送数据到IAP_DATA,只有数据改变时才需重新送
EEPROM_Trig(); //触发EEPROM操作
EE_address++; //下一个地址
DataAddress++; //下一个数据
}while(--length); //直到结束
EE_address = j;
length = i;
DataAddress = p;
i = 0;
IAP_READ(); //读N个字节并比较
do
{
IAP_ADDRE = (u8)(EE_address >> 16); //送地址高字节(地址需要改变时才需重新送地址)
IAP_ADDRH = (u8)(EE_address >> 8); //送地址中字节(地址需要改变时才需重新送地址)
IAP_ADDRL = (u8)EE_address; //送地址低字节(地址需要改变时才需重新送地址)
EEPROM_Trig(); //触发EEPROM操作
if(*DataAddress != IAP_DATA) //读出的数据与源数据比较
{
i = 2;
break;
}
EE_address++;
DataAddress++;
}while(--length);
DisableEEPROM();
return i;
}2.3 读取数据如下所示:
void EEPROM_read_n(u32 EE_address,u8 *DataAddress,u8 length)
{
IAP_ENABLE(); //设置等待时间,允许IAP操作,送一次就够
IAP_READ(); //送字节读命令,命令不需改变时,不需重新送命令
do
{
IAP_ADDRE = (u8)(EE_address >> 16); //送地址高字节(地址需要改变时才需重新送地址)
IAP_ADDRH = (u8)(EE_address >> 8); //送地址中字节(地址需要改变时才需重新送地址)
IAP_ADDRL = (u8)EE_address; //送地址低字节(地址需要改变时才需重新送地址)
EEPROM_Trig(); //触发EEPROM操作
*DataAddress = IAP_DATA; //读出的数据送往
EE_address++;
DataAddress++;
}while(--length);
DisableEEPROM();
}注意:关于 EEPROM 操作时是否需要关闭中断的问题
如果只有主循环的代码中或者只有中断代码中才使用IAP方式对 EEPROM 进行操作,则EEPROM 操作时不需要关闭中断。
如果主循环代码和中断代码中都有使用 IAP 方式对 EEPROM 进行操作,则 EEPROM 操作时必须关闭中断。因为如果在主循环代码中设置完成 IAP 相关寄存器后在 IAP 触发前或 IAP 触发半时,产生了中断,而在中断中进行 EEPROM 操作时,又对 IAP 相关寄存器进行重新设置中断返回后IAP 相关寄存器已经发生了改变,回到主循环中继续之前的 IAP 操作必然会出错。
我要赚赏金
