核心目标:掌握函数指针(嵌入式回调函数核心)、理解中断的概念与嵌入式处理流程,完成 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 中断)。
- 中断处理的核心流程(记牢!):
- 中断触发:事件发生(比如按键按下),硬件向 CPU 发送 “中断请求”。
- CPU 响应:暂停当前主程序,保存现场(比如寄存器值)。
- 执行中断服务函数(ISR):CPU 跳转到预先写好的中断处理函数(比如按键按下后执行 “点亮 LED”)。
- 返回主程序:处理完后,恢复现场,继续执行之前暂停的主程序。
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_pressed:volatile关键字是嵌入式中断的必备(避免编译器优化导致变量值读取错误)。key_isr_callback是中断服务函数的简化版(实际嵌入式中函数名有固定格式,比如 STM32 的EXTI0_IRQHandler)。- 实际开发中,
simulate_interrupt的逻辑由硬件自动完成(比如 GPIO 中断控制器检测到电平变化后,自动调用中断服务函数)。
五、第四天必掌握的 3 个关键知识点(10 分钟自测)
- 函数指针的核心用途是 “回调函数”,定义格式必须带括号:
返回值类型 (*指针名)(参数类型)。 - 中断是 “异步事件响应” 机制,核心流程是 “触发→响应→执行 ISR→返回主程序”。
- 中断服务函数必须 “快进快出”,全局变量需加
volatile关键字。


被折叠的 条评论
为什么被折叠?



