当前位置: 首页 > news >正文

嵌入式软件企业面

1. 自我介绍(侧重 MCU 项目)

面试官您好,我是××,××学校××专业。

我主要做 MCU 嵌入式,最熟的一个项目是×××。硬件用的是GD32/STM32,软件上了FreeRTOS。我负责的是××模块,比如串口通信、传感器采集、协议解析这块。

项目里我独立写过/改过××驱动,也处理过一些实际问题,比如通信不稳定、任务卡死之类,后面都定位并修掉了。

我对 MCU 底层和外设比较感兴趣,看到贵司做 GD32,和之前用的平台也比较接近,所以想来试试这个岗位。

2. 为什么选 GD32 / STM32?选型看哪些?

为什么选:

我选 STM32 或 GD32,主要是因为生态成熟:例程多、工具链完整、资料好找,开发效率比较高。GD32 和 STM32 外设用法很像,之前做过 STM32 的项目,迁到 GD32 上手会快一些。具体看项目对成本、供货和原厂支持的要求。

选型我会先看:

第一,Flash 和 RAM够不够,代码和数据能不能放下。

第二,外设数量,比如要几路 UART、有没有 CAN、ADC 路数够不够。

第三,主频和算力,有没有 RTOS、要不要跑复杂算法。

第四,封装和引脚,板子能不能放下。

第五,如果是量产,还会看供货、价格和温度等级

不会只盯着一颗芯片性能,而是先看项目需求再反推型号。

3.volatileconst在寄存器和中断共享变量里怎么用?

volatile

它的作用是告诉编译器:这个变量随时可能变,不要优化,每次都要从内存里读。

在寄存器操作上,访问硬件寄存器一般都要用volatile,不然编译器可能把读寄存器优化掉,导致状态判断不对。

在中断和主程序都会访问的变量上也要加,比如中断里置位的rx_flag,主循环里读它,如果不加volatile,主循环可能一直读到旧值。

不过我要补充一点:volatile只解决编译器优化问题,不保证多字节操作的原子性。如果是一个结构体或者head++这种复合操作,还要关中断或者用互斥保护。

const

它表示只读。像配置表、查表数组、只读参数我会用const,可以放在 Flash 里,也防止后面被误改。

如果是只读寄存器,可能会看到volatile const这种写法,表示硬件寄存器只读。

4. 结构体对齐是什么?#pragma pack用不对会怎样?

结构体对齐是编译器为了让 CPU 访问更高效,会在成员之间插入空白字节。

比如一个char加一个intchar占 1 字节,后面可能补 3 字节,再排int,所以整个结构体大小往往比成员简单相加要大。

#pragma pack(1)是把对齐关掉,成员紧凑排列。这个在通信协议打包时经常用,因为协议是按字节定义的。

如果用不对,会有几个问题:

一是和协议定义对不上,解析出来的数据错。

二是有些 MCU 对非对齐访问支持不好,可能直接 HardFault。

三是不同编译器、不同平台结构体大小可能不一致,联调容易出问题。

所以我的做法是:协议结构体单独pack(1),普通业务结构体用默认对齐,不随便全局改 pack。

5. 推挽输出和开漏输出区别?I2C 为什么用开漏?

推挽输出可以主动拉高或拉低,驱动能力强,适合 LED、片选这类需要明确高低的场景。

开漏输出只能主动拉低,拉高要靠外部上拉电阻,高电平本质是“释放总线”。

I2C 用开漏,核心原因有三个:

第一,I2C 是多设备共总线,需要线与,开漏才能多个设备同时挂在一起而不冲突。

第二,方便电平兼容,不同电压的器件可以通过上拉统一到同一高电平。

第三,从机可以做时钟拉伸,把 SCL 拉低延长时序。

所以 I2C 不仅软件上要配开漏,硬件上还必须接上拉电阻。

6. 定时器 PWM 怎么配?占空比怎么改?

我一般会这几步:

先开定时器时钟,然后配PSC 和 ARR,确定 PWM 频率。

再把通道设成PWM 模式,使能输出。

最后通过CCR来控制占空比。

频率大概是:

定时器时钟除以(PSC+1)再除以(ARR+1)

占空比就是:

CCR / (ARR+1)

如果只想改占空比,不动频率,运行中改CCR就行;不要去动 ARR,不然频率也会变。

实际项目里我还会注意 GPIO 复用、极性、是否需要互补输出和死区,比如电机控制就会用到这些。

7. IWDG 和 WWDG 区别?什么时候用哪个?

IWDG用的是独立低速时钟,就算主时钟出问题,它通常还能工作,所以更像最后一道保险。喂狗条件也简单,只要在溢出前喂就行。

WWDG用的是系统时钟分频出来的,它有个窗口,喂太早或太晚都会复位,所以不仅能看程序死没死,还能看程序是不是在预期时间范围内运行。

我一般的经验是:

正常运行靠IWDG做兜底;

如果项目对任务时序要求很严,比如功能安全相关,会考虑WWDG

