【嵌入式开发学习】第4天:函数指针 + 中断基础(嵌入式事件响应核心)

核心目标:掌握函数指针(嵌入式回调函数核心)、理解中断的概念与嵌入式处理流程,完成 2 个实操(模拟传感器回调、按键中断响应),搞懂 “异步事件” 如何在嵌入式中处理 —— 这是写驱动、做外设响应的关键。

一、函数指针:嵌入式 “回调机制” 的核心(60 分钟)

函数指针是 “指向函数的指针”,本质是存储函数的内存地址(和普通指针存储变量地址类似)。嵌入式中它的核心用途是 “回调函数”(比如传感器采集完成后自动调用处理函数、中断触发后调用响应函数)。

1. 函数指针的定义与语法(重点突破)
  • 定义格式:返回值类型 (*指针名)(参数类型1, 参数类型2, ...);
    • 括号必须加:(*指针名) 是关键,少了括号就成了 “返回指针的函数”(完全不同)。
    • 示例(对应之前的温度校准函数):

      c

      // 普通函数:输入原始数据,返回校准温度
      float calc_real_temp(int raw) {
          return (raw / 10.0) + 2;
      }
      
      // 函数指针:指向“输入int、返回float”的函数
      float (*calc_cb)(int) = calc_real_temp;  // 让指针指向calc_real_temp函数
      
  • 核心操作:通过函数指针调用函数,两种等价写法:
    • (*calc_cb)(256); (解引用调用,更直观)
    • calc_cb(256); (简化写法,嵌入式中更常用)两种写法结果都一样,返回 27.6℃。
2. 嵌入式场景:函数指针做 “回调函数”

嵌入式中,硬件事件(比如传感器采集完成、定时器溢出)需要 “自动触发处理逻辑”,此时用函数指针把 “处理函数” 传给硬件驱动,事件发生时驱动自动调用 —— 这就是回调机制。

  • 示例逻辑(传感器采集回调):

    c

    // 回调函数:采集完成后处理数据(比如打印)
    void process_data(float real_temp) {
        printf("采集完成!校准后温度:%.1f℃\n", real_temp);
    }
    
    // 传感器采集函数:接收回调函数指针,采集后调用
    void sensor_collect(int raw, float (*calc_cb)(int), void (*process_cb)(float)) {
        float temp = calc_cb(raw);  // 用函数指针调用校准函数
        process_cb(temp);           // 用函数指针调用处理函数
    }
    
  • 嵌入式意义:驱动和处理逻辑分离,比如想换处理方式(比如不打印而是存储数据),只需改回调函数,不用改驱动代码,复用性极强。

二、实操 1:用函数指针实现传感器采集回调(30 分钟)

结合之前的温度传感器结构体,用函数指针实现 “采集→校准→处理” 的回调流程,模拟嵌入式驱动的回调机制:

c

#include <stdio.h>

// 1. 温度校准函数(被回调)
float calc_real_temp(int raw) {
    return (raw / 10.0) + 2;
}

// 2. 数据处理函数(被回调)
void process_data(float real_temp) {
    printf("【回调函数执行】校准后温度:%.1f℃\n", real_temp);
}

// 3. 传感器采集函数(接收函数指针参数)
void sensor_collect(int raw, float (*calc_cb)(int), void (*process_cb)(float)) {
    printf("传感器采集原始数据:%d\n", raw);
    float temp = calc_cb(raw);  // 调用校准回调
    process_cb(temp);           // 调用处理回调
}

int main(void)
{
    // 模拟传感器采集到原始数据
    int raw_data = 265;
    
    // 调用采集函数,传入两个回调函数的地址
    sensor_collect(raw_data, calc_real_temp, process_data);
    
    while(1);  // 嵌入式持续运行
    return 0;
}
  • 运行结果:先打印原始数据,再执行回调函数打印校准温度。
  • 重点:sensor_collect 函数的参数是两个函数指针,分别指向 “校准函数” 和 “处理函数”—— 这是嵌入式驱动的标准写法(比如 STM32 的 HAL 库中,很多外设驱动都支持传入回调函数)。

三、中断基础:嵌入式 “异步事件响应” 的核心(50 分钟)

