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. 【笔记】浅谈支持向量机(SVM)

    SVM支持向量机 支持向量机的思想原理 使用支持向量机的思想,既可以解决回归问题,又可以解决分类问题 那么支持向量机的思想是什么? 已经知道逻辑回归这种算法的本质就是在一个平面中寻找决策边界,而分类算 ...

  2. Dll文件的创建与测试C#

    创建Dll文件 首先使用VS 2019创建Dll项目,创建项目时选择"类库",如下图 在项目中创建类文件,添加测试代码: namespace PlantSim_C_Interfac ...

  3. sqli-labs lesson 54-65

    less 54 需要从数据库的CHALLENGES表中取出key值输入,输入对了才算通过,但是只能做10次尝试. 这里id被单引号包裹,注意闭合单引号即可,剩下的就可以参照less 1获取表中信息即可 ...

  4. OAuth2 与OpenID的区别

    OAuth2 OpenId OpenId是在OAuth2基础之上实现的 比OAuth2更简便 OAuth2需要在认证后 额外的去再调用用户信息的接口 才能获取用户信息 而OpenId直接伴随token ...

  5. .Net 5 新特性之--支持字典在迭代中进行修改

    我们都知道以前字典迭代中是不支持动态修改的[否则会报错::"Collection was modified; enumeration operation may not execute.&q ...

  6. Mac Ideal 常用快捷键

    智能提示 ⌘ -> command ⇧ -> shift ⌥ -> option -> 上箭头 -> 下箭头 ⌃ -> Control mac的option键  = ...

  7. servlet中servletContext的五大作用(一)

    获取web的上下文路径 获取全局的参数 作为域对象使用 请求转发 读取web项目的资源文件 package day10.about_servletcontext.get_path; /** * 首先区 ...

  8. mysql基础操作(二):简单查询DQL

    -- 1.查询所有字段 select * from student; -- 2.查询指定的字段 select id from student; select id, name from student ...

  9. JDBC中级篇(MYSQL)——处理文件(BLOB)

    注意:其中的JdbcUtil是我自定义的连接工具类:代码例子链接: package b_blob_clob; import java.io.FileInputStream; import java.i ...

  10. SpringBoot博客开发之AOP日志处理

    日志处理: 需求分析 日志处理需要记录的是: 请求的URL 访问者IP 调用的方法 传入的参数 返回的内容 上面的内容要求在控制台和日志中输出. 在学习这部分知识的时候,真的感觉收获很多,在之前Spr ...