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 结构体类型变量的定义结构体类型变量的定义与其它类型的变量的定义是一样的,但由于结构体类型需要针对问 ...
随机推荐
- Shell-02-数据类型
shell数据类型 shell常用的数据类型有 字符串.整数型.数组 字符串 字符串是shell编程中最常用最有用的数据类型,字符串可以用单引号,也可以用双引号,也可以不用引号 建议使用双引号,因为双 ...
- STM32—位带操作
STM32中的位带操作: 名字为位带操作,实际上是对位的操作,位操作就是可以单独的对一个比特位读和写,这个在 51 单片机中非常常见. 51 单片机中通过关键字 sbit 来实现位定义, STM32 ...
- 备战秋招之十大排序——O(n)级排序算法
时间复杂度O(n)级排序算法 九.计数排序 前文说到,19591959 年 77 月,希尔排序通过交换非相邻元素,打破了 O(n^2)的魔咒,使得排序算法的时间复杂度降到了 O(nlog n) 级,此 ...
- C#多线程---Event类实现线程同步
一.简介 我们使用类(.net Framework中的类,如 AutoResetEvent, Semaphore类等)的方法来实现线程同步的时候,其实内部是调用操作系统的内核对象来实现的线程同步. S ...
- 一:Tomcat安装、配置和部署笔记
Tomcat安装(绿色版安装) 1.将下载的Tomcat解压到指定目录,如:D:\WorkSpaceByJava\DevtTools\Apache-Tomcat-8.0.23 2.Tomcat的目录结 ...
- LeetCoded第239题题解--滑动窗口最大值
滑动窗口最大值 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口内的 k 个数字.滑动窗口每次只向右移动一位. 返回滑动窗口中的最大值. 进 ...
- 栈(Stack)
特点: 栈最大的特点就是后进先出(LIFO).对于栈中的数据来说,所有操作都是在栈的顶部完成的,只可以查看栈顶部的元素,只能够向栈的顶部压入数据,也只能从栈的顶部弹出数据. 实现: 利用一个单链表来实 ...
- 网络视频m3u8解密及ts文件合并
网络视频m3u8解密及ts文件合并 参考了两篇博客: https://blog.csdn.net/weixin_41624645/article/details/95939510 https://bl ...
- 将svn项目导出,再导入到其他工作空间
方法一: 对于一致svn地址,本地没有的项目,直接eclipse中svn检出即可. 若本地有项目,但想导入到另一个工作空间(即拷贝一份,不想再从svn拉),则需要用export方法. 方法二(expo ...
- 二进制I/O
1 import java.io.BufferedInputStream; 2 import java.io.BufferedOutputStream; 3 import java.io.DataIn ...