这是读取和写入的两个功能
////////////EEPROM.c//////////////
void IEEPROM_Write(u16 A_u16Adress, u8 A_u8Data)
{
/* Wait for completion of previous write */
while(GET_BIT(EECR,EECR_EEWE)==1);
/* Set up address and data registers */
EEAR = A_u16Adress;
EEDR = A_u8Data;
/* Write logical one to EEMWE */
SET_BIT(EECR,EECR_EEMWE);
/* Start eeprom write by setting EEWE */
SET_BIT(EECR,EECR_EEWE);
}
u8 IEEPROM_Read(u16 A_u16Adress)
{
/* Wait for completion of previous write */
while(GET_BIT(EECR,EECR_EEWE)==1);
/* Set up address and data registers */
EEAR = A_u16Adress;
/* Start eeprom read by setting EERE */
SET_BIT(EECR,EECR_EERE);
return EEDR;
}
////////////EEPROM.h//////////////
#define EEARH (*(volatile u8 *)0x3F)
#define EEARL (*(volatile u8 *)0x3E)
#define EEAR (*(volatile u16 *)0x3E)
#define EECR (*(volatile u8 *)0x3C)
#define EECR_EERE 0
#define EECR_EEWE 1
#define EECR_EEMWE 2
#define EECR_EERIE 3
#define EEDR (*(volatile u8 *)0x3D)
void IEEPROM_Write(u16 A_u16Adress, u8 A_u8Data);
u8 IEEPROM_Read(u16 A_u16Adress);
我遵循了ATMEGA32数据表的说明,但代码不起作用我在一个字节上写了一个数字,然后读取并在LCD上显示,但它打印255,
不要在设置EEMWE
和设置EEWE
之间延迟。数据表上写着,我强调:
设置EEMWE时,在四个时钟周期内设置EEWE将数据写入所选地址的EEPROM。如果EEMWE为零,则设置EEWE将无效。当软件将EEMWE写入1时,硬件在四个时钟周期后将该位清零。
我删除了它,但仍然存在相同的问题
然后我假设SET_BIT
是一个需要超过四个时钟周期的函数或宏。你可能想编辑你的问题,并向我们展示它的定义。
用适当的代码替换它,以确保它等效于:
EECR |= 1 << EEMWE;
EECR |= 1 << EEWE;
当然,在两者之间不必发生中断。
数据表还提到:
在CPU写入闪存期间,EEPROM无法编程。在启动新的EEPROM写入之前,软件必须检查闪存编程是否已完成。
因此,建议等待SPMCR
中的SPMEN
变为零。然而,如果您确信没有Flash编程发生,我认为这是可选的。
EECR
寄存器位于IO寄存器下限范围内,可以使用sbi
和cbi
处理器指令单独访问这些位。
像EECR |= 1 << EEMWE
这样的操作将被编译为单比特访问。但是,根据数据表,你必须
在EECR中将0写入EEPE时,将逻辑1写入EEMPE位。
在设置EEMPE后的四个时钟周期内,将逻辑1写入EEPE。
这意味着,当使用sbi
时,零将不会写入EEPE
。相反,使用分配:
EECR = (EECR & ~(1 << EEPE)) | (1 << EEMPE)
或简单的EECR = (1 << EEMPE)
(将零写入所有其他位(
此外,如前所述,设置EEPE
必须在4个cpu时钟周期内完成。
以下是EEPROM写入代码的工作示例:
void eeprom_write(ee_addr_type addr, uint8_t val) {
while (EECR & (1 << EEPE)); // wait for the previous EEPROM operation to complete
uint8_t old_sreg = SREG; // Save flags (including I flag)
asm volatile("cli":::"memory"); // locking interrupts
while (EECR & (1 << EEPE)); // just for the case EEPROM operation was started in the interrupt, wait again
EEAR = addr;
EECR |= (1 << EERE); // reading the EEPROM content
uint8_t d = EEDR;
if (d != val) { // Programming only if needed
uint8_t eecr_val;
if (val == 0xFF) { // If all bits need to be set then
eecr_val = (1 << EEPM0); // Erase only mode
} else if ((d & val) == val) { // If all bits are only changing from 1 to 0 then
eecr_val = (1 << EEPM1); // Write only mode
} else {
eecr_val = 0; // Otherwise erase and write
}
EEDR = val;
EECR = eecr_val | (1<<EEMPE);
EECR |= (1<<EEPE);
}
SREG = old_sreg; // Restoring interrupt flag (enable interrupts only if they were enabled at the beginning)
}
当EEPROM操作正在进行时,该功能退出,在读取EEPROM 之前,您必须检查它是否完成
uint8_t eeprom_read(ee_addr_type addr) {
while(EECR & (1<<EEPE)); // wait for the previous EEPROM operation to complete
uint8_t old_sreg = SREG;
asm volatile("cli":::"memory"); // Lock interrupts
while(EECR & (1<<EEPE));
EEAR = addr;
EECR |= (1<<EERE);
uint8_t res = EEDR;
SREG = old_sreg; // Restore interrupts
return res;
}