嵌入式软件实习 · 八股文复习手册
面向:嵌入式软件(MCU 方向)实习/校招面试 · 单片机 + RTOS 为主
用法:先盖住答案自己讲一遍 → 对答案 → 标记讲不出的 。每题都能直接拿去问 AI 展开。
优先级图例:
★★★几乎每场必问 ·★★常考 ·★加分/拉开差距
答题三层(面试官真正想听的):
- 是什么(定义/原理)
- 对比与场景(和谁比、什么时候用、坑在哪)
- 我项目里怎么用/怎么炸过(结合项目,最好带数字或踩坑故事)
0. 针对你简历的"必被深挖点"
面试官会照着你简历上的词逐条问。下面每个词都准备了题,答不出就等于简历吹牛:
| 简历里的词 | 对应章节 | 你必须能讲清 |
|---|---|---|
| CAN、OTA、Bootloader | 四、七 | 帧格式/仲裁、Flash 分区与跳转 |
| LVGL 移植 | 七 | 怎么移植、怎么和驱动分层、帧率优化到 25fps |
| RT-Thread | 六 | 内核机制、IPC、你项目里怎么用 |
| STM32H743 MPU + D2 域 SRAM | 六、十一 | 为什么放 D2、MPU 配了什么 |
| K210 人脸识别 + 串口协议 + 状态机 | 四、十 | 协议怎么定、状态机怎么切 |
| ZigBee / WiFi / 机智云 | 四 | 多节点怎么组网、数据怎么上云 |
| 研读数据手册定位硬件故障 | 十二 | 准备好 2 个真实踩坑案例 |
一、C 语言 ★★★
Q1. volatile 的作用?哪些地方必须用?
- 告诉编译器该变量可能被"编译器看不见的地方"修改,禁止优化(不缓存到寄存器),每次访问都真的读内存。
- 必须用:① 硬件寄存器映射指针 ② 中断(ISR)与主循环共享的变量 ③ 多任务共享的标志位。
- 常与 const 组合:
const volatile------ 只读寄存器(程序不能写,但硬件会改)。 - 追问(高频坑):加了 volatile 就线程安全了吗?
→ 不是 。volatile 只保证"每次真读内存",不保证原子性、不提供内存屏障 。i++(读-改-写)多任务下仍会出错,计数类要么加临界区,要么用原子操作。
Q2. static 的三个作用? ★★★
- 修饰局部变量 :存储位置从栈→静态区,生命周期变成整个程序,但作用域仍在本函数内(函数间不共享)。
- 修饰全局变量 :链接属性变 internal,只在本文件可见(避免命名冲突)。
- 修饰函数:同上,只在本文件可见。
Q3. const 和 #define 的区别? ★★
#define是预处理文本替换 ,无类型检查、不占内存、调试看不到符号;const是编译期变量,有类型检查、有作用域。- 建议:常量优先
const/enum,宏只在条件编译和必要的宏函数里用。
Q4. const 修饰指针的几种写法怎么读? ★★
const int *p:p 可改,*p不能改(指向常量)。int * const p:p 不能改,*p可改(常指针)。const int * const p:都不能改。- 口诀:const 在
*左边管指向内容,在右边管指针本身。
Q5. #define 和 typedef 的区别? ★★
typedef是给类型起别名,编译期处理,有类型语义。#define是文本替换 ,预处理期。典型反例:#define PTR int*然后PTR a, b;→int* a, b;(b 是 int 不是指针!),而typedef int* PTR;则 a、b 都是指针。
Q6. sizeof 和 strlen 的区别? ★★★
sizeof是运算符,编译期算出字节数,对数组返回整个数组大小。strlen是函数 ,运行期数到'\0'为止。- 陷阱:
char *p = "abc"; sizeof(p)=4/8; strlen(p)=3。数组当参数传进函数会退化成指针 ,sizeof就不再是数组大小。
Q7. 指针和数组的区别? ★★
- 数组名是地址常量(不能自增),数组是真实存在的连续空间。
- 指针是变量,可以移动;指针可以是 NULL,数组名不行。
sizeof(数组)= 总大小;sizeof(指针)= 指针本身大小。
Q8. 结构体内存对齐规则?sizeof 怎么算? ★★★
- 规则:① 每个成员的偏移量是自身对齐数的整数倍 ;② 结构体总大小是最大对齐数的整数倍 ;③ 对齐数 =
min(成员大小, 编译器对齐参数)。 - 例子(32 位,默认 4 对齐):
struct {char c; int i;}→ c@0,i 填充到 4,共 8 字节。struct {int i; char c;}→ 共 8 字节(尾部补齐)。struct {char a; int b; char c;}→ 共 12 字节。
- 加分 :调整成员顺序可省空间;
#pragma pack(1)/__attribute__((packed))可压缩,用于协议打包,代价是可能拆成多次总线访问、M0 上非对齐访问会 HardFault。 - 追问 :协议通信不要直接强转结构体发送,要显式按字节序逐字段序列化。
Q9. union(联合体)和 struct 的区别? ★★
- union 所有成员共享同一块内存,大小 = 最大成员大小(再按对齐取整);同一时刻只有一个成员有效。
- 用途:省内存、类型双关(判断大小端、寄存器位域访问)。
Q10. 位域是什么? ★
- 结构体成员可指定占几位(
unsigned int flag:1;),用于硬件寄存器映射 和协议帧定义。缺点:布局依赖编译器。
Q11. 怎么判断大小端? ★★
- 大端:高字节存低地址。小端:低字节存低地址(x86、Cortex-M 都是小端)。
- 判断法:
c
union {int i; char c;} u = {1};
printf("%d\n", u.c); // 小端输出 1,大端输出 0
- 通信里跨平台必须约定字节序,常用
htonl/ntohl或手动移位打包。
Q12. C 程序的内存分区? ★★★
- 栈:局部变量、函数参数(自动分配释放,可能溢出)。
- 堆 :
malloc/free(手动管理,易泄漏/碎片)。 - .data:已初始化的全局/静态变量。
- .bss(ZI-data) :未初始化/零初始化的全局/静态变量,启动时统一清零。
- .rodata / .text:常量、字符串字面量、代码。
- 追问 :为什么
.bss(ZI-data)不占镜像大小?→ 都是 0,镜像里不用存,启动时把该 RAM 区清零即可。
Q13. 野指针、内存泄漏、栈溢出? ★★
- 野指针:指针未初始化 / 指向已释放内存 → 用完置 NULL,free 后置 NULL。
- 内存泄漏:malloc 后没 free(嵌入式慎用动态内存,优先静态内存池)。
- 栈溢出:栈太小或递归过深 → 现象是跑飞/HardFault,靠填充魔数、栈水位检测定位。
Q14. 函数指针 / 回调函数? ★★
void (*fp)(int);是函数指针,可用于回调、驱动分层、状态机跳转表、命令表。- 你项目里的"指令解析 + 状态机调度"就是典型用法。
Q15. 带参宏的陷阱? ★
c
#define SQ(x) x*x // SQ(1+2) → 1+2*1+2 = 5 错!
#define SQ(x) ((x)*(x)) // 正确:每个参数加括号,整体加括号
- 还有副作用问题:
#define MAX(a,b) ((a)>(b)?(a):(b)),MAX(i++,j++)会自增两次。
Q16. 编译的四个过程? ★★
- 预处理 (
.i:展开宏、头文件、条件编译)→ 编译 (.s:生成汇编)→ 汇编 (.o:生成目标文件)→ 链接 (可执行/.hex/.bin:合并段、分配地址)。
二、常用手写代码题 ★★
Q17. 手写 memcpy(考虑重叠用 memmove)
c
void *my_memcpy(void *dst, const void *src, size_t n) {
char *d = (char *)dst;
const char *s = (const char *)src;
while (n--) *d++ = *s++;
return dst;
}
// memmove:若 dst 在 src 后方且重叠,需从尾部倒着拷贝
Q18. 手写 strcpy / strlen
c
size_t my_strlen(const char *s) {
const char *p = s;
while (*p) p++;
return p - s;
}
char *my_strcpy(char *dst, const char *src) {
char *r = dst;
while ((*dst++ = *src++));
return r;
}
Q19. 判断大小端(见 Q11)
Q20. 宏求数组元素个数
c
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) // 仅对真数组有效,指针无效
Q21. 位操作
c
#define SET_BIT(x,n) ((x) |= (1u << (n)))
#define CLR_BIT(x,n) ((x) &= ~(1u << (n)))
#define TOGGLE_BIT(x,n) ((x) ^= (1u << (n)))
#define GET_BIT(x,n) (((x) >> (n)) & 1u)
Q22. 链表(手撕链表基本躲不掉)
- 必会:创建节点、尾插 、头插 、删除节点 、反转链表 、判环(快慢指针) 、合并两个有序链表。
- 嵌入式里链表常用于任务/设备管理、消息队列底层,所以面试官爱考。
Q23. 字符串反转 / 数组去重 / 冒泡·快排
三、STM32 / MCU 基础 ★★★
Q24. STM32 上电到 main 的过程? ★★★
- 上电复位,从向量表第 0 项取 MSP 初值(栈顶地址)。
- 从向量表第 1 项取 Reset_Handler 地址并跳转。
- Reset_Handler → 调 SystemInit(配时钟)→
__main→ 把.data从 Flash 搬到 RAM、把.bss清零 → 调main()。
Q25. GPIO 有哪几种模式?推挽和开漏的区别? ★★★
- 输入:浮空、上拉、下拉、模拟。
- 输出:推挽、开漏;复用推挽、复用开漏。
- 推挽:能主动输出高和低,驱动能力强。
- 开漏 :只能拉低,高电平靠外部上拉 ,可实现线与 、电平转换 、总线共享 → I2C 必须用开漏。
Q26. 为什么 I2C 用开漏 + 上拉? ★★
- 多设备共享两条线,开漏实现线与:任一设备拉低总线就为低,避免推挽"一个拉高一个拉低"造成短路。
- 上拉电阻提供高电平;阻值影响上升沿速度与功耗(常见 4.7k)。
Q27. 中断和轮询的区别?什么时候用哪个? ★★
- 轮询:CPU 主动查状态,简单但浪费 CPU、实时性差。
- 中断:事件触发,CPU 不用等,实时性好、效率高。
- 高频大量数据用 DMA 更进一步(不占 CPU)。
Q28. 中断服务函数(ISR)里要注意什么? ★★★
- 快进快出,别做耗时操作。
- 不能用会阻塞的 API (如带阻塞的 RTOS 调用、
malloc)。 printf慎用(不可重入、慢),非要打印用无锁/环形缓冲方式。- 与主循环共享的变量加
volatile。 - 带 RTOS 时中断里只能调
xxxFromISR版本 API。
Q29. 中断优先级怎么理解? ★★
- Cortex-M 用 NVIC,优先级数值越小优先级越高。
- 分抢占优先级 (能打断别人)和子优先级(同抢占级谁先,不能互相打断)。
- 用
HAL_NVIC_SetPriorityGrouping划分位数。
Q30. 时钟树 / 主频怎么配? ★★
- HSE/HSI → PLL 倍频 → SYSCLK → AHB/APB 分频。
- 你自己的坑 :GY906 温度跳 1037.55/-273.15,根因是
SystemClock_Config配成 8MHz 而非 64MHz,串口/时序全错。这就是绝佳的项目排障案例。
Q31. Flash 擦除后是什么值?能按字节写吗? ★★
- 擦除后是 0xFF;写之前必须先擦除(只能 1→0)。
- 写入按对齐单位:F1 半字(16bit)、F4 字(32bit)、H7 更宽,不能随意按字节写。
- Flash 有擦写寿命,频繁写用 EEPROM/外部 Flash。
Q32. ADC 采样精度由什么决定? ★
- 分辨率(12 位 = 0~4095)、参考电压、采样时间、输入阻抗、是否过滤波。
- 电压 =
adc * Vref / 4095。
Q33. 看门狗(IWDG/WWDG)原理? ★★
- 独立看门狗由内部低速时钟驱动,程序定时"喂狗",超时未喂就复位。
- 防跑飞/死锁,喂狗要放在"确认系统健康"的地方,别放中断里盲目喂。
四、通信总线 ★★★
Q34. UART / I2C / SPI 的区别?各自场景? ★★★(经典必考对比题)
| UART | I2C | SPI | |
|---|---|---|---|
| 线数 | 2 (TX/RX) | 2 (SCL/SDA) | 4 (SCK/MOSI/MISO/CS) |
| 同步 | 异步 | 同步 | 同步 |
| 双工 | 全双工 | 半双工 | 全双工 |
| 速率 | 中 | 低 | 高 |
| 拓扑 | 点对点 | 多设备(地址) | 多设备(片选) |
| 场景 | 调试/模块通信 | 传感器/EEPROM | Flash/屏/高速外设 |
Q35. UART 数据帧结构和波特率? ★★★
- 帧:起始位(1) + 数据位(5~9) + 校验位(0/1) + 停止位(1/2)。
- 波特率 = 每秒传输位数;两端必须一致,不一致会乱码。
- 计算:
BRR = fCK / (16 × 波特率),16 倍过采样,还有小数部分修正(USARTDIV的整数+小数)。
Q36. UART 怎么收不定长数据? ★★
- 方案:DMA + 空闲中断(IDLE) ------ DMA 搬运,总线空闲中断触发后算本次收到多少字节,再处理。比一字节一中断效率高。这条面试很爱问,你项目里用了多路串口,准备好。
Q37. SPI 的 4 种模式(CPOL/CPHA)? ★★
- CPOL 决定空闲电平(0 低 / 1 高),CPHA 决定在哪个边沿采样(0 第一个边沿 / 1 第二个边沿)。
- Mode0~3。主从必须配置一致,否则数据错。
Q38. I2C 时序 / 卡死怎么排查? ★★
- 起始/停止条件、ACK/NACK、时钟拉伸(clock stretching)。
- 卡死常见原因:从设备把 SDA 拉死 → 补救:发 9 个时钟脉冲让从机释放,或复位 I2C 外设。
- 上拉电阻缺失/阻值不对也会导致通信失败。
Q39. CAN 为什么常用于汽车?帧格式? ★★★(你项目①核心)
- 优势:差分传输抗干扰 、多主仲裁 、错误检测强(CRC+位填充+ACK)、可靠性高、成本低。
- 差分:CAN_H/CAN_L,显性(逻辑0) 覆盖隐性(逻辑1) ,两端各 120Ω 终端电阻。
- 帧:标准帧(11 位 ID)/ 扩展帧(29 位 ID);数据帧含仲裁段、控制段(DLC)、数据段(0~8)、CRC、ACK、帧结束。
Q40. CAN 仲裁怎么工作? ★★★
- 非破坏性按 ID 仲裁:多个节点同时发,ID 小的(显性位多)获胜,输的节点自动退出、等下次。ID 越小优先级越高。
Q41. CAN 波特率怎么计算? ★★
- 位时间 = 1 个位分成的若干 Tq:Sync + BS1 + BS2,采样点通常在 75%~87.5%。
波特率 = 1 / (Tq × (1 + BS1 + BS2)),Tq = (预分频+1) / fCAN。- 你自己的坑 :CAN 调不通往往就是波特率算错。这是你现成的排障案例。
Q42. CAN 的过滤器、错误处理? ★★
- 过滤器:只接收关心的 ID,减轻 CPU 负担(掩码/列表模式)。
- 错误管理:TEC/REC 计数,主动错误→被动错误→总线关闭(Bus-Off) 三态。
五、DMA ★★
Q43. DMA 是什么?为什么要用? ★★★
- 直接内存访问:不经过 CPU 在内存与外设间搬数据,CPU 可干别的。
- 用于:串口大批量收发、ADC 连续采样、SPI 刷屏、PWM 驱动 LED。
- 概念:通道/请求映射、优先级、正常模式 vs 循环模式 、传输完成/半传输中断。
Q44. 用 DMA 驱动 WS2812 的原理? ★★(你项目④做过)
- WS2812 靠脉宽编码 :0 码/1 码占空比不同。用定时器 PWM 输出对应占空比波形,用 DMA 把预先算好的比较值(CCR) 连续搬进寄存器,实现不占 CPU 的精确时序输出。
Q45. DMA 和 Cache 的一致性问题? ★
- 带 Cache 的核(M7/M4):DMA 直接改内存,CPU 可能读到 Cache 里的旧值 → 需要 clean/invalidate Cache,或把 DMA 缓冲区放到非 Cache 区(你项目④的 H743 + D2 域 SRAM 就与此相关)。
六、RTOS(RT-Thread / FreeRTOS)★★★
Q46. 任务有哪几种状态?怎么切换? ★★★
- 就绪 / 运行 / 阻塞(等信号量/延时)/ 挂起。
- 调度时机:时间片用完、被更高优先级抢占、主动阻塞/延时、事件到来被唤醒。
Q47. 调度算法? ★★★
- 抢占式 + 同优先级时间片轮转,永远运行最高优先级就绪任务。
- FreeRTOS 用优先级位图 + 就绪链表 实现 O(1) 调度。
Q48. 裸机 vs RTOS?什么时候用 RTOS? ★★★
- 裸机:任务少、逻辑简单、实时性要求确定 → 前后台 + 状态机够用。
- RTOS:多任务并发、有阻塞等待、模块解耦时用,能简化复杂时序,但引入栈开销、调度开销、共享资源保护问题。
Q49. 信号量 / 互斥量 / 事件 / 消息队列 的区别? ★★★(高频对比题)
- 二值信号量:事件通知/同步(ISR 里 give,任务里 take)。
- 计数信号量:管理多个同类资源(如缓冲池)。
- 互斥量(Mutex) :有所有者 ,用于临界资源保护,带优先级继承;不能用于中断。
- 事件集/事件标志组 :一个任务等多个事件组合。
- 消息队列 :传递数据(拷贝/引用),可跨任务/中断。
- 任务通知:最轻量最快的"单任务"通知方式。
Q50. 优先级反转是什么?怎么解决? ★★★(最高频 RTOS 题)
- 场景:低优先级任务 L 持锁 → 高优先级 H 等锁被阻塞 → 中优先级 M 抢占 L → H 被 M 间接挡住。
- 解决:① 优先级继承 (持锁的 L 临时提升到 H 的优先级,FreeRTOS 的 Mutex 自动做)② 优先级天花板(持锁即提升到可能用该锁的最高优先级)。
- 工程根治:缩短临界区、别嵌套锁、别持锁阻塞、少用大锁。
Q51. 临界区怎么保护? ★★
- 关中断(简单但影响实时性)、关调度/调度锁、用互斥量。
- Cortex-M3/M4 用 BASEPRI 寄存器屏蔽指定优先级以下的中断,比全关中断温和。
Q52. 中断里能用 RTOS 的 API 吗? ★★★
- 只能用在中断安全版本 (FreeRTOS 的
xxxFromISR,RT-Thread 的rt_xxx_from_isr/带_isr后缀)。 - 绝不能在 ISR 里调用会阻塞的 API。
Q53. 任务栈多大合适?栈溢出怎么发现? ★★
- 一般几百字节~几 KB,按最深调用 + 局部变量估算,宁大勿小。
- 检测:① FreeRTOS
uxTaskGetStackHighWaterMark()看栈水位 ②configCHECK_FOR_STACK_OVERFLOW③ 栈填充魔数(0xA5)看被踩到哪。
Q54. 上下文切换做了什么? ★★
- 保存当前任务的寄存器 + 返回地址到该任务栈,切到新任务的 TCB/栈,恢复其寄存器。
- M3/M4 用 PSP 存任务栈、MSP 存中断/内核栈。
Q55. 死锁怎么产生、怎么避免? ★★
- 四条件:互斥、持有并等待、不可抢占、循环等待。
- 避免:加锁顺序统一、用超时、一次拿全、减少嵌套锁。
七、Bootloader / OTA / 启动 ★★(加分项,你项目①核心)
Q56. Bootloader 跳转到 APP 的关键步骤? ★★★
- 校验 APP 有效(CRC/魔数)。
- 关总中断(跳转前必须)。
- 设 MSP = APP 向量表0(栈顶)。
- 设
SCB->VTOR = APP 起始地址(重定位向量表)。 - 取向量表1(Reset_Handler)地址并跳转。
Q57. IAP 和 ISP 的区别? ★★
- ISP:用芯片自带的 BootROM + 串口/USB 下载(出厂固件)。
- IAP:程序运行时自己擦写 Flash 升级,即 OTA 的核心。
Q58. Flash 分区怎么做?OTA 怎么防变砖? ★★★
- 典型:Bootloader 区 + APP 区(可再分 APP_A/APP_B 双备份)+ 参数/标志区。
- 防变砖:升级前校验完整性和签名、升级标志写 Flash、失败可回滚到旧版本、断电续传。
Q59. LVGL 怎么移植?帧率怎么优化? ★★
- 移植:提供显示驱动(刷屏接口)、输入驱动、时基(tick)、配置
lv_conf.h。 - 帧率优化(你答到 25fps):优化刷屏通道(SPI 提速/DMA)、只刷新脏矩形、减少重绘、降低色深/图片解码开销、双缓冲。
八、中断 / 异常 / 排障 ★★★
Q60. HardFault 怎么排查? ★★★(面到必加分)
- 定位:在 HardFault_Handler 里读栈里的 PC/LR/xPSR ,判断出错的是主栈(MSP)还是任务栈(PSP),再反汇编定位出错指令/变量。
- 常见原因:空指针/野指针、数组越界、栈溢出、非对齐访问、除零、访问未使能的外设时钟、跳转非法地址。
- 工具:J-Link 看寄存器、CmBacktrace 库自动回溯。
Q61. 程序跑飞怎么办? ★★
- 查栈溢出、指针越界、中断标志没清导致的重复进中断、时钟/外设未初始化、看门狗喂狗位置不当。
Q62. 怎么看一个 bug 是硬件还是软件? ★★
- 用示波器/逻辑分析仪看引脚波形:电源纹波、时钟、总线时序。软件逻辑对就查硬件(虚焊、上拉缺失、供电)。
九、操作系统 / 计算机网络(部分公司)★★
Q63. 进程和线程的区别? ★★
- 进程有独立地址空间、资源;线程共享进程资源、切换开销小。
Q64. TCP 和 UDP 的区别? ★★
- TCP:面向连接、可靠、有序(三次握手/四次挥手);UDP:无连接、快、不可靠。
- 视频流/实时控制常用 UDP;配置/文件传输用 TCP(你项目④的 RTMP 基于 TCP)。
Q65. 三次握手为什么不是两次? ★
- 防止已失效的连接请求迟到后server误建连接;确认双方收发能力都正常。
十、无线 / 云端(你项目③④)★★
Q66. WiFi / BLE / ZigBee / LoRa / 4G 的区别与场景? ★★
- WiFi:高带宽、功耗高、局域网 → 网关/数据上传。
- BLE:低功耗、短距、低带宽 → 可穿戴/近场。
- ZigBee:低功耗、自组网多跳、低带宽 → 传感器组网(你项目③)。
- LoRa:远距离、极低功耗、低带宽 → 野外/农业(你项目④)。
- 4G:广域、需基站、功耗高 → 远程回传。
Q67. 多节点怎么组网、数据怎么上云? ★★(照你项目③讲)
- 子节点(ZigBee) → 中控单片机汇聚 → WiFi/ESP8266 → 云平台(机智云/阿里云) → 手机 APP 显示与控制。
- 讲清:协议、汇聚节点角色、上云协议(MQTT/HTTP)。
Q68. 用过的云平台?数据怎么存? ★
- 阿里云 / 机智云 / OneNET;数据可存时序库,用规则引擎转发。
十一、ARM 架构 / 体系结构 ★(拉开差距)
Q69. Cortex-M 系列区别? ★
- M0/M0+:小核、无 MPU(部分)、无 Cache;M3:带 MPU、无 FPU;M4:带 FPU(单精度);M7:高性能、双精度 FPU、Cache、TCM。
Q70. MSP 和 PSP 是什么? ★★
- 两个栈指针:MSP 主栈 (中断/内核用),PSP 进程栈(RTOS 任务用)。任务切换时切 PSP。
Q71. MPU 是什么?H743 的 D2 域 SRAM 为什么要单独布局? ★★(你项目④核心)
- MPU:内存保护单元,划分区域并设置访问权限和 Cache 属性,防止越界破坏。
- H743 有多个 SRAM 域(如 AXI/D2/D3):不同域挂在不同总线上,可在 MPU 里单独配置 Cache 属性/权限 。把 DMA 缓冲或高频访问数据放到指定域并配好 Cache 策略 ,避免 Cache 一致性问题和总线争用。面试能讲清"为什么放 D2、MPU 设了什么属性"就非常出彩。
Q72. 异常向量表是什么?怎么重定位? ★★
- 存各种异常/中断入口地址的表,默认在 Flash 起始。用
SCB->VTOR改基址(OTA/Bootloader 跳转时用)。
十二、项目排障(STAR 法则)★★★
面试问"遇到什么困难/最自豪的项目",用 STAR :S ituation 背景 → T ask 任务 → A ction 你怎么做 → R esult 结果(带数字)。
你现成的两个案例(一定要背熟):
案例1:CAN 通信调不通
- S:双 STM32 做 CAN 仪表盘,一直收不到数据。
- T:定位是硬件还是软件。
- A:查 TSR/ESR/MSR 寄存器判断发送状态和错误类型,核对位时序与波特率计算,排查 TJA1050 收发器供电/终端电阻。
- R:发现是波特率配错,改正后通信正常(可补:稳定 25fps 刷新)。
案例2:GY906 红外测温温度乱跳(1037.55 / -273.15)
- S:温度读到明显离谱的值。
- T:找根因。
- A:排除"增量编译混链"假设,读数据手册核对时序;确认是主频 8MHz 而非 64MHz (
SystemClock_Config与 RT-Thread 的system_clock_config不一致),导致 I2C/时序基准全错。 - R:统一时钟配置后温度正常。
- 这个案例体现"看数据手册定位配置错误",正好对应你自我评价那句。
准备框架,每个项目都能套:
- 一句话项目是什么 + 解决什么
- 你负责哪块(精确到模块/文件)
- 最大难点 + 定位过程 + 修复结果(数字)
- 如果重做会怎么改进(几乎必问,提前想)
备考节奏建议
- 先扫自己简历:简历上每个技术词,都要能讲"定义→对比→项目里怎么用"。讲不出的立刻补。
- 按优先级背:C 语言 → STM32 外设 → RTOS → 你的项目,这四块占 70%。
- 每题三层:定义 / 对比场景 / 项目结合。
- 手撕代码:链表、memcpy、字符串,提前手敲到熟练。
- 准备 1 分钟和 5 分钟两个版本的项目介绍。
- 一面考广度,二面考深度:二面多想"系统设计、问题定位、工程取舍"。
参考来源(详见文末链接):CVTE/小米/安克创新/江波龙等面经,牛客春招嵌入式汇总,CSDN/知乎嵌入式八股题库。