在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样直接从文件中读出来省得用流个个解析很是麻烦 没有想到在中 ...
随机推荐
- 跟我一起写 Makefile(四)
书写规则 ---- 规则包含两个部分,一个是依赖关系,一个是生成目标的方法. 在Makefile中,规则的顺序是很重要的,因为,Makefile中只应该有一个最终目标,其它的目标都是被这个目标所连带出 ...
- Mina的JMX支持
以下是一个增加了JMX支持的Mina Echo Server. package org.apache.mina.echoServer; import java.lang.management.Mana ...
- jd-gui或jad反编译工具bug
文件1:A.class------------2020-09-01日版本 文件2:A.class------------2020-09-02日版本,代码内容有变动. bug出现条件:文件1或文件2同目 ...
- elk 7.9.3 版本容器化部署
ELK-V7.9.3 部署 为什么用到ELK? 平时我们需要进行日志分析的时候,可以直接在日志文件中 grep.awk 就可以过滤出自己想要的信息及关键字,但规模较大的场景中,此方法极大的减低了效率, ...
- miniFTP项目实战二
项目简介: 在Linux环境下用C语言开发的Vsftpd的简化版本,拥有部分Vsftpd功能和相同的FTP协议,系统的主要架构采用多进程模型,每当有一个新的客户连接到达,主进程就会派生出一个ftp服务 ...
- NOIP 模拟 $27\; \rm 牛半仙的妹子Tree$
题解 \(by\;zj\varphi\) 很妙的虚树题. 考虑若没有操作 \(2\),那么直接记录一下扩散到它的最短时间和询问时间相比即可,可以当作一个树上最短路. 有 \(2\) 操作怎么办,将操作 ...
- PHP随手记2--获取随机n位不重复字符
定义一个函数返回26英文字母中n位不重复随机字符 基本思路是利用内置函数生成随机数,取出该位置字母之后将其删除,再进行下一次随机,最后实现字符串拼接就ok! 代码很简单,通俗易懂,直接上代码吧: 1 ...
- 【转】TCP的三次握手与四次挥手理解及面试题
转自:https://blog.csdn.net/qq_38950316/article/details/81087809 序列号seq:占4个字节,用来标记数据段的顺序,TCP把连接中发送的所有数据 ...
- Inject-APC (Ring3)
1 // APCInject.cpp : 定义控制台应用程序的入口点. 2 // 3 4 #include "stdafx.h" 5 #include "APCInjec ...
- 万能密码的SQL注入漏洞其PHP环境搭建及代码详解+防御手段
目录 环境搭建 session会话 环境搭建代码 创建数据库脚本 登录界面html: 查询数据库是否为正确的账号密码php代码 连接数据库php代码: 注销登录代码(即关闭session会话) 登录成 ...