大家好,欢迎来到IT知识分享网。
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; // 设置擦除的页数为 1 uint32_t PageError = 0; // 定义变量用于存储擦除时的错误码 status = HAL_FLASHEx_Erase(&f, &PageError); // 调用擦除函数,传入擦除配置 if (status != HAL_OK) {
// 如果擦除失败 ret = -12; // 设置错误返回值为 -12 goto 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; // 如果成功,设置返回值为 0 end: /*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 空间 地址范围从 0x0 到 0x0803FFFF 每页的大小为 2KB 我们预留了 6 个页供用户使用,每个页可保存 2KB 数据 STM32F103RBT6 有 128KB 的 Flash 空间 地址范围从 0x0 到 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 0x0 // 通用的 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(); // 初始化GPIO MX_ADC1_Init(); // 初始化ADC1 MX_USART1_UART_Init(); // 初始化UART1 MX_RTC_Init(); // 初始化RTC // 初始化结构体usrinfo,并赋初始值 struct usrinfo info; info.flags = 10086; // 设置flags值为10086 strcpy(info.wifiname, "haiyangxing"); // 将WiFi名称设为 "haiyangxing" strcpy(info.wifipasswd, ""); // 将WiFi密码设为 "" strcpy(info.usrname, "xiaowang"); // 将用户名设为 "xiaowang" strcpy(info.usrpasswd, ""); // 将用户密码设为 "" 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秒 } }
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/116019.html