STM32 在flash中存储float数据

本文详细介绍了计算机中浮点数(Float类型)的存储结构,包括符号、底数和指数部分,并按照IEEE-754标准进行解析。同时,讲解了在Flash中存储和读取浮点数的两种方法,一种是通过指针转换,另一种是利用共用体。这些知识对于嵌入式系统和底层编程至关重要。

Float 类型数字在计算机中用4个字节存储,遵循IEEE-754格式标准:

Float 数据符号部分(S)底数部分(M)指数部分(E)
说明

0 表示正

1 表示负

使用二进制数来表示此浮点数的实际值,底数部分实际是占用24 bit的一个值,但是最高位省去不存储,在存储中占23 bit科学技术法。

 占用8 bit的二进制数,可表示数值范围是0~255。因为指数可正可负,所以按照IEEE规定计算的指数减去127才是真正的指数,float类型的指数真正范围是-127到128。

所以格式为:SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM

在flash中存取float数据有两种方式,第一种使用指针的方式

把float数据存储到flash中

float data;

uint32_t temp;

temp = *(uint32_t *)&data;

Flash_WriteWordData(Flash_Save_Adder, temp);


从flash中读取出来

Flash_ReadWordData(Flash_Write_Adder, temp);

data = *(float *)&temp;

第二种共用体,利用共用体共用一段内存的特性进行存储

float data;
union
{

    float a;

    uint32_t b;

}temp;

temp.a = data;

Flash_WriteWordData(Flash_Save_Adder, temp.b);


从flash中读取出来

Flash_ReadWordData(Flash_Write_Adder, temp.b);

data = temp.a;



原文链接:https://blog.youkuaiyun.com/qq_41836400/article/details/121964054

