荣耀嵌入式面经:C 内存、I²C/SPI、中断与 FreeRTOS 调度
- 轮次
- 一面/二面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
一面:C 语言、接口和项目
static放在函数内部和外部,分别影响什么?修饰函数又有什么作用?- C 程序运行时,代码、全局变量、局部变量一般放在哪里?
- 返回局部变量的地址有什么问题?函数返回以后还能不能继续用?
- 段错误通常和哪些非法内存访问有关?拿到一个崩溃现场会先看什么?
- 链表和数组各适合什么情况?删除链表节点时,哪些指针操作容易写错?
- 项目中用过哪些硬件通信接口,为什么选这一种?
- 讲一下 I²C 从开始通信到结束的过程,ACK 在哪里出现?
- I²C 的 SDA 一直被拉低,可能有哪些原因?准备怎么查?
- SPI 和 I²C 有什么区别?如果接多个外设,连接方式有什么变化?
- 中断发生以后,程序怎么进入处理函数,又怎么回到原来的位置?
- 中断处理函数里哪些事情不适合做?收到数据后怎么交给任务处理?
- 中断和任务共用一个变量,
volatile能解决哪些问题,哪些解决不了? - FreeRTOS 怎么决定接下来运行哪个任务?
- 任务切换时需要保存哪些现场?为什么不能只保存一个函数地址?
- 高优先级任务一直处于就绪状态,低优先级任务还有没有机会运行?
- 项目里的蓝牙模块怎么和 MCU 通信?自己实现了哪一层,哪些由模块完成?
- 蓝牙连接上了,但应用收不到数据,会从哪里开始排查?
- 回看一道笔试题,解释当时的思路。如果输入规模扩大,有没有更合适的做法?
二面:项目分工、竞赛和个人选择
- 为什么参加这个项目或竞赛,是自己报名还是老师安排的?
- 团队有几个人,自己具体负责什么?
- 项目中最麻烦的一次问题是什么,当时怎么处理的?
- 几个人对方案有分歧时,最后怎么决定?
- 如果队友负责的部分没按时完成,自己会怎么办?
- 项目最后有什么结果,哪些地方还没有做好?
- 觉得自己的优势是什么?有什么需要改的地方?
- 最近一次遇到挫折是什么,之后做了什么?
- 为什么选择嵌入式,后面更想做哪一类工作?
- 选工作主要考虑什么,工作内容、地点和薪资怎么取舍?
- 意向工作地点有哪些?
- 有什么想了解的?
《参考解析》
内存布局与局部变量返回,是同一道题的两面。 典型进程地址空间从低到高:代码段(.text)、只读数据(.rodata)、已初始化全局/静态(.data)、未初始化全局/静态(.bss)、堆(向上)、共享库/映射区、栈(向下)。局部变量通常在栈上,但被 static 修饰后在 .data/.bss,被优化进寄存器时也可能根本不在栈上。返回局部变量地址的问题是:函数返回后栈帧失效,那块内存会被后续调用覆盖,指针变成悬空指针;即使「暂时还能读到」,也是未定义行为。正确做法是返回值、由调用方传缓冲区、或 malloc(并约定释放责任)。
I²C 要能画出时序。 空闲时 SCL/SDA 都被上拉为高;起始条件是 SCL 高时 SDA 由高变低;然后逐位传 7 位地址 + 读写位,第 9 个时钟由从机拉低 SDA 表示 ACK;接着传数据,每字节后同样有 ACK/NACK;停止条件是 SCL 高时 SDA 由低变高。常见坑:地址是 7 位还是 8 位(是否含读写位)、时钟频率与上拉电阻匹配、重复起始条件、时钟拉伸。SDA 一直被拉低,先查从机是否把总线拉死(断电重启)、上拉电阻是否过大/过小、是否有多个主机冲突、从机供电和地址是否正常;用示波器/逻辑分析仪看波形,再逐段断开设备定位。
SPI 与 I²C 的取舍是「速度 vs 引脚」。 SPI 全双工、速率高、无地址帧,靠独立片选选从机,接多个外设时片选线线性增加;I²C 两线、支持多主多从、有地址和 ACK,但速率低、总线电容限制设备数、调试更依赖波形。选型看数据量、实时性、引脚预算和器件支持。
中断处理要「短进短出」。 中断发生时硬件保存部分现场、根据向量表跳转;处理函数里只做清标志、读数据、发信号/入队,把耗时逻辑留给任务;返回时恢复现场。不要在 ISR 里阻塞、睡眠、malloc、打印、等锁;共享变量要 volatile + 临界区/原子操作,volatile 只防优化,不防竞态。FreeRTOS 里用 FromISR 版本的 API,并在退出时处理 pxHigherPriorityTaskWoken 触发切换。
FreeRTOS 调度:优先级抢占 + 同优先级时间片。 就绪链表按优先级组织,调度器总是选最高优先级的就绪任务;同优先级任务按时间片轮转(configUSE_TIME_SLICING)。任务切换保存的是完整上下文:R0–R12、LR、PC、xPSR,以及浮点寄存器(若开启 FPU 懒保存);只保存函数地址不够,因为恢复后要继续执行同一条指令、用同样的寄存器值。高优先级任务一直就绪,低优先级任务会被饿死;解决办法是优先级设计合理、必要时用时间片或让高优先级任务主动阻塞/让出。
蓝牙排查按「链路分层」走。 先确认连接状态(GAP 是否 connected)、服务与特征值是否发现、CCCD 是否使能通知;再看模块与 MCU 的串口链路(波特率、流控、TX/RX 接线、是否有数据吐出);然后看协议层(AT 命令是否回 OK、透传模式是否正确、MTU 与分包);最后看应用层(回调是否注册、缓冲区是否溢出、任务优先级是否导致丢数据)。用逻辑分析仪抓 UART,比盲猜快得多。
综合面要准备「具体的一次」。 团队分歧讲一次真实的技术选择:双方理由、你怎么用数据/原型推进、最后谁拍板、结果如何;队友延期讲你怎么发现、怎么补位、有没有及时升级风险,不要把自己写成唯一的救世主。择业取舍可以讲权重:技术方向 > 团队与成长 > 地点 > 薪资,但要和你的投递行为一致。