STM32基础/通用参数读写函数

通用参数读写函数

以下是一个基于 STM32 的通用参数读写函数的示例代码,实现了对不同数据类型参数在指定地址的读写操作:

#include "stm32f10x.h"

// 解锁 Flash
void FLASH_Unlock(void);
// 锁定 Flash
void FLASH_Lock(void);
// 擦除页
FLASH_Status FLASH_ErasePage(uint32_t Page_Address);

// 写参数(支持不同数据类型)
void writeParameter(void *data, uint32_t address, uint8_t dataType)
{
    FLASH_Unlock();
    FLASH_ErasePage(address);
    FLASH_Status status;

    switch (dataType)
    {
        case 1:
        {
            uint8_t *value8 = (uint8_t *)data;
            *(__IO uint8_t *)address = *value8;
            break;
        }
        case 2:
        {
            uint16_t *value16 = (uint16_t *)data;
            *(__IO uint16_t *)address = *value16;
            break;
        }
        case 4:
        {
            uint32_t *value32 = (uint32_t *)data;
            *(__IO uint32_t *)address = *value32;
            break;
        }
        default:
            break;
    }
    FLASH_Lock();
}

// 读参数(支持不同数据类型)
void readParameter(void *data, uint32_t address, uint8_t dataType)
{
    switch (dataType)
    {
        case 1:
        {
            uint8_t *value8 = (uint8_t *)data;
            *value8 = *(__IO uint8_t *)address;
            break;
        }
        case 2:
        {
            uint16_t *value16 = (uint16_t *)data;
            *value16 = *(__IO uint16_t *)address;
            break;
        }
        case 4:
        {
            uint32_t *value32 = (uint32_t *)data;
            *value32 = *(__IO uint32_t *)address;
            break;
        }
        default:
            break;
    }
}

以下是对代码的解释:

  1. 函数功能

    • writeParameter函数:用于将不同数据类型的参数写入到 STM32 的内部 Flash 中。它接受三个参数,data是要写入数据的指针,address是写入数据的目标 Flash 地址,dataType表示数据类型(1 表示 8 位,2 表示 16 位,4 表示 32 位)。
    • readParameter函数:用于从 STM32 的内部 Flash 中读取不同数据类型的参数。它也接受三个参数,data是用于存储读取数据的指针,address是读取数据的源 Flash 地址,dataType的含义与写入函数相同。
  2. Flash 操作流程

    • writeParameter函数中,首先解锁 Flash,然后执行页擦除操作,这是因为 Flash 的编程特性决定了写入操作前需要先擦除相应的存储区域。接着根据dataType的值,将数据按照相应的长度写入 Flash 中。最后锁定 Flash 以确保数据的安全性。
    • readParameter函数相对简单,它根据dataType的值,从指定的 Flash 地址读取相应长度的数据,并将数据存储到由data指向的变量中。

以下是一个简单的使用示例:

int main()
{
    uint8_t byteData = 0x55;
    uint16_t wordData = 0x1234;
    uint32_t dwordData = 0x12345678;

    // 写入不同类型的数据
    writeParameter(&byteData, 0x08008000, 1);
    writeParameter(&wordData, 0x08008002, 2);
    writeParameter(&dwordData, 0x08008004, 4);

    // 读取不同类型的数据
    uint8_t readByte;
    uint16_t readWord;
    uint32_t readDword;

    readParameter(&readByte, 0x08008000, 1);
    readParameter(&readWord, 0x08008002, 2);
    readParameter(&readDword, 0x08008004, 4);

    return 0;
}

在这个示例中,首先定义了不同数据类型的变量(8 位、16 位和 32 位),然后使用writeParameter函数将这些变量的值分别写入 Flash 的不同地址。接着,定义了新的变量用于存储读取的数据,并使用readParameter函数从 Flash 中读取相应的数据。

将不同数据类型的读写操作改为结构体形式的代码:

#include "stm32f10x.h"

// 解锁 Flash
void FLASH_Unlock(void);
// 锁定 Flash
void FLASH_Lock(void);
// 擦除页
FLASH_Status FLASH_ErasePage(uint32_t Page_Address);

// 定义一个结构体用于存储不同类型的数据
typedef struct {
    uint8_t byteData;
    uint16_t wordData;
    uint32_t dwordData;
} Parameters;

// 写参数(使用结构体)
void writeParameters(Parameters *params, uint32_t address)
{
    FLASH_Unlock();
    FLASH_ErasePage(address);

    *(__IO uint8_t *)(address) = params->byteData;
    *(__IO uint16_t *)(address + 1) = params->wordData;
    *(__IO uint32_t *)(address + 3) = params->dwordData;

    FLASH_Lock();
}

// 读参数(使用结构体)
void readParameters(Parameters *params, uint32_t address)
{
    params->byteData = *(__IO uint8_t *)(address);
    params->wordData = *(__IO uint16_t *)(address + 1);
    params->dwordData = *(__IO uint32_t *)(address + 3);
}

