当前位置: 首页 > news >正文

FLash存储

FLash

  • 在嵌入式系统中,Flash 通常指的是微控制器中的闪存,它是一种非易失性存储器,用于存储程序代码(.bin和.hex)和一些常驻数据(静态数据),即便在掉电后数据也不会丢失。
  • Flash的操作通常通过HAL_FLASH系列函数进行,包括编程、擦除以及保护等功能。
  • Flash存储器可以用来实现Bootloader(引导加载程序),用于在系统启动时进行初步的硬件初始化,并可以选择性地更新应用程序代码。
  • Bootloader可以通过串口、USB或其他接口接收新的固件,并将其写入Flash中,实现远程升级。
  • 常用的一些函数
向指定FLash地址写入数据
HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
参数:FLASH_TypeProgram:指定编程类型(字节、半字或双字)。uint32_t Address:要编程的起始地址。uint32_t Data:要写入的数据。功能:擦除指定的Flash扇区或全部扇区。	
HAL_FLASH_Erase()
参数:FLASH_EraseInitTypeDef *pFlashEraseInit:指向包含擦除初始化参数的结构体指针。uint32_t *PagesError:指向一个数组,用于返回擦除失败的页号。功能:解锁Flash访问。
HAL_FLASH_Unlock()功能:锁定Flash访问。
HAL_FLASH_Lock()-----------自己编写的FLash的接口函数-------------------
#include "stm32f1xx_hal.h"  // 包含 STM32 HAL 库头文件
#include "flash-ops.h"      // 包含自定义的 flash 操作头文件/*每次写入 都是 4B,要求 data是4B对齐的,即len是4的整数倍
*/
int flash_ops_write(int addr, int *data, int len)  // 定义 flash 写操作函数
{int i;  // 循环变量int ret;  // 返回值HAL_StatusTypeDef status;  // HAL 库操作的状态值if ((len % 4) != 0) {  // 判断 len 是否是 4 的倍数int mode = len % 4;  // 计算多余的字节数len -= mode;  // 减去多余的字节数len += 4;  // 向上调整为 4 字节对齐}/*1 解锁*/HAL_FLASH_Unlock();  // 解锁 Flash,使能写操作/*2 擦除*/FLASH_EraseInitTypeDef f;  // 初始化 FLASH_EraseInitTypeDef 结构体f.TypeErase = FLASH_TYPEERASE_PAGES;  // 设置擦除类型为页面擦除f.PageAddress = addr;  // 设置要擦除的页面的起始地址f.NbPages = 1;  // 设置擦除的页数为 1uint32_t PageError = 0;  // 定义变量用于存储擦除时的错误码status = HAL_FLASHEx_Erase(&f, &PageError);  // 调用擦除函数,传入擦除配置if (status != HAL_OK) {  // 如果擦除失败ret = -12;  // 设置错误返回值为 -12goto end;  // 跳转到结束部分,跳过写入步骤}/*3 编程 烧写 */for (i = 0; i < len / 4; i += 1) {  // 循环按 4 字节写入数据HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr + i * 4, data[i]);  // 调用 HAL 库写入 4 字节的数据}ret = 0;  // 如果成功,设置返回值为 0end:    /*4 锁住*/HAL_FLASH_Lock();  // 锁住 Flash,禁止写操作return ret;  // 返回结果
}int flash_ops_read(int addr, void *data, int len)  // 定义 flash 读操作函数
{int i;  // 循环变量volatile char *ptaddr = (__IO char *)addr;  // 定义指向 flash 读地址的指针char *ptdata = (char *)data;  // 定义指向目标数据缓冲区的指针for (i = 0; i < len; i++) {  // 循环读取数据ptdata[i] = ptaddr[i];  // 将 flash 中的数据逐字节复制到输出缓冲区}return 0;  // 返回成功
}
-------------------.h文件-------------------
#ifndef __flash_ops_HH_H  // 防止重复包含头文件的预处理指令
#define __flash_ops_HH_H  // 定义宏以确保头文件只被包含一次/*STM32F103RCT6 有 256KB 的 Flash 空间地址范围从 0x08000000 到 0x0803FFFF每页的大小为 2KB我们预留了 6 个页供用户使用,每个页可保存 2KB 数据STM32F103RBT6 有 128KB 的 Flash 空间地址范围从 0x08000000 到 0x0801FFFF每页大小为 1KB下面是倒数几页的地址:0x0801F000  // 倒数第三页开始.....    0x0801F400  // 倒数第二页开始倒数第二页: 0x0801F800  // 倒数第二页开始倒数第一页: 0x0801FC00  // 倒数第一页开始
*/// 定义用于 STM32F103RBT6 的 Flash 页的起始地址(1KB 每页)
#define PAGE0_RBT6_ADDR  0x0801F000  // 倒数第三页地址
#define PAGE1_RBT6_ADDR  0x0801F400  // 倒数第二页地址
#define PAGE2_RBT6_ADDR  0x0801F800  // 倒数第一页地址
#define PAGE3_RBT6_ADDR  0x0801FC00  // 最后一页地址// 定义通用 Flash 页的地址
#define PAGET_ADDR  0x08007000  // 通用的 Flash 页地址// 定义用于 STM32F103RCT6 的 Flash 页的起始地址(2KB 每页)
#define PAGE0_RCT6_ADDR  0x0803D000  // 倒数第六页地址
#define PAGE1_RCT6_ADDR  0x0803D800  // 倒数第五页地址
#define PAGE2_RCT6_ADDR  0x0803E000  // 倒数第四页地址
#define PAGE3_RCT6_ADDR  0x0803E800  // 倒数第三页地址
#define PAGE4_RCT6_ADDR  0x0803F000  // 倒数第二页地址
#define PAGE5_RCT6_ADDR  0x0803F800  // 倒数第一页地址// 函数声明:用于将数据写入指定 Flash 地址
int flash_ops_write(int addr, int *data, int len);// 函数声明:用于从指定 Flash 地址读取数据
int flash_ops_read(int addr, void *data, int len);#endif  // 结束头文件包含保护
  • 代码示例
#include "main.h"  // 包含主头文件
#include "flash-ops.h"  // 包含flash操作头文件// 定义一个结构体usrinfo,用于存储用户的WiFi信息和用户凭证
struct usrinfo{char wifiname[32];  // WiFi名称,最大长度32字节char wifipasswd[16];  // WiFi密码,最大长度16字节char usrname[16];  // 用户名,最大长度16字节char usrpasswd[8];  // 用户密码,最大长度8字节long flags;  // 一个标志位,可以用于存储状态信息
};ADC_HandleTypeDef hadc1;  // ADC1的句柄,用于配置和管理ADC的操作
RTC_HandleTypeDef hrtc;  // RTC的句柄,用于配置和管理RTC的操作
UART_HandleTypeDef huart1;  // UART1的句柄,用于配置和管理UART1的操作// 函数原型声明
void SystemClock_Config(void);  // 系统时钟配置函数
static void MX_GPIO_Init(void);  // GPIO初始化函数
static void MX_ADC1_Init(void);  // ADC1初始化函数
static void MX_USART1_UART_Init(void);  // USART1 UART初始化函数
static void MX_RTC_Init(void);  // RTC初始化函数// 重定向printf函数,通过串口发送数据
int __io_putchar(int ch)  
{HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);  // 通过UART1发送一个字符return ch;  // 返回发送的字符
}// 主函数
int main(void)
{HAL_Init();  // 初始化HAL库,复位所有外设,配置Flash接口和Systick定时器SystemClock_Config();  // 配置系统时钟MX_GPIO_Init();  // 初始化GPIOMX_ADC1_Init();  // 初始化ADC1MX_USART1_UART_Init();  // 初始化UART1MX_RTC_Init();  // 初始化RTC// 初始化结构体usrinfo,并赋初始值struct usrinfo info;info.flags = 10086;  // 设置flags值为10086strcpy(info.wifiname, "haiyangxing");  // 将WiFi名称设为 "haiyangxing"strcpy(info.wifipasswd, "12345678");  // 将WiFi密码设为 "12345678"strcpy(info.usrname, "xiaowang");  // 将用户名设为 "xiaowang"strcpy(info.usrpasswd, "123456");  // 将用户密码设为 "123456"flash_ops_write(PAGE4_RCT6_ADDR, &info, sizeof(info));  // 将info结构体数据写入Flash的Page4中memset(&info, 0, sizeof(info));  // 清空info结构体的数据flash_ops_read(PAGE4_RCT6_ADDR, &info, sizeof(info));  // 从Flash的Page4中读取数据到info结构体中// 无限循环while (1){// 通过UART1输出WiFi和用户信息,每秒输出一次printf("wifi=%s pass=%s username=%s usrpasswd=%s flags=%d\r\n",info.wifiname, info.wifipasswd, info.usrname, info.usrpasswd, info.flags);HAL_Delay(1000);  // 延迟1秒}
}

http://www.mrgr.cn/news/26733.html

相关文章:

  • 下一代 AI 教育:知识图谱RAG + 多智能体,听老师的话没前途,让老师听你的才是正道
  • Android Studio:驱动高效开发的全方位智能平台
  • Java wrapperr打包springboot项目到linux和Windows
  • YOLOv5改进 | 模块缝合 | C3 融合Self-Calibrated Convolutions丰富特征图【CVPR2020】
  • Python-简介
  • Web 安全基础教程:从零基础入门到精通
  • B站宋红康JAVA基础视频教程(chapter14数据结构与集合源码)
  • 2024年9月中国数据库排行榜:openGauss系多点开花,根社区优势明显
  • 【ArcGISProSDK】初识
  • 刻意练习:舒尔特方格提升专注力
  • 并行程序设计基础——并行I/O(4)
  • Redhat 7,8系(复刻系列) 一键部署Oracle21-xe rpm
  • Android 用线程池实现一个简单的任务队列(Kotlin)
  • element实现动态路由+面包屑
  • python版本dikstra堆优化
  • 【C++】c++的继承
  • 【数据仓库】数据仓库常见的数据模型——维度模型
  • SAP B1 Web Client MS Teams App集成连载二:安装Install/升级Upgrade/卸载Uninstall
  • Mysql | 知识 | 理解是怎么加锁的
  • SpringBoot