使用STM32F103C8T6 HAL库将数据存储在其内部Flash中

使用STM32F103C8T6 HAL库将数据存储在其内部Flash中的实验通常涉及几个关键步骤,这里提供一个不包含具体代码的概览:

1. 硬件准备

  • 确保STM32F103C8T6开发板正常工作,并连接好所有必要的电源和地线。
  • 无需外部Flash模块,因为我们将使用STM32的内部Flash。

2. 软件准备

  • STM32CubeMX:用于配置STM32的时钟、GPIO、中断等,并初始化HAL库。
  • Keil uVision5 或 STM32CubeIDE:作为编程平台,用于编写和编译代码。

3. STM32CubeMX配置

  • 新建项目并选择STM32F103C8T6芯片。
  • 配置系统时钟(如72MHz)。
  • 虽然对于内部Flash的写入通常不需要额外的硬件配置(如SPI、I2C等),但确保GPIO和其他外设配置正确,以符合你的应用需求。
  • 在STM32CubeMX中,通常不需要特别为内部Flash写入进行配置,因为HAL库提供了相关的函数。
  • 生成代码,包括HAL库初始化代码。

4. 编程步骤

在Keil uVision5或STM32CubeIDE中编写代码:

  • 包含必要的头文件:确保包含了STM32F1xx的HAL库头文件,特别是与Flash操作相关的头文件(如stm32f1xx_hal_flash.h)。
  • 初始化HAL库:在main函数中调用HAL_Init()来初始化HAL库,并根据需要调用SystemClock_Config()来配置系统时钟。
  • 编写Flash写入函数
    • 使用HAL库提供的Flash写入函数(如HAL_FLASH_Unlock()解锁Flash,HAL_FLASH_Program()写入数据,HAL_FLASH_Lock()锁定Flash)。
    • 注意:写入Flash前需要确保目标地址位于Flash的有效范围内,并且Flash已经被解锁。
    • 写入后,可能需要验证数据是否正确写入。
  • 编写Flash读取函数(如果需要):
    • 直接通过指针或数组访问Flash地址来读取数据。
  • main函数中调用Flash操作函数
    • 首先解锁Flash。
    • 写入一些测试数据到内部Flash。
    • (可选)读取并验证写入的数据。
    • 锁定Flash以防止意外写入。

5. 调试与测试

  • 编译项目并确保没有错误。
  • 下载程序到STM32F103C8T6开发板。
  • 使用调试工具(如J-Link, ST-Link等)和IDE的调试功能来观察Flash写入和读取操作的结果。
  • 验证Flash中的数据是否正确无误。

6. 注意事项

  • 写入Flash时,务必遵循Flash的写入规则,如先擦除再写入,因为Flash通常不能直接覆盖已有数据。
  • 考虑到Flash的寿命,避免频繁写入同一地址,尤其是小范围的数据更改。
  • 在写入重要数据前,最好进行备份,以防写入失败导致数据丢失。
  • 解锁Flash时,注意保护机制,避免意外写入或修改Flash中的关键数据(如中断向量表、启动代码等)。

在使用STM32F103C8T6的HAL库将数据存储到其内部Flash中时,你需要确保遵循Flash的编程和擦除规则。STM32F1系列的Flash通常具有页(Page)和扇区(Sector)的概念,其中数据可以按页写入,但必须先擦除整个扇区才能写入新数据。

以下是一个简化的示例代码,展示如何使用STM32F103C8T6的HAL库在内部Flash中写入和读取数据。请注意,这个示例可能需要根据你的具体需求进行调整。

首先,确保你的STM32CubeMX项目已经配置好了HAL库,并且生成了相应的初始化代码。

然后,在你的项目中添加以下函数:

#include "stm32f1xx_hal.h"  
  
// 假设我们要写入的数据起始地址是Flash的某个扇区的开始地址  
// 这里只是一个示例地址,你需要根据你的Flash布局来确定它  
#define FLASH_USER_START_ADDR   ((uint32_t)0x08008000) // 假设从Flash的某个扇区开始  
  
// 解锁Flash  
void FLASH_Unlock(void)  
{  
    HAL_FLASH_Unlock();  
}  
  
// 锁定Flash  
void FLASH_Lock(void)  
{  
    HAL_FLASH_Lock();  
}  
  
// 擦除Flash扇区  
// 注意:这个函数会擦除从FLASH_USER_START_ADDR开始的整个扇区  
void FLASH_Erase_Sector(void)  
{  
    FLASH_EraseInitTypeDef EraseInitStruct = {0};  
    uint32_t SectorError = 0;  
  
    // 获取FLASH_USER_START_ADDR所在的扇区号  
    // 这里需要根据你的Flash布局来计算扇区号,这里只是一个示例  
    // 假设FLASH_USER_START_ADDR是第一个扇区的开始地址  
    uint32_t SectorNumber = FLASH_SECTOR_0; // STM32F103C8T6的第一个扇区  
  
    // 配置擦除操作  
    EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;  
    EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3; // 3.0V to 3.6V  
    EraseInitStruct.Sector = SectorNumber;  
    EraseInitStruct.NbSectors = 1; // 擦除一个扇区  
  
    // 执行擦除操作  
    if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK)  
    {  
        // 擦除错误处理  
        // ...  
    }  
}  
  
