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 !


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM