【嵌入式开发学习】第3天:结构体 + 函数(嵌入式代码封装核心)

核心目标:掌握结构体(打包硬件相关数据 / 配置)和函数(复用驱动代码),完成 2 个嵌入式场景实操,理解两者在 “简化代码、统一管理” 中的核心作用 —— 这是后续写外设驱动、系统初始化的基础。

一、结构体:嵌入式中 “打包相关数据” 的工具(50 分钟)

嵌入式开发中,硬件的 “配置参数”“采集数据” 往往是相关联的(比如传感器的采样率、地址、采集值),结构体就是把这些 “相关数据” 打包成一个整体,避免变量混乱。

1. 结构体的定义与命名(嵌入式习惯)
  • 定义格式:struct 结构体名 { 成员1类型 成员1名; 成员2类型 成员2名; ... };
  • 嵌入式命名习惯:结构体名首字母大写,成员名延续 “见名知意” 缩写(比如传感器配置结构体叫TempSensorCfgCfgConfiguration的缩写)。
  • 示例(温度传感器配置 + 数据结构体):

    c

    // 定义“温度传感器”结构体:打包配置参数和采集数据
    struct TempSensorCfg {
        int cfg_samplerate;  // 采样率(cfg=配置,samplerate=采样率)
        int cfg_addr;        // 传感器I2C地址(addr=地址)
        int raw_data;        // 单次采集原始数据
        float real_data;     // 单次校准后温度
    };
    
2. 结构体的使用(3 个核心步骤)
  1. 声明结构体变量:struct TempSensorCfg sensor1;(创建一个名为 sensor1 的传感器实例)
  2. 给成员赋值(2 种方式):
    • 逐个赋值:sensor1.cfg_samplerate = 10;(采样率 10 次 / 秒)、sensor1.cfg_addr = 0x48;(I2C 地址 0x48)
    • 初始化赋值:struct TempSensorCfg sensor1 = {10, 0x48, 256, 27.6};(按成员顺序赋值)
  3. 访问成员:用.运算符,sensor1.raw_data 就是访问 sensor1 的原始数据成员。
3. 嵌入式场景意义
  • 替代多个独立变量:比如不用定义samplerate1、addr1、raw1、real1,用一个结构体sensor1统一管理,代码更清晰。
  • 方便批量处理:如果有多个传感器(sensor1、sensor2),每个都包含完整配置和数据,后续用数组或指针管理更高效。

二、实操 1:用结构体管理传感器数据(30 分钟)

模拟 “单个温度传感器” 的配置、数据采集和校准,用结构体打包所有相关信息:

c

#include <stdio.h>

// 定义温度传感器结构体(打包配置+数据)
struct TempSensorCfg {
    int cfg_samplerate;  // 采样率(次/秒)
    int cfg_addr;        // I2C地址(嵌入式中传感器地址常用十六进制)
    int raw_data;        // 原始采样值
    float real_data;     // 校准后温度
};

int main(void)
{
    // 声明并初始化结构体变量(传感器1)
    struct TempSensorCfg sensor1 = {
        .cfg_samplerate = 10,  // 显式赋值(推荐,顺序可打乱)
        .cfg_addr = 0x48,
        .raw_data = 259
    };
    
    // 计算校准后温度(沿用之前的公式)
    sensor1.real_data = (sensor1.raw_data / 10.0) + 2;
    
    // 打印传感器信息(嵌入式中可通过串口输出)
    printf("传感器I2C地址:0x%X\n", sensor1.cfg_addr);  // 0x%X以十六进制显示地址
    printf("采样率:%d次/秒\n", sensor1.cfg_samplerate);
    printf("原始数据:%d\n", sensor1.raw_data);
    printf("校准后温度:%.1f℃\n", sensor1.real_data);
    
    while(1);
    return 0;
}
  • 运行结果:会依次输出传感器的地址、采样率、原始数据和校准温度。
  • 重点:.cfg_samplerate = 10 是嵌入式常用的 “显式初始化”,即使成员顺序变了,赋值也不会错,比按顺序赋值更稳健。

三、函数:嵌入式中 “复用代码” 的核心(50 分钟)

嵌入式开发中,很多逻辑会重复使用(比如温度校准、传感器初始化),把这些逻辑写成函数,每次用的时候直接调用,不用重复写代码 —— 既节省内存,又方便修改(比如校准公式变了,只改函数即可)。

1. 函数的定义与嵌入式常用格式
  • 定义格式:返回值类型 函数名(参数类型 参数名) { 函数体; return 返回值; }
  • 嵌入式核心原则:
    • 函数名用 “动词 + 名词”(比如calc_real_temp:计算真实温度),见名知意。
    • 优先用 “指针参数” 传递大数据(比如结构体),避免拷贝浪费内存。
    • 避免复杂逻辑:函数内部尽量简洁,一个函数只做一件事(比如校准函数只负责计算,不负责打印)。
2. 嵌入式常用函数类型(2 种核心)
  1. 有参数、有返回值(比如温度校准函数):

    c

    // 功能:输入原始数据,返回校准后温度
    float calc_real_temp(int raw) {
        return (raw / 10.0) + 2;  // 校准逻辑封装
    }
    
  2. 指针参数(传递结构体,修改内部数据):

    c

    // 功能:初始化传感器配置(通过指针修改结构体成员)
    void init_sensor(struct TempSensorCfg *sensor) {
        sensor->cfg_samplerate = 10;  // 指针访问结构体成员用“->”,而非“.”
        sensor->cfg_addr = 0x48;
        sensor->raw_data = 0;  // 初始化原始数据为0
    }
    
  • 关键细节:指针访问结构体成员时,用 -> 替代 .(比如 sensor->cfg_addr 等价于 (*sensor).cfg_addr),是嵌入式高频写法。

四、实操 2:用函数封装传感器初始化 + 温度校准(40 分钟)

把实操 1 的逻辑拆分成 “初始化函数” 和 “校准函数”,模拟嵌入式中 “代码复用” 的场景:

c

#include <stdio.h>

// 1. 定义结构体
struct TempSensorCfg {
    int cfg_samplerate;
    int cfg_addr;
    int raw_data;
    float real_data;
};

// 2. 函数1:初始化传感器(指针参数,修改结构体)
void init_sensor(struct TempSensorCfg *sensor) {
    sensor->cfg_samplerate = 10;
    sensor->cfg_addr = 0x48;
    sensor->raw_data = 0;  // 初始化为0,后续由硬件采集填充
}

// 3. 函数2:校准温度(有参数、有返回值)
float calc_real_temp(int raw) {
    return (raw / 10.0) + 2;  // 校准逻辑封装,后续修改只需改这里
}

int main(void)
{
    struct TempSensorCfg sensor1;
    
    // 调用初始化函数:传入结构体地址(&sensor1)
    init_sensor(&sensor1);
    
    // 模拟硬件采集数据(实际开发中由ADC接口读取)
    sensor1.raw_data = 262;
    
    // 调用校准函数:传入原始数据,返回校准后温度
    sensor1.real_data = calc_real_temp(sensor1.raw_data);
    
    // 打印结果
    printf("传感器初始化完成,地址:0x%X\n", sensor1.cfg_addr);
    printf("采集原始数据:%d\n", sensor1.raw_data);
    printf("校准后温度:%.1f℃\n", sensor1.real_data);
    
    // 复用函数:如果有第二个传感器,直接调用即可
    struct TempSensorCfg sensor2;
    init_sensor(&sensor2);
    sensor2.raw_data = 253;
    sensor2.real_data = calc_real_temp(sensor2.raw_data);
    printf("\n传感器2校准后温度:%.1f℃\n", sensor2.real_data);
    
    while(1);
    return 0;
}
  • 运行结果:会输出 sensor1 和 sensor2 的校准温度,两个传感器共用一套初始化和校准逻辑,体现函数复用价值。
  • 重点:init_sensor(&sensor1) 传入的是结构体地址,函数内部通过指针修改成员 —— 嵌入式中传递结构体时,优先用指针(避免拷贝整个结构体,节省内存)。

五、第三天必掌握的 3 个关键知识点(10 分钟自测)

  1. 结构体的核心作用是 “打包相关数据”,访问成员用 .(普通变量)或 ->(指针变量)。
  2. 函数的核心是 “代码复用”,嵌入式中优先用 “指针参数” 传递结构体等大数据。
  3. 嵌入式函数命名原则:“动词 + 名词”,一个函数只做一件事(比如初始化函数只负责赋值,校准函数只负责计算)。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值