基于PY32F403开发板学习(2-读写内部FLASH)

一、介绍:

PY32F403的FLASH内部空间是384K,代码参考了STM32的代码(具体是哪位大哥的不记得),同时做小调整,修改成PY单片机的能够直接使用的代码,只要用HAL库都能用,只需要修改一点内存存放位置即可,

flash内容暂时设定为380K-384K 的内存空间中。

修改内存的参数方式就是先更新结构体内容。然后调用my_flash_write的接口函数即可。

末尾有整个程序的下载链接。。。

二、主要程序

#include "flash.h"

savedata_t save_param;

/**
 * @brief  向指定闪存地址写入数据
 * @param  addr 要写入数据的起始闪存地址
 * @param  Data 指向要写入数据数组的指针,数据类型为 uint32_t
 * @param  L 要写入的 uint32_t 数据的数量
 * @retval 无
 */
void WriteFlash(uint32_t addr,uint32_t *Data,uint32_t L)
{
    uint32_t i = 0;
    // 解锁闪存,允许对闪存进行擦除和写入操作
    HAL_FLASH_Unlock();

    // 等待上一次闪存操作完成,超时时间为 FLASH_TIMEOUT_VALUE
    FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);

    // 定义闪存擦除初始化结构体,用于配置擦除参数
    FLASH_EraseInitTypeDef FlashSet;
    // 设置擦除类型为页擦除
    FlashSet.TypeErase = FLASH_TYPEERASE_PAGEERASE;
    // 设置要擦除的闪存页起始地址
    FlashSet.PageAddress = addr;
    // 设置要擦除的页数为 1 页
    FlashSet.NbPages = 1;
    // 用于存储擦除过程中可能出现的页错误信息
    uint32_t PageError = 0;

    // 底层 HAL 库可能存在 BUG,擦除前需要先解锁
    __HAL_UNLOCK(&pFlash);
    // 执行闪存页擦除操作
    int ret = HAL_FLASHEx_Erase(&FlashSet, &PageError);

    // 检查擦除操作是否成功
    if(ret != HAL_OK) {
        // 若擦除失败,打印错误信息
        printf("Erase Error[%d]\n",ret);
    }

    // 循环将数据写入闪存
    for(i = 0; i < L; i++) {
        // 按页编程方式将数据写入闪存指定地址
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_PAGE, addr + 4 * i, &Data[i]);
    }

    // 锁定闪存,防止意外修改
    HAL_FLASH_Lock();
}

/**
 * @brief  从指定闪存地址读取数据
 * @param  address 要读取数据的起始闪存地址
 * @param  data 指向用于存储读取数据的数组指针,数据类型为 uint32_t
 * @param  length 要读取的 uint32_t 数据的数量
 * @retval 无
 */
void Flash_Read(uint32_t address, uint32_t *data, uint16_t length)
{
    // 定义循环计数器,用于遍历要读取的数据数量
    uint16_t i;
    // 循环读取指定长度的数据
    for (i = 0; i < length; i++) {
        // 通过指针访问的方式,从指定闪存地址读取一个 uint32_t 数据
        // __IO 是一个宏,通常用于标记该变量为易变的,告诉编译器不要对其进行过度优化
        // (address + (i * 4)) 计算当前要读取数据的地址,每个 uint32_t 占 4 字节
        data[i] = *(__IO uint32_t *)(address + (i * 4)); 
    }
}

/**
 * @brief  将 save_param 结构体数据写入闪存
 * @note   该函数会先将结构体数据复制到 uint32_t 数组,再调用 WriteFlash 函数写入闪存
 * @retval 无
 */
void my_flash_write(void)
{
    // 打印当前函数名,用于调试,方便确认函数是否被调用
    printf("%s\n",__func__);

    // 向上取整计算所需的 uint32_t 元素数量,确保数组有足够空间存储 savedata_t 结构体数据
    size_t num_elements = (sizeof(savedata_t) + sizeof(uint32_t) - 1) / sizeof(uint32_t);

    // 定义一个 uint32_t 类型的数组,用于存储要写入闪存的结构体数据
    uint32_t flash_data[num_elements];

    // 将 save_param 结构体的数据复制到 flash_data 数组中
    // sizeof(savedata_t) 表示要复制的数据大小
    memcpy(flash_data, &save_param, sizeof(savedata_t));

    // 调用 WriteFlash 函数,将 flash_data 数组中的数据写入指定的闪存地址
    // FLASH_SAVE_ADDR 为闪存写入的起始地址
    // num_elements 为要写入的 uint32_t 数据的数量
    WriteFlash(FLASH_SAVE_ADDR, flash_data, num_elements);
}