// 写入数据到Flash  
// pData: 指向要写入的数据的指针  
// DataAddress: Flash中的目标地址  
// DataLength: 要写入的数据长度(字节)  
void FLASH_Write_Data(uint32_t DataAddress, uint8_t *pData, uint32_t DataLength)  
{  
    for (uint32_t i = 0; i < DataLength; i += 4) // 每次写入4字节(一个Word)  
    {  
        // 确保不会越界  
        if ((DataAddress + i) >= (FLASH_END_ADDR - 1))  
        {  
            break;  
        }  
  
        // 将数据转换为32位,以便写入Flash(如果数据量不是4的倍数,则最后可能需要特殊处理)  
        uint32_t word_data = *((uint32_t*)(pData + i));  
  
        // 写入Flash  
        if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, DataAddress + i, word_data) != HAL_OK)  
        {  
            // 写入错误处理  
            // ...  
        }  
    }  
}  
  
// 从Flash读取数据  
// pData: 指向存储读取数据的缓冲区的指针  
// DataAddress: Flash中的源地址  
// DataLength: 要读取的数据长度(字节)  
void FLASH_Read_Data(uint32_t DataAddress, uint8_t *pData, uint32_t DataLength)  
{  
    for (uint32_t i = 0; i < DataLength; i++)  
    {  
        // 确保不会越界  
        if (DataAddress + i >= FLASH_END_ADDR)  
        {  
            break;  
        }  
  
        // 读取Flash中的数据  
        pData[i] = *(uint8_t*)(DataAddress + i);  
    }  
}  
  
// 在main函数或其他适当的位置调用这些函数  
// ...

首先,FLASH_END_ADDR 需要被正确定义,它代表了 Flash 存储区的结束地址。然而,这个地址取决于你的 STM32F103C8T6 的具体 Flash 大小(通常是 64 KB,即 0x10000 字节)。对于 STM32F103C8T6,Flash 起始地址通常是 0x08000000,所以结束地址是 0x0800FFFF(如果你没有使用其他内存区域,比如 OTP 区域)。

但是,通常你不会使用到 Flash 的最后一个字节,因为 Flash 的编程和擦除操作需要一些空间来确保操作的正确性和安全性。因此,你可能希望将 FLASH_END_ADDR 设置为比实际 Flash 结尾稍早的地址。

另外,FLASH_SECTOR_0 是在 STM32 HAL 库中定义的,用于指定 Flash 的第一个扇区。这个值在不同的 STM32 系列中可能不同,但对于 STM32F103C8T6,它通常是正确的。

下面是更新后的代码示例,其中包含了 FLASH_END_ADDR 的定义,并做了一些小的调整:

#include "stm32f1xx_hal.h"  
  
// 定义 Flash 存储区的起始和结束地址  
// 注意:这里假设 Flash 大小为 64 KB,但通常不会使用到最后一个字节  
#define FLASH_USER_START_ADDR   ((uint32_t)0x08008000) // 假设从 Flash 的某个扇区开始  
#define FLASH_END_ADDR          ((uint32_t)0x0800FFFF) // Flash 结束地址(实际使用中可能需要调整)  
  
// ...(之前的函数保持不变)  
  
// 在 main 函数中调用 Flash 操作的示例  
int main(void)  
{  
    HAL_Init(); // 初始化 HAL 库  
    // ...(其他初始化代码,如 SystemClock_Config())  
  
    uint8_t testData[] = "Hello Flash!"; // 要写入 Flash 的测试数据  
    uint32_t dataLength = sizeof(testData);  
  
    // 解锁 Flash  
    FLASH_Unlock();  
  
    // 擦除 Flash 扇区(注意:这将删除该扇区内的所有数据!)  
    FLASH_Erase_Sector();  
  
    // 写入数据到 Flash  
    FLASH_Write_Data(FLASH_USER_START_ADDR, testData, dataLength);  
  
    // 锁定 Flash(可选,但在完成 Flash 操作后是个好习惯)  
    FLASH_Lock();  
  
    // 读取并验证数据(可选)  
    uint8_t readBuffer[dataLength];  
    FLASH_Read_Data(FLASH_USER_START_ADDR, readBuffer, dataLength);  
  
    // ...(在这里可以添加代码来验证 readBuffer 中的数据是否与 testData 相同)  
  
    // ...(主循环等其他代码)  
  
    while (1)  
    {  
        // 空闲循环  
    }  
}  
  
// ...(之前的函数定义保持不变)  
  
// 注意:在实际应用中,你可能需要添加更多的错误处理和边界检查来确保代码的健壮性。

请注意,上面的代码示例在擦除 Flash 扇区时没有进行扇区号的计算,而是直接使用了 FLASH_SECTOR_0。如果你的数据不是从 Flash 的第一个扇区开始写入的,你需要根据你的 Flash 布局来计算正确的扇区号。此外,如果你的数据跨越了多个扇区,你需要对每个扇区都执行擦除操作。

另外,请确保在调用 FLASH_Write_Data 函数之前,目标 Flash 地址(DataAddress)和长度(DataLength)是有效的,并且不会超出 Flash 的边界。同样,确保在调用 FLASH_Read_Data 时也是如此。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

科创工作室li

你的鼓励将是大学生的创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值