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 !
STM32L0系列EEPROM中结构体的读取的更多相关文章
- C语言中结构体对齐问题
C语言中结构体对齐问题 收藏 关于C语言中的结构体对齐问题 1,比如: struct{short a1;short a2;short a3;}A;struct{long a1;short a2;}B; ...
- C++中 结构体和类的异同
在C++中,结构体是一种特殊形态的类. 结构体和类的唯一区别就是: 结构体和类具有不同的默认访问控制属性. 类中,对于未指定访问控制属性的成员,其访问控制属性为私有类型(private) 结构体中, ...
- C语言中结构体赋值问题的讨论
今天帮师姐调一个程序的BUG,师姐的程序中有个结构体直接赋值的语句,在我印象中结构体好像是不能直接赋值的,正如数组不能直接赋值那样,我怀疑这个地方有问题,但最后证明并不是这个问题.那么就总结一下C语言 ...
- OC中结构体作为对象属性
在OC中结构体有时候也作为对象的属性 类的定义 #import <Foundation/Foundation.h> typedef struct{ int year; int month; ...
- (一)一个工作任务引起的乱战——c#中结构体与byte[]间相互转换
一个工作任务涉及到c#与c++系统间的udp通信,处理了蛮长时间没有完成任务,但是期间接触到不少小知识点.本人是初接触c#,c++语言没有接触过.可能写的东西都很小儿科,暂且记录下来当工作日记把. 先 ...
- C C++ 中结构体与类
先来说说C和C++中结构体的不同 a) C语言中的结构体不能为空,否则会报错 1>d:\myproject\visual studio 2013\projects\myc++\main.c(71 ...
- C语言中结构体赋值问题的讨论(转载)
今天帮师姐调一个程序的BUG,师姐的程序中有个结构体直接赋值的语句,在我印象中结构体好像是不能直接赋值的,正如数组不能直接赋值那样,我怀疑这个地方有问题,但最后证明并不是这个问题.那么就总结一下C语言 ...
- C中结构体的存储分配
C中结构体的存储分配 对于C语言中结构体所占的存储空间的大小,也一直是笔试面试的常客,今天好好看了一下这方面,以前一直以为很清楚了,今天通过各种实际测试举例,发现原来还是没有搞透彻,好在现在是彻底懂了 ...
- C /C ++中结构体的定义
c语言中结构体的定义: struct 结构体名{ 成员列表: ..... }结构体变量: 7.1.1 结构体类型变量的定义结构体类型变量的定义与其它类型的变量的定义是一样的,但由于结构体类型需要针对问 ...
随机推荐
- Golang语言系列-06-map数据类型和指针
Map数据类型和指针 Map数据类型 Map基本概念 package main import "fmt" // map // make()函数和new()函数的区别 // make ...
- SpringBoot开发八-会话管理
需求介绍-会话管理 利用Cookie和Seesion使得HTTP变成有会话的连接,写几个实例演示一下 代码实现 先写个例子,表示客户端第一次访问服务器,服务器端创建一个Cookie发送给客户端. 不管 ...
- [08 Go语言基础-for循环]
[08 Go语言基础-for循环] 循环 循环语句是用来重复执行某一段代码. for 是 Go 语言唯一的循环语句.Go 语言中并没有其他语言比如 C 语言中的 while 和 do while 循环 ...
- 命令执行 安鸾 Writeup
目录 命令执行 01 命令执行 02 仅代码层面来说,任意命令执行漏洞的利用条件: 1.代码中存在调用系统命令的函数 2.函数中存在我们可控的点 3.可控点没有过滤,或过滤不严格. Linux命令连接 ...
- LDAP未授权访问学习
LDAP未授权访问学习 一.LDAP 介绍 LDAP的全称为Lightweight Directory Access Protocol(轻量级目录访问协议), 基于X.500标准, 支持 TCP/IP ...
- FTP三种访问模式
FTP匿名访问模式是比较不安全的服务模式,尤其在真实的工作环境中千万不要存放敏感的数据,以免泄露. vsftpd程序默认已经允许匿名访问模式,我们要做的就是开启匿名用户的上传和写入权限,写入下面的参数 ...
- [论文阅读] ALM-HCS(高对比场景自适应对数映射)
[论文阅读] ALM-HCS(高对比场景自适应对数映射) 文章: Adaptive Logarithmic Mapping for Displaying High Contrast Scenes 1. ...
- .Net Core WebApi(二)
查看当前端口暴露的所有接口信息 https://localhost:5001/.well-known/openid-configuration 拿到信息如下
- MySQL常用权限操作
MySQL常用权限操作 ** ubuntu mysql 8.0.21修改root密码 ** 1.查看默认安装密码: sudo cat /etc/mysql/debian.cnf 2. 登录mysql ...
- ES6对象扩展——部分新的方法和属性
1.Object.is方法返回布尔值,和全等于===差不多,除了参数是+0和-0,以及NaN时 //Object.is,返回布尔值,和全等于===差不多,除了+0和-0,以及NaN console.l ...