/**
 * @brief  从闪存中读取数据到 save_param 结构体
 * @note   该函数会先从指定闪存地址读取数据到 uint32_t 数组,再将数组数据复制到 save_param 结构体
 * @retval 无
 */
void my_flash_read(void)
{
    // 向上取整计算所需的 uint32_t 元素数量,确保数组有足够空间存储 savedata_t 结构体数据
    size_t num_elements = (sizeof(savedata_t) + sizeof(uint32_t) - 1) / sizeof(uint32_t);
    // 定义一个 uint32_t 类型的数组,用于存储从闪存读取的数据
    uint32_t flash_data_read[num_elements];
    // 调用 Flash_Read 函数,从指定闪存地址 FLASH_SAVE_ADDR 读取 num_elements 个 uint32_t 数据到 flash_data_read 数组
    Flash_Read(FLASH_SAVE_ADDR, flash_data_read, num_elements);
    // 将 flash_data_read 数组中的数据复制到 save_param 结构体中
    // sizeof(savedata_t) 表示要复制的数据大小
    memcpy(&save_param, flash_data_read, sizeof(savedata_t));
}

/**
 * @brief  初始化 save_param 结构体
 * @note   将 save_param 结构体的所有成员初始化为默认值
 * @retval 无
 */
void save_param_init(void)
{
	memset(&save_param,0,sizeof(save_param));
	save_param.verif_code = 0x55AA;
	sprintf((char *)save_param.version,"MAGEAA");
	sprintf((char *)save_param.password,"123456");
}

/**
 * @brief  验证闪存中存储的参数版本信息
 * @note   从闪存读取参数,检查版本验证码是否正确,若不正确则初始化参数并写入闪存
 * @retval 无
 */
void flash_verify(void)
{
	my_flash_read();
	/*判断版本是否为相同*/
	if(save_param.verif_code != 0x55AA) {
		save_param_init();
		my_flash_write();
	}
	flash_display_param();
	
}

/**
 * @brief  显示闪存中存储的版本和密码信息
 * @note   该函数会先从闪存读取最新的参数信息,然后打印版本和密码
 * @retval 无
 */
void flash_display_param(void)
{
	my_flash_read();
	printf("version[%s]\n",save_param.version);
	printf("password=[%s]\n",save_param.password);	
}

三、头文件代码

#ifndef __FLASH_H
#define __FLASH_H

#include "py32f4xx_hal.h"
#include "main.h"

#define FLASH_SAVE_ADDR  (0x0805F000) 		// 保存数据的起始地址 380K~384K

typedef struct {
	uint32_t 	verif_code;
	uint8_t 	version[7];
	uint8_t 	password[7];
} __attribute__((packed)) savedata_t;					

extern savedata_t save_param;

void WriteFlash(uint32_t addr,uint32_t *Data,uint32_t L);
void my_flash_write(void);
void my_flash_read(void);
void save_param_init(void);
void flash_verify(void);
void flash_display_param(void);

#endif

四、主程序代码

实现功能:

1、开机验证验证码,验证不通过,则进行程序参数初始化。

2、按键0按下LED0灯状态跳转,并且修改结构体密码为999999。按复位按钮观察按键内部参数是否正常更新。

3、按键1按下LED1灯状态跳转,并且修改结构体密码为666666。按复位按钮观察按键内部参数是否正常更新。

int main(void)
{
	
	_system_clock_config();
	
	HAL_Init(); 							/*hal库初始化*/
	usart_init(115200);				        /*UART1初始化,PA9,PA10*/
	led_init();								/*LED外设初始化*/
	key_init();								/*按键外设初始化*/
	printf("Hello World!\n");
	uint8_t key_val = 0;
	flash_verify();
	
	while(1){
		key_val = key_scan(0);
		if(key_val) printf("keyval=[%d]\n",key_val);
		switch(key_val){
			case KEY0_PRES:
				LED0_TOGGLE(); 
				sprintf((char *)save_param.password,"999999");
				my_flash_write();
				break;
			
			case KEY1_PRES:
				LED1_TOGGLE(); 
				sprintf((char *)save_param.password,"666666");
				my_flash_write();
				break;
			
			defult:
				break;
		}
	}
	return 0;
}

五、打印结果

可以看见开机初始时,密码被写入123456,然后在按下按键2后,密码被修改为666666,重启观察也是666666.也就写入flash内了,掉电也能给生效。

同理,按按键1时,密码修改为999999,重启后也是生效的。所以这个实验是成功的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值