嵌入式中,很多事件是 “突发的”(比如按键按下、串口收到数据、传感器数据就绪),不能让 CPU 一直等待(浪费资源),此时需要 “中断” 机制 ——CPU 正常执行主程序,事件发生时暂停主程序,优先处理事件,处理完再返回主程序。

1. 中断的核心概念(嵌入式必懂)
  • 什么是中断:打断 CPU 当前任务,优先处理紧急事件的机制(比如你看书时电话响了,接完电话再继续看书)。
  • 嵌入式中常见中断源:
    • 外部中断:按键按下(GPIO 中断)、传感器数据就绪(I2C/SPI 中断)。
    • 内部中断:定时器溢出(定时中断)、串口收发完成(UART 中断)、ADC 采集完成(ADC 中断)。
  • 中断处理的核心流程(记牢!):
    1. 中断触发:事件发生(比如按键按下),硬件向 CPU 发送 “中断请求”。
    2. CPU 响应:暂停当前主程序,保存现场(比如寄存器值)。
    3. 执行中断服务函数(ISR):CPU 跳转到预先写好的中断处理函数(比如按键按下后执行 “点亮 LED”)。
    4. 返回主程序:处理完后,恢复现场,继续执行之前暂停的主程序。
2. 嵌入式中断处理的 3 个关键原则
  • 中断服务函数(ISR)必须 “快进快出”:不能有循环、延时、复杂运算(否则会阻塞主程序和其他中断)。
  • 中断服务函数中尽量不用全局变量,若必须用,要加 “volatile” 关键字(告诉编译器 “这个变量可能被中断修改,不要优化”)。
  • 同一时间只能处理一个中断,优先级高的中断可以打断优先级低的中断(嵌入式中可配置中断优先级)。

四、实操 2:模拟按键中断触发温度采集(40 分钟)

结合函数指针和中断概念,模拟 “按键按下(中断触发)→ 调用回调函数采集温度” 的嵌入式典型场景:

c

#include <stdio.h>

// 全局变量:标记按键状态(用volatile,模拟中断中修改)
volatile int key_pressed = 0;

// 1. 温度校准函数
float calc_real_temp(int raw) {
    return (raw / 10.0) + 2;
}

// 2. 中断回调函数(中断触发后执行)
void key_isr_callback(int raw) {
    float real_temp = calc_real_temp(raw);
    printf("【按键中断触发】采集温度:%.1f℃\n", real_temp);
    key_pressed = 0;  // 清除按键状态
}

// 3. 模拟中断控制器:检测到按键后触发中断,调用回调函数
void simulate_interrupt(void (*isr_cb)(int)) {
    if (key_pressed == 1) {
        int raw_data = 273;  // 模拟采集到的原始数据
        isr_cb(raw_data);    // 调用中断回调函数
    }
}

int main(void)
{
    printf("主程序运行中...\n");
    printf("模拟按键按下(设置key_pressed=1)\n");
    key_pressed = 1;  // 模拟按键按下,触发中断
    
    // 主程序循环中检测中断(实际嵌入式中由硬件自动检测)
    while(1) {
        simulate_interrupt(key_isr_callback);  // 传入中断回调函数
    }
    
    return 0;
}
  • 运行结果:主程序运行中,模拟按键按下后,触发中断回调,打印采集到的温度。
  • 重点解析:
    • volatile int key_pressedvolatile 关键字是嵌入式中断的必备(避免编译器优化导致变量值读取错误)。
    • key_isr_callback 是中断服务函数的简化版(实际嵌入式中函数名有固定格式,比如 STM32 的EXTI0_IRQHandler)。
    • 实际开发中,simulate_interrupt 的逻辑由硬件自动完成(比如 GPIO 中断控制器检测到电平变化后,自动调用中断服务函数)。

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

  1. 函数指针的核心用途是 “回调函数”,定义格式必须带括号:返回值类型 (*指针名)(参数类型)
  2. 中断是 “异步事件响应” 机制,核心流程是 “触发→响应→执行 ISR→返回主程序”。
  3. 中断服务函数必须 “快进快出”,全局变量需加volatile关键字。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值