c-AVR内部EEPROM写入功能工作不正常



这是读取和写入的两个功能

////////////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寄存器下限范围内,可以使用sbicbi处理器指令单独访问这些位。

EECR |= 1 << EEMWE这样的操作将被编译为单比特访问。但是,根据数据表,你必须

  1. 在EECR中将0写入EEPE时,将逻辑1写入EEMPE位。

  2. 在设置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;
}

最新更新