在FLASH中读写结构体
在FLASH中读写结构体
注意事项
编程(写数据)地址要对齐
写数据时,我们要指定写入的地址,如果写入地址为非对齐,则会出现编程对齐错误。
比如遵循32位(4字节)地址对齐,你的地址只能是4的倍数。0x08001000正确,0x08001001错误。
不同型号对齐宽度可能不同,有的32位、有的128位等,可通过“取余”判断地址。比如我遇到在
EEPROM中写一个结构体时,下面这种会有问题,最后一个数据会写入失败。将uint8_t ID;改为uint32_t ID;则正常。typedef struct
{
// uint8_t ID;
uint32_t ID;
float zero;
float dutyCorr;
float fittingCorr;
float initialTemp;
} usrflash;
main.c
usrflash dtl645Config = {0};
...
// 读
FLASH_EEPROM_Read_struct(0x0801FC00, &dtl645Config);
// 写
FLASH_EEPROM_Write_struct(0x0801FC00, &dtl645Config);
flash.h
#ifndef __FLASH_H
#define __FLASH_H
#ifdef __cplusplus
extern "C"
{
#endif
#include "main.h"
// 在 FLASH 写入的结构体变量的类型。
// 第一个成员变量的变量名(ID)不要随便改;
// 变量类型也千万别瞎改。
typedef struct
{
uint8_t ID; // ID
uint8_t addr[6]; // 终端地址
uint8_t baud; // 波特率
uint8_t residualCurrent; // 剩余电流值
uint8_t warningValue; // 剩余电流预警值(百分比)
uint8_t actionValue; // 剩余电流动作值
uint8_t lndt; // 极限不驱动时间
uint16_t trippingTimes; // 跳闸次数mi
uint8_t password[3]; // 密码
uint8_t sSwitch; // 动作状态(0为断开,1为闭合)(分闸/合闸)
uint8_t sStatus; // 运行状态(0为正常,1为警告,2为越限)
} usrflash;
// 在FLASH中写一个字(32bit)
void FLASH_EEPROM_Write(uint32_t a, uint32_t n);
// 从FLASH中读取一个字(32bit)
uint32_t FLASH_EEPROM_Read(uint32_t addr);
// 在FLASH中写一个结构体(usrflash 类型的结构体)
void FLASH_EEPROM_Write_struct(uint32_t addr, usrflash *userinfo);
// 从FLASH中读取一个结构体(usrflash 类型的结构体)
void FLASH_EEPROM_Read_struct(uint32_t addr, usrflash *userinfo);
#ifdef __cplusplus
}
#endif
#endif /* __FLASH_H */
flash.c
//***************************************************************************************************
// flash.c 串口相关功能实现
//
// Includes
// ******************************************************************************************
#include "flash.h"
//***************************************************************************************************
// 在FLASH中写一个字(32bit)
// 传入参数为写入的地址和要写入的数据, 写入数据以字为单位,每个字占32bit即4Byte.
// 擦除时将擦除此地址所在的一整页。
//
void FLASH_EEPROM_Write(uint32_t addr, uint32_t n)
{
// FLASH 擦除操作 --------------------------------------------------------------/
HAL_FLASH_Unlock(); //解锁
uint32_t PageError = 0; // 如果出现错误这个变量会被置为出错的FLASH地址
FLASH_EraseInitTypeDef EraseInitStruct; // 定义结构体
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; // Flash执行页面只做擦除操作
EraseInitStruct.PageAddress = addr; // 要擦除的地址
EraseInitStruct.NbPages = 1; // 要擦除的页数
if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) == HAL_OK)
; // 擦除此地址所在的一整页
// FLASH 写入操作 --------------------------------------------------------------/
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, n); // 向FLASH中写入
HAL_FLASH_Lock(); // 锁住FLASH
}
//***************************************************************************************************
// 从FLASH中读取一个字(32bit)
// 入口参数为要读取的FLASH的地址,返回值为uint32_t变量
//
uint32_t FLASH_EEPROM_Read(uint32_t addr)
{
uint32_t pValue = *(__IO uint32_t*)(addr);
return pValue;
}
//***************************************************************************************************
// 在FLASH中写一个结构体(usrflash 类型的结构体,这个类型在 flash.h 中定义的).
// 传入参数为要写入的地址和 usrflash 型结构体变量的取地址。
// 擦除时将擦除此地址所在的一整页。
// STM32F103C8 的 FLASH 中每页的大小为 1k, 写入时需注意数据量不要太大。
//
void FLASH_EEPROM_Write_struct(uint32_t addr, usrflash* userinfo)
{
// FLASH 擦除操作 --------------------------------------------------------------/
HAL_FLASH_Unlock(); //解锁
uint32_t PageError = 0; // 如果出现错误这个变量会被置为出错的FLASH地址
FLASH_EraseInitTypeDef EraseInitStruct; // 定义结构体
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; // Flash执行页面只做擦除操作
EraseInitStruct.PageAddress = addr; // 要擦除的地址
EraseInitStruct.NbPages = 1; // 要擦除的页数
if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) == HAL_OK); // 擦除此地址所在的一整页
// FLASH 写入操作 --------------------------------------------------------------/
for (uint8_t i = 0; i < sizeof(usrflash); i += 4) {
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr + i, *((__IO uint32_t*)(&userinfo->ID + i))) != HAL_OK) //这里的数据由于是结构体,需要从里面取值,一定要以第一个成员的地址开始偏移,不能使用结构体自身的地址来偏移,否则数据会出错
{
HAL_FLASH_Lock();
return;
}
}
HAL_FLASH_Lock();
}
//***************************************************************************************************
// 从FLASH中读取一个结构体(usrflash 类型的结构体,这个类型在 flash.h 中定义的).
// 入口参数为要读取的 FLASH 的地址和接收数据的 usrflash 型结构体变量的取地址。无返回值。
// 为了避免数据出错,读操作一定要和写操作对应,写是按双字写,读就要按双字读,否则就需要解决大小端的问题。
//
void FLASH_EEPROM_Read_struct(uint32_t addr, usrflash* userinfo)
{
for (uint8_t i = 0; i < sizeof(usrflash); i += 4) {
*((uint32_t*)(&userinfo->ID + i)) = *(__IO uint32_t*)(addr + i); //注意赋值的左边,必须要用结构体第一个成员的地址来偏移,双字偏移量是8
}
//这样获取的结构体内容,可以直接通过结构体变量或者结构体指针来访问了.
}
禁止转载到CSDN !
禁止转载到CSDN !
禁止转载到CSDN !
在FLASH中读写结构体的更多相关文章
- c++ 读写结构体到文件
可以使用fwrite()将一个结构体写入文件: fwrite(&some_struct,sizeof somestruct,1,fp);对应的fread函数可以再把它读出来,此处fwrite ...
- C++中的结构体
http://zhidao.baidu.com/link?url=8OYQSKV9mvSBc6Hkf9NsLQmipSge9VCZDJQGAZZs5PCBQ54UTmK98VRmAklEEAFYu7d ...
- C/C++中的结构体
结构体定义 结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构. 结构体作用 结构体和其他类型基础数据类型一样,例如int类型,char类型 只不过结构体可以做成 ...
- C语言中的结构体,结构体数组
C语言中的结构体是一个小难点,下面我们详细来讲一下:至于什么是结构体,结构体为什么会产生,我就不说了,原因很简单,但是要注意到是结构体也是连续存储的,但要注意的是结构体里面类型各异,所以必然会产生内存 ...
- 再识C中的结构体
在前面认识C中的结构体中我介绍了结构体的基础知识,下面通过这段代码来回顾一下: #include<stdio.h> #define LEN 20 struct Student{ //定义结 ...
- C语言中的结构体和C++中的结构体以及C++中类的区别
c++中结构体可以定义一个函数 C中的结构体和C++中结构体的不同之处:在C中的结构体只能自定义数据类型,结构体中不允许有函数,而C++中的结构体可以加入成员函数. C++中的结构体和类的异同: 一. ...
- 关于C语言中结构体中的结构体成员导致的字节对齐问题
关于结构体的字节对齐是什么,就不赘述,再此附上一篇文章,介绍字节对齐:http://www.linuxsong.org/2010/09/c-byte-alignment/ 这里的结构体字节对齐的数据类 ...
- C语言中处理结构体的原理
汇编中有几种寻址方式,分别是直接寻址:(ds:[idata]).寄存器间接寻址(ds:[bx]).寄存器相对寻址(ds:[bx + idata].ds:[bx + si])基址变址寻址(ds:[bx ...
- 结构体:探析C#文件方式读写结构体
最近直在研究Net Micro Framework字体文件(tinyfnt)由于tinyfnt文件头部有段描述数据所以很想 定义个结构体像VC样直接从文件中读出来省得用流个个解析很是麻烦 没有想到在中 ...
随机推荐
- Redisson实战-BloomFilter
1. 简介 布隆过滤器是防止缓存穿透的方案之一.布隆过滤器主要是解决大规模数据下不需要精确过滤的业务场景,如检查垃圾邮件地址,爬虫URL地址去重, 解决缓存穿透问题等. 布隆过滤器:在一个存在一定数量 ...
- NGINX-1.6.3部署详情
Nginx_沁贰百科 介绍 Nginx (engine x) 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器.Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Ra ...
- labuladong 05.16 微信直播
labuladong 05.16 微信直播 一.基础: 1.校招相关 1)扫盲 秋招:8-10月 提前批:7月 暑期实习:3-5月 非必须 2)关注公司前景,部门信息,公司财报 企查查,天眼查,多获取 ...
- ThreadPoolExecutor(线程池)的参数
构造函数 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit u ...
- net start mongodb 提示:发生系统错误 5,拒绝访问。
问题: net start mongodb 提示:发生系统错误 5,拒绝访问. 无法启动mongodb 服务. 解决办法: 右键cmd,选择以管理员身份运行即可
- 【springcloud alibaba】注册中心之nacos
1.为什么需要注册中心 1.1 没有注册中心会怎么样 1.2 注册中心提供什么功能以及解决什么问题 2.常用的微服务注册中心对比 3.案例项目父工程 4.nacos作为注册中心的使用 4.1 单机版的 ...
- js之DOM入门(慕课网学习笔记)
DOM简介 获得元素 document.getElementById('') 1.通过id获得元素内容 document.getElementsByTagName('') 2.通过标签获得元素内容 d ...
- 用vue的抽象组件来做一个防止img标签url为空或url地址出错的验证
看了网上文章学习了下vue的抽象组件,感觉就跟react的高阶组件一样的使用场景,只是更加面向vue的底层编程 ,网上介绍的抽象组件一般有2种用法,1 用来加防抖和节流 2 用来控制按钮是否允许点击做 ...
- Redis笔记(一)
redis:1.什么是缓存? mybatis一级缓存和二级缓存 mybatis的一级缓存存在哪? SqlSession,就不会再走数据库 什么情况下一级缓存会失效? 当被更新,删除的时候sqlsess ...
- Spring源码浅析之bean实例的创建过程(二)
在上一篇内容中,介绍了doGetBean方法的源码内容,知道了bean在创建的过程中,有三个范围,单例.多例.Scope,里面都使用到了createBean.下面本篇文章的主要内容,就是围绕creat ...