新凯来嵌入式一面凉经(985本)
- 轮次
- 一面
- 结果
- 已挂
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
- 自我介绍。
- 介绍一下你的项目。
- 第一个项目是否使用了 RTOS?如果没有 RTOS,有没有写简单的任务调度?(作者回答用状态机实现)
- 在白板上画一下系统设计图(作者画成了列表形式,被问有没有学过系统的画法)。
- 问成绩、主修课程、毕业设计(还没开始)。
- 用 VSCode 写一道滑动窗口求平均值的题(第一遍写错,第二遍写出来了)。
- 反问:部门业务、部门对 AI 辅助的态度。
《参考解析》
没有 RTOS 时怎么做任务调度:这是嵌入式面试的高频题,答案要分层次说。①前后台架构(超循环):main 里一个 while(1) 轮询,中断里只置标志位,耗时逻辑放主循环执行,是最简单也最常用的方案;②时间片轮询:用 SysTick 或定时器产生 tick,维护一张任务表,每个任务记录周期 period 和上次执行时间 last_run,主循环里判断 now - last_run >= period 就执行,实现多个不同周期任务的”软并行”;③状态机:把一条业务流拆成「状态 + 事件 + 动作」,每次进主循环推进一步,避免 delay 阻塞(作者回答的就是这个);④协作式调度:任务自己主动让出 CPU,用一个任务队列 + 函数指针数组实现。实现要点:中断里只做置标志、入队这类短操作;共享变量要加 volatile 或用临界区保护;坚决不用长 delay,一律改成 HAL_GetTick() 做非阻塞计时;给每个任务留好超时与错误处理。
状态图该怎么画(为什么不能画成列表):面试官指出”画成列表”是个典型扣分点——列表只能表达步骤的先后,表达不了分支、回退、并发,而嵌入式系统的复杂性恰恰在这些地方。规范的画法是 UML 状态机图:实心圆表示起始状态,圆角矩形表示状态,带箭头的迁移线标注格式为「事件 [守卫条件] / 动作」,双圈表示终止状态;复杂系统用层次状态机(HSM)把子状态嵌套进去,或并列画出多个正交区域表示并发。另一个很实用的工程画法是状态迁移表(行是状态、列是事件,格子里写目标状态和动作),评审时一览无遗,代码里直接用二维数组或 switch(state) + switch(event) 落地。白板面试时先花 10 秒说明你要用哪种图、图例是什么,再动笔,比闷头画完被挑错要好。
滑动窗口求平均值的代码:用环形缓冲做到 O(1) 更新:
#define N 4
static double win[N];
static int idx = 0, cnt = 0;
static double sum = 0.0;
double push(double x)
{
if (cnt == N) { /* 窗口已满,先减去被覆盖的旧值 */
sum -= win[idx];
} else {
cnt++; /* 未满时先按已有元素求平均 */
}
win[idx] = x;
sum += x;
idx = (idx + 1) % N;
return sum / cnt;
}
写之前先跟面试官确认边界,这是第一遍写错的主要原因:①窗口未满时返回什么——按已有元素求平均,还是返回 0/NULL?②”平均值”是本次窗口内 N 个数的平均,还是从头到尾的移动平均?③数据类型——整数除法会截断,要不要用 double 或定点?其他加分细节:浮点累加会有误差累积,长时间运行可定期重算或用 Kahan 求和;数据量大且精度要求高时用整数累加(放大倍数后取整);如果在中断和多线程里共享这个窗口,要加临界区保护。
白板/共享编辑器写代码的方法论:作者”第一遍写错、第二遍写上来”,说明思路没问题,输在没打草稿。建议固定四步:①先口述思路(用环形缓冲、O(1)、边界怎么处理),让面试官确认方向;②先写测试用例(比如 push(1)、push(2)、push(3)、push(4)、push(5) 的期望输出),拿数据驱动代码;③写代码时把下标、初始值、边界分支写清楚,不要追求一行流;④写完用刚才的用例手动走一遍,说一句”我走一下样例”。手写代码卡壳是嵌入式面试最常见的挂点,平时就要在共享编辑器(不带补全)里练,不要只在 IDE 里练。
这场面试的整体启示:作者提到”也没问八股,就只问了项目、白板画图、写代码”,这说明岗位对工程表达的权重高于背诵。要准备的三件事:项目要能画出框图并讲清数据流与控制流;系统设计要会用状态图/时序图这类标准表达;C 语言基础题(环形缓冲、位操作、字符串处理、链表、内存对齐)要能手写并自测。另外毕业设计还没开始这一点在面试里是会被问到的,提前想好一句话说清选题方向和进度安排。