在FLASH中读写结构体

注意事项

  1. 编程(写数据)地址要对齐

    写数据时,我们要指定写入的地址,如果写入地址为非对齐,则会出现编程对齐错误。

    比如遵循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中读写结构体的更多相关文章

  1. c++ 读写结构体到文件

    可以使用fwrite()将一个结构体写入文件:  fwrite(&some_struct,sizeof somestruct,1,fp);对应的fread函数可以再把它读出来,此处fwrite ...

  2. C++中的结构体

    http://zhidao.baidu.com/link?url=8OYQSKV9mvSBc6Hkf9NsLQmipSge9VCZDJQGAZZs5PCBQ54UTmK98VRmAklEEAFYu7d ...

  3. C/C++中的结构体

    结构体定义 结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构.   结构体作用 结构体和其他类型基础数据类型一样,例如int类型,char类型 只不过结构体可以做成 ...

  4. C语言中的结构体,结构体数组

    C语言中的结构体是一个小难点,下面我们详细来讲一下:至于什么是结构体,结构体为什么会产生,我就不说了,原因很简单,但是要注意到是结构体也是连续存储的,但要注意的是结构体里面类型各异,所以必然会产生内存 ...

  5. 再识C中的结构体

    在前面认识C中的结构体中我介绍了结构体的基础知识,下面通过这段代码来回顾一下: #include<stdio.h> #define LEN 20 struct Student{ //定义结 ...

  6. C语言中的结构体和C++中的结构体以及C++中类的区别

    c++中结构体可以定义一个函数 C中的结构体和C++中结构体的不同之处:在C中的结构体只能自定义数据类型,结构体中不允许有函数,而C++中的结构体可以加入成员函数. C++中的结构体和类的异同: 一. ...

  7. 关于C语言中结构体中的结构体成员导致的字节对齐问题

    关于结构体的字节对齐是什么,就不赘述,再此附上一篇文章,介绍字节对齐:http://www.linuxsong.org/2010/09/c-byte-alignment/ 这里的结构体字节对齐的数据类 ...

  8. C语言中处理结构体的原理

    汇编中有几种寻址方式,分别是直接寻址:(ds:[idata]).寄存器间接寻址(ds:[bx]).寄存器相对寻址(ds:[bx + idata].ds:[bx + si])基址变址寻址(ds:[bx ...

  9. 结构体:探析C#文件方式读写结构体

    最近直在研究Net Micro Framework字体文件(tinyfnt)由于tinyfnt文件头部有段描述数据所以很想 定义个结构体像VC样直接从文件中读出来省得用流个个解析很是麻烦 没有想到在中 ...

随机推荐

  1. Speed up Downloading Files on Linux

    Compared aria2c, axel and wget, aria2c is the best. It support multi-thread download (with "-s ...

  2. 官宣 .NET 6 预览版 6

    我们很高兴宣布.NET 6 预览版6问世啦.预览版6 是我们RC版发布之前的倒数第二个预览版. 我们将有两个RC版. 此版本本身相对较小,而预览版7会更大. 在那之后,我们将进行质量修复,直到11 月 ...

  3. Django ORM记录的增删改查结合web端

    模版语法分配变量 在views.py文件中定义一个视图函数show_data: def show_data(request): # 定义一个字典 并将它展示在前端HTML文件 user_dic = { ...

  4. 对象 绑定关系 隐藏属性 property 继承

    绑定方法两种: 1.绑定给对象的 class Student(): country = 'CHINA' def __init__(self,name,age): self.name = name se ...

  5. 旅游景点 Tourist Attractions 题解

    题面在这里 再次破了纪录,连做了3天... 让我们从头来一点一点分析 1.预处理 先看题面,乍一看貌似是个图论题,有n个点m条边,给定一些必须经过的点和强制经过顺序,求一条最短路 我们发现n和m都比较 ...

  6. jpa 指定字段内容按照顺序排序(orderBy when then)

    query.orderBy( criteriaBuilder.desc( criteriaBuilder.selectCase() .when(criteriaBuilder.equal(root.g ...

  7. ASP.NET Core Web服务器

    一.Http.sys HTTP.sys是仅能在Windows上运行的适用于ASP.NET Core的Web服务器. HTTP.sys运行在内核态中,极大减少了系统调用次数,运行效率很高:自带生存环境的 ...

  8. WPF 显示3D密集场景,堆场管理系统

    又好久好久没写博客了,这次接着上文https://www.cnblogs.com/CSSZBB/p/12785380.html,上文用WPF 的绘图功能,制作了一个伪3D的2.5D控件ThreeDBo ...

  9. 单例对象 (Singleton)设计模式

    单例的目的是为了保证运行时Singleton类只有唯一的一个实例,用于一些较大开销的操作. 饿汉式(没有线程安全问题): ' 由于使用static关键字进行了修饰,只能获取到一个对象,从而达到了单例, ...

  10. 【java web】过滤器filter

    一.过滤器简介 过滤器filter依赖于servlet容器 所谓过滤器顾名思义是用来过滤的,Java的过滤器能够为我们提供系统级别的过滤,也就是说,能过滤所有的web请求, 这一点,是拦截器无法做到的 ...