<think>我们正在讨论STM32Flash读取数据的问题。根据提供的引用,特别是引用[3]和[4],我们可以得到一些示例代码和方法。引用[3]提供了一个读取数据的函数示例:```cvoidprintFlashTest(void){uint32_ttemp=*(__IOuint32_t*)(addr);printf("addr:0x%x,data:0x%x\r\n",addr,temp);}```这里,`addr`是要读取的Flash地址,使用直接指针访问的方式读取一个32位的数据。引用[4]中则使用了函数`FlashReadBuff`来读取一段数据:```cFlashReadBuff(DEVICE_INFO_ADDRESS+sizeof(FlashTest),FlashRBuff,255);//从Flash中读取数```这个函数可能是用户自己封装的,用于从指定地址读取多个字节到缓冲区。因此,从Flash读取数据的基本方法有两种:1.直接通过指针访问:适用于读取固定大小的数据(如32位、16位或8位)。2.通过函数读取一段数据:通常需要自己封装一个函数,使用循环逐个读取。下面我们详细说明这两种方法,并给出示例代码。###方法1:直接指针访问这种方法简单直接,适用于读取单个变量或已知长度的数组。注意,读取的数据长度可以是8位、16位、32位,取决于指针类型。示例代码(读取32数据):```c//假设要读取的地址为0x0800F000uint32_taddress=0x0800F000;uint32_tdata=*(__IOuint32_t*)address;```如果要读取一个字节:```cuint8_tdata_byte=*(__IOuint8_t*)address;```###方法2:读取一段数据(自定义函数)我们可以编写一个函数,从指定地址读取多个字节到缓冲区。注意,由于Flash通常以32位或16位访问,但我们可以按字节读取(实际上,在C语言中,我们可以按任意宽度读取,但要注意对齐问题)。示例函数(按字节读取):```cvoidFlash_ReadBytes(uint32_taddress,uint8_t*buffer,uint32_tsize){for(uint32_ti=0;i<size;i++){buffer[i]=*(__IOuint8_t*)(address+i);}}```或者按32位读取(效率更高,但要求地址4字节对齐,且size是4的倍数):```cvoidFlash_ReadWords(uint32_taddress,uint32_t*buffer,uint32_tword_count){for(uint32_ti=0;i<word_count;i++){buffer[i]=*(__IOuint32_t*)(address+(i*4));}}```###注意事项1.**地址对齐**:读取32数据时,地址最好是4字节对齐,否则可能会引发硬件错误(取决于芯片)。2.**安全区域**:读取Flash时,要确保读取的地址在Flash地址范围内,并且避开程序代码区域(通常使用Flash的末尾部分)。具体可参考引用[2]。3.**读取前不需要解锁**:读取Flash不需要解锁,只有写入和擦除才需要解锁(引用[3]中写入操作有解锁步骤,但读取没有)。###完整示例假设我们要从地址0x0800F000读取10个字节的数据,并打印出来。```c#include"stm32f1xx_hal.h"//根据实际型号包含对应的HAL库#defineFLASH_READ_ADDRESS0x0800F000voidread_and_print_data(void){uint8_tbuffer[10];//按字节读取for(inti=0;i<10;i++){buffer[i]=*(__IOuint8_t*)(FLASH_READ_ADDRESS+i);}//打印读取的数据printf("DatareadfromFlash:");for(inti=0;i<10;i++){printf("%02X",buffer[i]);}printf("\r\n");}```或者使用自定义的读取函数:```cvoidFlash_ReadBytes(uint32_taddress,uint8_t*buffer,uint32_tsize){for(uint32_ti=0;i<size;i++){buffer[i]=*(__IOuint8_t*)(address+i);}}voidread_and_print_data(void){uint8_tbuffer[10];Flash_ReadBytes(FLASH_READ_ADDRESS,buffer,10);//打印printf("DatareadfromFlash:");for(inti=0;i<10;i++){printf("%02X",buffer[i]);}printf("\r\n");}```###总结读取Flash数据STM32中非常简单,只需通过指针访问即可。但要注意地址的选择,避免覆盖程序代码区域。读取操作不需要解锁Flash,这是与写入操作的重要区别。§§相关问题§§1.在STM32中,如何安全地选择Flash地址来存储数据?2.写入Flash数据前为什么需要擦除?擦除操作是如何进行的?3.如何验证从Flash读取的数据是否正确?4.在STM32中,Flash读写操作有哪些常见的错误?如何避免?</think>### STM32Flash读取数据的方法及示例代码 在STM32中从Flash读取数据是直接访问内存地址的过程,不需要解锁或特殊初始化(与写入不同)。以下是具体方法和示例: #### 📌 读取数据的关键步骤 1. **确定安全地址** 避开代码存储区(通常选择Flash末尾区域)[^2]。 计算地址公式: $$ \text{FlashEnd} = \text{FlashStart} + \text{FlashSize} - \text{ReservedSpace} $$ (例如:STM32F4系列Flash起始地址为0x08000000) 2. **直接指针访问** 通过内存映射读取数据,无需调用HAL库函数[^3]。 #### ⚙️ 示例代码(基于HAL库) ##### 1. 读取单个32数据 ```c // 定义安全地址(示例:使用倒数第2页) #define FLASH_DATA_ADDR 0x0800F000 uint32_t read_single_word(void) { // 直接通过指针访问Flash地址 return *(__IO uint32_t*)(FLASH_DATA_ADDR); } ``` ##### 2. 读取字节数组 ```c void read_byte_array(uint8_t* buffer, uint32_t size) { uint8_t* flash_ptr = (uint8_t*)FLASH_DATA_ADDR; for(uint32_t i = 0; i < size; i++) { buffer[i] = flash_ptr[i]; // 逐字节复制 } } // 调用示例: uint8_t received_data[128]; read_byte_array(received_data, sizeof(received_data)); ``` ##### 3. 读取结构体数据 ```c typedef struct { uint32_t id; float sensor_calib; char device_id[16]; } DeviceConfig; DeviceConfig read_config(void) { return *(DeviceConfig*)FLASH_DATA_ADDR; // 直接类型转换 } ``` #### ⚠️ 重要注意事项 1. **地址对齐** 32数据需4字节对齐地址(如0x0800F000),16位数据需2字节对齐。 2. **内存屏障** 在频繁读取时可添加内存屏障: ```c __DSB(); // 数据同步屏障 ``` 3. **访问宽度** 根据数据长度选择指针类型: - 8位:`*(__IO uint8_t*)addr` - 16位:`*(__IO uint16_t*)addr` - 32位:`*(__IO uint32_t*)addr` 4. **避免写入区域** 读取时确保该区域未被编程/擦除操作占用[^1]。 #### 🔍 验证数据完整性 建议添加校验机制: ```c // CRC32校验示例 uint32_t calculate_crc(uint8_t* data, uint32_t len) { uint32_t crc = 0xFFFFFFFF; // ...CRC计算逻辑... return crc; } // 读取时校验 if(calculate_crc(received_data, sizeof(received_data)) == stored_crc) { // 数据有效 } ``` > **关键区别**:与写入操作不同,读取Flash**不需要解锁**(`HAL_FLASH_Unlock()`)或擦除步骤[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值