很多普通项目只开 IWDG 就够了。

8. UART 波特率怎么算?两边偏差会怎样?

波特率本质就是把定时器时钟分频到目标通信速率。

常见算法是:

波特率 = fPCLK / (16 × USARTDIV)

实际开发里我一般不会手算,直接用 CubeMX 或 HAL 配置,它会根据时钟树算出 BRR。

如果两边波特率偏差太大,典型现象就是乱码、丢字节、偶发通信失败。UART 对误差是有容忍范围的,一般总共几个百分点以内还能接受,具体看位数和采样方式。

所以硬件上我会尽量用精度高的晶振,软件上关键数据会加校验,不能裸 UART 硬扛误差。

9. CAN 标准帧和扩展帧区别?仲裁怎么做?

标准帧ID 是 11 位,扩展帧是 29 位。扩展帧能表示更多 ID,适合节点多、ID 规划复杂的系统。

CAN 仲裁的核心是:ID 越小优先级越高,而且是非破坏性仲裁

多个节点同时发时,大家都发 ID 位,发 1 但读到 0 的节点就知道有更高优先级节点在发,自己退出发送。这样总线上的数据不会被破坏。

实际项目里我会特别注意 ID 规划,关键报文 ID 设小一点,保证实时性。

10. SPI 和 I2C 选传感器怎么取舍?

我会先看三个点:速度、线数、拓扑

SPI 是全双工,速度高,但线多,每个从机通常还要一根 CS。

I2C 是半双工,速度低一些,但只需要两根线,多设备靠地址区分。

如果是高速 ADC、Flash、屏幕这种大数据量,我倾向 SPI。

如果是温湿度、气压、EEPROM这种低速传感器,I2C 更省引脚,布线也简单。

同一个传感器如果两种接口都有,我会结合板子引脚资源和速率要求来选,不是单纯看哪个“更好”。

11. DMA 内存递增、外设地址固定是什么意思?

这个在 UART、ADC 接收里非常常见。

外设地址固定,是因为像USART->DRADC->DR这种寄存器地址不会变,DMA 每次都来同一个寄存器取/放数据。

内存地址递增,是因为我要把收到的数据依次存进数组,比如buf[0]、buf[1]、buf[2]...,所以内存指针要往后走。

UART RX 典型就是:外设不递增,内存递增。

UART TX 则反过来:内存递增,外设固定。

理解这个,DMA 配置就不容易配反。

12. Cortex-M 中断优先级分组怎么理解?

Cortex-M 的中断优先级可以分成抢占优先级子优先级,具体各占几位由PRIGROUP决定。

我的理解是:

抢占优先级决定能不能打断别人。

子优先级只是在同时 pending 时决定谁先响应,不能互相打断。

数值越小,优先级越高。

实际项目里我会把时间要求最紧的中断,比如高速采样、关键通信,抢占优先级设高一点;不太紧急的放低一点,避免中断嵌套太深。

13. 程序跑飞或 HardFault 怎么查?

我一般会按这个顺序:

第一步,先看Fault 寄存器,比如 CFSR、HFSR,判断是 Bus Fault、MemManage 还是 Usage Fault。

第二步,看栈里保存的PC 和 LR,定位是哪条指令出问题。

第三步,用 IDE 或addr2line找到对应源码行。

常见原因我会优先怀疑:

空指针、数组越界、栈溢出、访问没开时钟的外设、非对齐访问、除零。

如果是 FreeRTOS 项目,我还会查任务栈高水位,看是不是某个任务栈给小了。

定位后不会只改一行就完事,我会做复现、修复、长时间跑稳定性测试,确认不是偶发。

14. FreeRTOS 任务栈怎么估?栈溢出什么现象?

我一般不会一开始就算得很准,而是先给大一点,再用高水位反推

开发阶段会开uxTaskGetStackHighWaterMark(),看任务运行后最少还剩多少栈。如果剩余很少,就加大。

估算时会考虑:

局部变量大不大、调用层深不深、有没有printf、有没有浮点运算、会不会被中断打断。

栈溢出我遇到过几种典型现象:

系统偶发 HardFault;

某个变量值突然不对;

任务逻辑乱掉;

configCHECK_FOR_STACK_OVERFLOW后直接进钩子函数。

所以我现在习惯在调试版把栈监控打开。

15. 互斥量和二值信号量区别?

我会这么区分:

互斥量是用来保护共享资源的,谁加锁谁解锁,而且 FreeRTOS 的互斥量支持优先级继承

二值信号量更像一个同步标志,用来通知“某个事件发生了”,不一定强调资源归属。

比如保护一个全局缓冲区和 UART 发送资源,我会用Mutex

如果是中断通知任务“数据到了”,我更倾向信号量或任务通知

面试里我常记一句:保护资源用 Mutex,传递事件用信号量。

16. 什么是优先级反转?FreeRTOS 怎么解决?

优先级反转就是:高优先级任务在等低优先级任务手里的资源,结果中优先级任务把低优先级抢走了,导致高优先级反而被间接堵住。

