STM32L0系列EEPROM中结构体的读取

STM32L0中操作EEPROM本来参考了上篇操作FLASH的方法,多多少少都有些问题。我觉得可能是结构体在转换成其他变量的时候出了问题。

比如下面这段代码,在Windows上可以正常运行(使用g++编译),但是在单片机上就会卡死。

typedef struct
{
    uint8_t IDD;
    uint8_t zero[4];
    uint8_t dutyCorr[4];
} usrflash;

usrflash eepromDat = {.IDD = 1U, .zero = {0}, .dutyCorr = {0}};

int main()
{
    float zerof = 3.14;
    uint8_t zeroc[4] = {0};
    float zero = 0;
    eepromDat.zero[0] = *((uint8_t *)&zerof + 0);
    eepromDat.zero[1] = *((uint8_t *)&zerof + 1);
    eepromDat.zero[2] = *((uint8_t *)&zerof + 2);
    eepromDat.zero[3] = *((uint8_t *)&zerof + 3);
    zero = *(float *)(&eepromDat)->zero;
    printf("\r\nzero=%f\r\n\n", zero);
    return 0;
}

这段代码的大义是将 zerof 这个变量打散储存在结构体的一个数组里,然后再还原出来。其在Windows上毫无问题,但若要再单片机上运行就必须创建一个中间变量将eepromDat.zero[0~3]的值先赋给中间变量再利用中间变量还原那个浮点数。总的来说就是单片机,结构体,不行

	float zerof = 3.14;
	uint8_t p_time[4] = {0};
	float zero = 0;
	eepromDat.zero[0] = *((uint8_t *)&zerof + 0);
	eepromDat.zero[1] = *((uint8_t *)&zerof + 1);
	eepromDat.zero[2] = *((uint8_t *)&zerof + 2);
	eepromDat.zero[3] = *((uint8_t *)&zerof + 3);
	p_time[0] = eepromDat.zero[0];
	p_time[1] = eepromDat.zero[1];
	p_time[2] = eepromDat.zero[2];
	p_time[3] = eepromDat.zero[3];
	zero = *(float*)p_time;
	printf("\r\nzero=%f\r\n\n", zero);

造成这种问题的原因我也没想明白,但我隐约觉得这事没准和编译器有关系,也许ARM-GCC可以解决。这是我第一次对ARM-CC提出质疑。

将结构体与字符串进行相互转换

为了应对以上的问题,我想到的办法是干脆先将结构体数据转换成字符串,再将字符串储存进 EEPROM 就要方便的多了。这样只各需要一个在 EEPROM 中读写字符串的函数就可以同时操作字符串和结构体了。

而且字符串是 char* , 其是由字节组成的,又因为byte「字节」是内存寻址和存取的最小单位,最起码这样看上去要安全一些。

对于结构体的要求

若想将结构体顺利的准换成字符串,对于结构体还是有一定要求的,一般要求结构体的形式如下

typedef struct
{
		uint8_t IDD;
		float zero;
		float dutyCorr;
		...............
} usrflash;

其中第一个成员变量的变量名和变量类型千万不要修改,因为在将结构体转换为字符串是是要以它的第一个成员变量的地址作为开头的。

将结构体转换成字符串的方法

其实就是指针的灵活运用

// eepromDat 是 usrflash 类型的结构体

uint8_t *p_temp = (uint8_t *)malloc(sizeof(usrflash));
for (uint8_t i = 0; i < sizeof(usrflash); i++)
{
    p_temp[i] = *((uint8_t *)((&(&eepromDat)->IDD) + i));
}
free(p_temp);

将字符串还原为结构体的方法

// eepromDat2 是 usrflash 类型的结构体

uint8_t *q_temp = (uint8_t *)malloc(sizeof(usrflash));
for (uint8_t i = 0; i < sizeof(usrflash); i++)
{
    *(uint8_t *)(&((&eepromDat2)->IDD) + i) = *(q_temp + i);
}
free(q_temp);

以字符串作为中间量的EEPROM中结构体的读写操作

    /* 向 EEPROM 中写结构体 ------------------------------------------- */
    // 待写入的结构体
    usrflash eepromDat;
    // 为中间缓存(字符串)分配内存
    uint8_t *p_temp = (uint8_t *)malloc(sizeof(usrflash));
    // 将结构体转换成字符串
    for (uint8_t i = 0; i < sizeof(usrflash); i++)
    {
        p_temp[i] = *((uint8_t *)((&(&eepromDat)->IDD) + i));
    }
    // 将字符串写入 EEPROM
    FLASH_EEPROM_Write_string(EEPROM_BASE_ADDR, p_temp, sizeof(usrflash));
    // 释放内存
    free(p_temp);

    /* 从 EEPROM 中读结构体 ------------------------------------------- */
    // 待存入的结构体
    usrflash eepromDat2;
    // 为中间缓存(字符串)分配内存
    uint8_t *q_temp = (uint8_t *)malloc(sizeof(usrflash));
    // 从 EEPROM 中读取字符串
    FLASH_EEPROM_Read_string(EEPROM_BASE_ADDR, q_temp, sizeof(usrflash));
    // 将字符串转换为结构体
    for (uint8_t i = 0; i < sizeof(usrflash); i++)
    {
        *(uint8_t *)(&((&eepromDat2)->IDD) + i) = *(q_temp + i);
    }
    // 释放内存
    free(q_temp);

EEPROM 函数。在别的文件中摘录

 void FLASH_EEPROM_Write_string(uint32_t addr, uint8_t * p_temp, uint16_t len)
    {
        HAL_FLASHEx_DATAEEPROM_Unlock();
        for (uint16_t i = 0; i < len; i++)
        {
            HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAMDATA_BYTE, addr + i, *((uint8_t *)(p_temp + i)));
        }
        HAL_FLASHEx_DATAEEPROM_Lock();
    }
    void FLASH_EEPROM_Read_string(uint32_t addr, uint8_t * q_temp, uint16_t len)
    {
        for (uint16_t i = 0; i < len; i++)
        {
            *((uint8_t *)(q_temp + i)) = *(uint8_t *)(addr + i);
        }
    }

禁止转载到 CSDN !
禁止转载到 CSDN !
禁止转载到 CSDN !

posted @ 2021-09-22 16:18  路合华  阅读(847)  评论(3编辑  收藏  举报