以下是对代码的解释:

  1. 结构体定义

    • 定义了一个名为Parameters的结构体,其中包含了uint8_t类型的byteDatauint16_t类型的wordDatauint32_t类型的dwordData三个成员,用于存储不同长度的数据。
  2. 写参数函数

    • writeParameters函数接受一个指向Parameters结构体的指针params和一个uint32_t类型的address作为参数。
    • 在函数内部,首先解锁 Flash,然后擦除指定地址所在的页。
    • 接着按照顺序将结构体中的数据写入 Flash 中,注意写入的地址需要根据数据的长度进行偏移(uint8_t占 1 个字节,uint16_t占 2 个字节,从address + 1开始写,uint32_taddress + 3开始写)。
    • 最后锁定 Flash。
  3. 读参数函数

    • readParameters函数同样接受一个指向Parameters结构体的指针params和一个uint32_t类型的address作为参数。
    • 函数内部直接从指定地址按照数据长度依次读取数据到结构体的相应成员中。

以下是一个使用示例:

int main()
{
    Parameters params;
    params.byteData = 0x55;
    params.wordData = 0x1234;
    params.dwordData = 0x12345678;

    // 写入结构体数据
    writeParameters(&params, 0x08008000);

    Parameters readParams;
    // 读取结构体数据
    readParameters(&readParams, 0x08008000);

    return 0;
}

在这个示例中,首先创建了一个Parameters结构体变量params,并对其成员进行赋值。然后使用writeParameters函数将结构体中的数据写入 Flash 中。接着创建了另一个Parameters结构体变量readParams,并使用readParameters函数从 Flash 中读取数据到这个结构体中。

以下是在结构体中添加新成员变量时修改参数读写函数的步骤:

一、添加新成员变量到结构体

假设原来的结构体为:

typedef struct {
    uint8_t byteData;
    uint16_t wordData;
    uint32_t dwordData;
} Parameters;

  1. 考虑数据对齐:在定义结构体时,注意数据的对齐方式。一些处理器对数据的对齐有要求,例如在某些架构下,int类型的数据可能需要 4 字节对齐。可以使用编译器的#pragma pack指令来控制结构体的对齐方式,确保结构体在内存中的布局符合预期,从而保证数据完整性。
#pragma pack(1)
typedef struct {
    uint8_t byteData;
    uint16_t wordData;
    uint32_t dwordData;
} Parameters;
#pragma pack()
  • 在上述示例中,#pragma pack(1)强制结构体Parameters的成员按照 1 字节对齐,这样结构体的大小就是成员变量大小之和(1 + 2+ 4 = 7 字节)。#pragma pack()用于恢复默认的对齐方式。

现在添加一个新的uint32_t类型成员变量newData,结构体变为:

typedef struct {
    uint8_t byteData;
    uint16_t wordData;
    uint32_t dwordData;
    uint32_t newData;
} Parameters;

二、修改写参数函数

  1. 调整写入顺序和地址偏移

    • writeParameters函数中,需要考虑新成员变量在结构体中的位置以及数据长度,来调整写入的顺序和地址偏移。
    • 由于前面三个成员变量(byteData占 1 字节,wordData占 2 字节,dwordData占 4 字节)总共占用了 7 字节,所以新的成员变量newData应该从address + 7开始写入。
  2. 更新写入操作代码

    • 原有的写入操作是:
void writeParameters(Parameters *params, uint32_t address)
{
    FLASH_Unlock();
    FLASH_ErasePage(address);

    *(__IO uint8_t *)(address) = params->byteData;
    *(__IO uint16_t *)(address + 1) = params->wordData;
    *(__IO uint32_t *)(address + 3) = params->dwordData;

    FLASH_Lock();
}
  • 修改后的写入操作如下:
void writeParameters(Parameters *params, uint32_t address)
{
    FLASH_Unlock();
    FLASH_ErasePage(address);

    *(__IO uint8_t *)(address) = params->byteData;
    *(__IO uint16_t *)(address + 1) = params->wordData;
    *(__IO uint32_t *)(address + 3) = params->dwordData;
    *(__IO uint32_t *)(address + 7) = params->newData;

    FLASH_Lock();
}

三、修改读参数函数

  1. 调整读取顺序和地址偏移

    • readParameters函数中,同样要根据新成员变量的位置来调整读取的顺序。
    • 因为新成员变量在结构体中是在前面三个成员之后,所以读取时要从相应的偏移地址开始读取新成员变量的值。
  2. 更新读取操作代码

    • 原有的读取操作是:
void readParameters(Parameters *params, uint32_t address)
{
    params->byteData = *(__IO uint8_t *)(address);
    params->wordData = *(__IO uint16_t *)(address + 1);
    params->dwordData = *(__IO uint32_t *)(address + 3);
}
  • 修改后的读取操作如下:
void readParameters(Parameters *params, uint32_t address)
{
    params->byteData = *(__IO uint8_t *)(address);
    params->wordData = *(__IO uint16_t *)(address + 1);
    params->dwordData = *(__IO uint32_t *)(address + 3);
    params->newData = *(__IO uint32_t *)(address + 7);
}

写结构体的函数时,如何保证数据的完整性?

结构体成员变量名的命名规则是什么?

如何优化参数读写函数的性能?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值