FreeRTOS 里我主要用互斥量的优先级继承来缓解。低优先级任务持有 Mutex 时,如果高优先级任务在等,会临时把低优先级抬上去,让它尽快释放资源。

另外从设计上,我会尽量缩短持锁时间,能不在锁里做阻塞操作就不做。

17. Sleep、Stop、Standby 区别?唤醒怎么配?

我的理解可以简单记:

Sleep功耗降一些,CPU 停,很多外设还在,唤醒快。

Stop功耗更低,大部分时钟停了,但 RAM 通常还在,唤醒后要重新配时钟。

Standby最省电,但唤醒后往往相当于复位重启,RAM 内容一般保不住。

唤醒源常见有EXTI、RTC、串口某些模式、WKUP 引脚,具体要看芯片手册。

低功耗项目里我会先关不用外设时钟,再配唤醒源,进低功耗前把 IO 状态也处理好,避免漏电。

18. 项目里最难的 bug 是什么?怎么定位、怎么确认修好?

我举一个比较有代表性的:

之前有个 FreeRTOS 项目,运行几小时后会偶发 HardFault,不是必现。

我一开始以为是硬件干扰,后来通过 Fault 寄存器和 PC 定位,发现总是在某个通信任务附近出问题。再查栈高水位,发现这个任务栈剩余几乎为 0。

根因是任务里加了较大的局部数组,还调了printf,栈给 128 word 明显不够,溢出后踩到了别的内存,所以表现成偶发 HardFault。

修复就是把栈加大,去掉不必要的printf,并打开栈溢出检测。

验证不是只跑 10 分钟,而是连续跑 24~72 小时,同时看 High Water Mark,确认栈还有余量,再做回归测试。

http://www.jsqmd.com/news/1341582/

相关文章:

  • 如何使用Nextcloud Photos创建与分享精美相册
  • 广州职务类经济犯罪刑事律师选哪个:【法纳刑辩】首选律所 - 晚香时候
  • 计算机毕业设计之短视频分享的微信小程序
  • 广州大型企业高管经济犯罪律师选哪个:【法纳刑辩】绝佳选择 - 晴光转树
  • AI项目从入门到上线29-准确率99%但用户说不好用?AI项目评估的E2E度量体系
  • 像素即空间,孪生即智能!镜像视界重构数字孪生底座,打造全域可计算可推演的实景孪生
  • 如何在5分钟内开始使用YoloDotNet:从安装到首次目标检测
  • 国内靠谱过滤设备厂家 龙田过滤为首 专业生产过滤袋、袋式胶水机床化工墨水油墨过滤器源头工厂 - 变量人生001
  • 广州职务类经济犯罪刑事律师哪个专业:【法纳刑辩】术业专攻 - 云溪自乐
  • 计算机毕业设计之短视频接单兼职平台
  • 程序员专属巴厘岛出逃指南:告别内卷,解锁低压力高质慢旅行
  • DQ-dq - 青龙面板自动签到脚本
  • 2026 年 8 月长沙股权架构设计顾问测评,股权转让服务商该如何挑选? - 讲清楚了
  • 3个步骤搞定分子动力学自由能计算:gmx_MMPBSA完整指南
  • 广东产教融合科技研究院:学徒制大专和全日制大专的区别? - 升学指导教育资讯
  • 【arXiv 技术报告 2025】NVIDIA Nemotron 3:高效与开放智能|从大模型高效推理架构视角
  • C++控制台实现双人俄罗斯方块:游戏循环、碰撞检测与架构设计实战
  • 花都招聘平台哪个好:【帅聘网】高效靠谱 - 17328623207
  • 豆包怎么去除视频水印?用耶斯去水印、大佬去水印与主流去水印工具实战 - 免费软件工具方法教程
  • NS-USBLoader终极指南:Switch文件传输与RCM注入的完整解决方案
  • 从入门到精通:flipperzero-mayhem高级WiFi攻击技术全解析
  • 百兆瓦独立储能电站双网冗余通信解决方案|河北400MWh储能项目应用
  • 海牙公证在哪里办?线下排队排到心碎!“慧办好”出手,全程办理
  • PLC通信与故障处理29-PLC通信安全有多脆弱?从震网病毒到纵深防御,工业安全实战指南,纵深防御四层架构深度拆解(附VLAN+CPnS实战配置)
  • 如何实现ElasticJob任务依赖调度:5个简单方法解决复杂任务编排难题
  • 广东工业烤箱厂家榜盘点:泽润机械等源头厂家如何破解锂电池烘烤痛点,看这篇选型避坑干货 - 变量人生001
  • 海牙认证公证怎么办?零跑腿申办实操,完整流程与注意事项汇总
  • 2026年东南亚出口美国 优质合作公司盘点推荐几家 - 奔跑123
  • 计算机毕业设计之短视频广告发布系统的设计与实现
  • 北京通州区少儿武术培训文武学校:家长实地考察武校应该关注哪些细节? - 圣龙武术朱老师