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 !

STM32L0系列EEPROM中结构体的读取的更多相关文章

  1. C语言中结构体对齐问题

    C语言中结构体对齐问题 收藏 关于C语言中的结构体对齐问题 1,比如: struct{short a1;short a2;short a3;}A;struct{long a1;short a2;}B; ...

  2. C++中 结构体和类的异同

    在C++中,结构体是一种特殊形态的类. 结构体和类的唯一区别就是:  结构体和类具有不同的默认访问控制属性. 类中,对于未指定访问控制属性的成员,其访问控制属性为私有类型(private) 结构体中, ...

  3. C语言中结构体赋值问题的讨论

    今天帮师姐调一个程序的BUG,师姐的程序中有个结构体直接赋值的语句,在我印象中结构体好像是不能直接赋值的,正如数组不能直接赋值那样,我怀疑这个地方有问题,但最后证明并不是这个问题.那么就总结一下C语言 ...

  4. OC中结构体作为对象属性

    在OC中结构体有时候也作为对象的属性 类的定义 #import <Foundation/Foundation.h> typedef struct{ int year; int month; ...

  5. (一)一个工作任务引起的乱战——c#中结构体与byte[]间相互转换

    一个工作任务涉及到c#与c++系统间的udp通信,处理了蛮长时间没有完成任务,但是期间接触到不少小知识点.本人是初接触c#,c++语言没有接触过.可能写的东西都很小儿科,暂且记录下来当工作日记把. 先 ...

  6. C C++ 中结构体与类

    先来说说C和C++中结构体的不同 a) C语言中的结构体不能为空,否则会报错 1>d:\myproject\visual studio 2013\projects\myc++\main.c(71 ...

  7. C语言中结构体赋值问题的讨论(转载)

    今天帮师姐调一个程序的BUG,师姐的程序中有个结构体直接赋值的语句,在我印象中结构体好像是不能直接赋值的,正如数组不能直接赋值那样,我怀疑这个地方有问题,但最后证明并不是这个问题.那么就总结一下C语言 ...

  8. C中结构体的存储分配

    C中结构体的存储分配 对于C语言中结构体所占的存储空间的大小,也一直是笔试面试的常客,今天好好看了一下这方面,以前一直以为很清楚了,今天通过各种实际测试举例,发现原来还是没有搞透彻,好在现在是彻底懂了 ...

  9. C /C ++中结构体的定义

    c语言中结构体的定义: struct 结构体名{ 成员列表: ..... }结构体变量: 7.1.1 结构体类型变量的定义结构体类型变量的定义与其它类型的变量的定义是一样的,但由于结构体类型需要针对问 ...

随机推荐

  1. MySQL:JDBC批量插入数据的效率

    平时使用mysql插入.查询数据都没有注意过效率,今天在for循环中使用JDBC插入1000条数据居然等待了一会儿 就来探索一下JDBC的批量插入语句对效率的提高 首先进行建表 create tabl ...

  2. MySQL学习01(初识MySQL)

    初识MySQL 只会写代码的是码农:学好数据库,基本能混口饭吃:在此基础上再学好操作系统和计算机网络,就能当一个不错的程序员.如果能再把离散数学.数字电路.体系结构.数据结构/算法.编译原理学通透,再 ...

  3. 【笔记】numpy.array基础(3)

    numpy数组的合并与分割 合并操作 concatenate拼接,只能操作维数一样的数据 且并不局限于两个元素 对于二维数组来说,可以通过控制axis来控制是按照行还是按照列来进行拼接操作,默认为ax ...

  4. LeetCode通关:栈和队列六连,匹配问题有绝招

    刷题路线参考: https://github.com/chefyuan/algorithm-base https://github.com/youngyangyang04/leetcode-maste ...

  5. WPF在圆上画出刻度线

    思路 我们可以使用Ellipse先画出一个圆当背景,然后用Canvas再叠加画上刻度线,就能得到如下的效果 我们先用Ellipse画一个橙色的圆,然后将Canvas的宽度和高度绑定到Ellipse的宽 ...

  6. MongoDB用户创建

    MongoDB采用基于角色的访问控制(RBAC)来确定用户的访问. 授予用户一个或多个角色,确定用户对MongoDB资源的访问权限和用户可以执行哪些操作. 用户应该只有最小权限集才能确保最小权限的系统 ...

  7. 将数组对象相同key的内容合并

    function fireDuplicate (arr) { var arr = JSON.parse(JSON.stringify(arr)) var ids = [] arr.forEach(fu ...

  8. C# 查询所有设备的插拔事件

    private void test() { //Win32_DeviceChangeEvent  Win32_VolumeChangeEvent ManagementEventWatcher watc ...

  9. asp.net MVC 的路由匹配

  10. Math.round() 函数返回一个数字四舍五入后最接近的整数。

    语法: Math.round(x); 参数:x 返回值:给定数字的值四舍五入到最接近的整数 描述: 如果参数的小数部分大于 0.5,则舍入到相邻的绝对值更大的整数. 如果参数的小数部分小于 0.5,则 ...