中控技术嵌入式开发(系统软件)面经:FreeRTOS 任务设计与 Modbus RTU 通讯
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
自我介绍与背景
- 简单做一下自我介绍。
- 你有没有做过驱动相关的工作?
- 你日常开发主要偏向驱动还是应用?
FreeRTOS 控制器项目深挖
- 基于 FreeRTOS 的控制器开发项目,是你个人完成还是几个人合伙?
- 硬件是买的开发板吗?还是自己做的?
- 底层驱动需要你自己调吗?还是拿开发板自带的直接用?
- 买开发板时配套的教程、基础源码你用了吗?用这些驱动时出过问题吗?
- 你在这个控制器里具体做了哪些功能?
- 你设计了几个任务?哪个优先级最高?哪个最低?
- 看门狗任务的优先级是多少?
- 这些任务的优先级为什么这么设定?是怎么考虑的?
- 升级过程不需要监控吗?没有心跳?
- 如果任务卡死了,靠什么触发软复位?由谁来判断?
- 那个时间判断是在任务本身做,还是在别的任务里做?
- 如果任务自己卡死了,它怎么自己监控自己?
Modbus RTU 与 485 通讯
- Modbus RTU 你应该知道吧?
- 485 有收发控制,一般通过什么事件控制收转发、发转收?讲一下逻辑。
- TC 这一位代表什么?是最后一个字节传完了,还是已经填到计数器里了?你确认吗?
FreeRTOS 任务函数耗时测量
- 在 FreeRTOS 工程下,要测某个任务里某个函数的执行时间,有哪几种方式?
- 这个时间戳是在哪里增加的?是软件驱动还是硬件驱动的?
- 你说 CPU 内部计数器,那多任务场景下要严格测函数的完整执行时间,是不是还要考虑任务切换和调度?
- 如果要考虑调度和其他干扰,应该怎么做?
Linux 与 AI 单元测试
- 你有 Linux 开发经验,Linux 上主要做哪些事情?
- 你用 AI agent 做单元测试,效果怎么样?测出来的结果可信吗?
- 你现在是在实验室吗?
岗位适配与收尾
- 你有哪些问题需要了解?
- 面试官介绍岗位后反问:DCS 行业嵌入式工作强度有点大,你心理预期怎么样?能接受吗?
《参考解析》
- 任务划分与优先级怎么定:优先级不是按「哪个功能重要」排,而是按截止期和实时性排——硬实时的外设收发、控制输出、采样这类错过就有后果的任务放最高;控制计算与状态机次之;上报、日志、OTA、参数存取这类可以容忍延迟的放最低,被前面任意任务抢占。FreeRTOS 里数值越大优先级越高,同优先级默认按时间片轮转;如果控制环是固定周期的,可以照速率单调的思路——周期越短优先级越高。要主动交代的是共享资源的处理:跨任务访问同一外设或缓冲区用互斥量而不是二值信号量,让优先级继承机制抑制优先级反转;中断服务里只做置位、发信号这类短操作,用
FromISR版 API,把耗时处理交给任务。 - 看门狗任务的优先级与位置:看门狗任务本身得能被及时调度到,所以一般放较高优先级,但也不能高到把实时任务饿死。它的职责是收集各任务上报的心跳计数或时间戳,统一判断后决定要不要喂硬件狗。要强调一点:如果把喂狗放在最低优先级的任务里,一旦上面某个任务卡死,这个任务照样会按时喂狗,硬件看门狗就形同虚设。
- 任务卡死与软复位由谁判断:判断者不能是被监控者自己——一个任务自己死循环或者阻塞住了,它没有任何机会去上报「我卡了」,所以必须由另一个任务或定时器中断来看它的最后活动时间戳,超时就触发
NVIC_SystemReset()软复位,或者先尝试只重启相关模块。硬件层面还有独立看门狗(IWDG)兜底,它由独立时钟驱动,主逻辑整体跑飞时靠它复位。要补一句局限:如果任务仍在被调度、只是逻辑上有问题(比如每轮都做无用功),单纯的时间戳看不出异常,得让它每轮上报「进度」而不是只报「我还活着」。 - Modbus RTU 与 485 的收发方向控制:RS-485 是半双工差分总线,收发共用一对线,方向由 DE/RE 引脚控制。切换时机是这道题的核心:发送前拉高 DE 进入发送态,写数据到 UART,等**发送完成(TC,Transmit Complete)**再切回接收态,因为 TC 才表示最后一个字节已经从移位寄存器完全送上线、总线空闲;如果只等 TXE(发送数据寄存器空)就切,最后那个字节还在移位寄存器里没发完,就会被截断。实现上可以走「TC 中断里翻转 DE」,也可以用 DMA 发送加传输完成中断,部分 MCU 自带 RS485 模式由硬件自动翻转。往上还有协议层的活:用 3.5 个字符时间的总线空闲判帧结束、CRC 校验、超时重传和主从轮询节拍。
- FreeRTOS 下测函数执行时间:常用的有几种,各有取舍。① 读 CPU 周期计数器(Cortex-M 的 DWT->CYCCNT)前后取差值,精度最高、开销最小;② 用系统时间戳,比如
xTaskGetTickCount(),但精度受 tick 周期限制;③ GPIO 翻转加逻辑分析仪或示波器,对被测代码侵入小、还能看到波形;④ 打开 FreeRTOS 的运行时统计(configGENERATE_RUN_TIME_STATS)看各任务的 CPU 占用,但它到不了单个函数的粒度;⑤ 用 SystemView、Tracealyzer 这类 trace 工具;⑥ 把纯逻辑抽出来在主机上跑 benchmark。至于时间戳的软硬件之分:CYCCNT 是 CPU 内部的硬件周期计数器,SysTick 与 RTOS tick 是软件计数,精度和抖动完全不同。 - 多任务下的干扰怎么处理:直接读计数器测到的是挂钟时间——函数执行期间如果被高优先级任务抢占、被中断打断,这段时间都会算进去,所以它不等于函数自己消耗的 CPU 时间。要严格测量有两种思路:一是排除干扰,把测量区间放进临界区关中断(
taskENTER_CRITICAL)或者把当前任务临时提到最高优先级且保证不阻塞,代价是会拉长中断延迟、改变系统时序,测完必须恢复,且不适合测长函数;二是把干扰量化扣掉,用带上下文切换记录的 trace 工具,把被抢占的时间段减掉,或者用 CPU 周期计数配合 trace 事件统计。更实用的做法是分两类各测一次——「含调度的挂钟延迟」用于评估实时性,「纯执行时间」在关中断或单任务环境下测,两边一起看才能判断问题出在函数本身还是被抢占太频繁。 - Linux 上主要做什么:常见几块——写和维护内核驱动或字符设备、应用层服务(网络、串口、进程管理)、用 Buildroot/Yocto 做交叉编译与系统裁剪、启动流程与文件系统打包、以及调试(gdb、strace、perf、dmesg、ftrace)。回答时最好落到自己真做过的具体事和踩过的坑,别只报名词。
- AI agent 做单元测试可信吗:可以当补充手段,不能直接当验收依据。风险有三点:模型容易顺着实现写用例,把实现当成规范,实现错了用例也跟着错;为了让测试通过,它有时会去改断言或加特判;嵌入式代码里被 mock 掉的寄存器时序、并发与硬件行为,恰恰是最容易出问题的地方,mock 掉就等于不测。可行的用法是把 AI 用在生成边界用例、补齐回归脚手架、把已有用例改写成新框架这类低风险环节,断言必须能追溯到需求或协议文档而不是实现,覆盖率只当参考指标,关键路径仍然要在板或 HIL 上验。用例进主干之前要人工评审。
- 岗位适配与反问:被问到「强度大能不能接受」时,具体比表态有用——可以问清楚典型项目的交付节奏、是否需要驻场或出差、on-call 与加班的大致情况,再结合自己的预期给出明确回答,含糊的「能接受」反而显得没准备。反问环节可以问团队做的方向(DCS 里偏控制器、IO 模块还是上位通信)、新人培养与导师安排、技术栈与代码规范、以及考核与晋升的节奏。