尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

嵌入式软件企业面

嵌入式软件企业面 1. 自我介绍侧重 MCU 项目面试官您好我是××××学校××专业。我主要做 MCU 嵌入式最熟的一个项目是×××。硬件用的是GD32/STM32软件上了FreeRTOS。我负责的是××模块比如串口通信、传感器采集、协议解析这块。项目里我独立写过/改过××驱动也处理过一些实际问题比如通信不稳定、任务卡死之类后面都定位并修掉了。我对 MCU 底层和外设比较感兴趣看到贵司做 GD32和之前用的平台也比较接近所以想来试试这个岗位。2. 为什么选 GD32 / STM32选型看哪些为什么选我选 STM32 或 GD32主要是因为生态成熟例程多、工具链完整、资料好找开发效率比较高。GD32 和 STM32 外设用法很像之前做过 STM32 的项目迁到 GD32 上手会快一些。具体看项目对成本、供货和原厂支持的要求。选型我会先看第一Flash 和 RAM够不够代码和数据能不能放下。第二外设数量比如要几路 UART、有没有 CAN、ADC 路数够不够。第三主频和算力有没有 RTOS、要不要跑复杂算法。第四封装和引脚板子能不能放下。第五如果是量产还会看供货、价格和温度等级。不会只盯着一颗芯片性能而是先看项目需求再反推型号。3.volatile和const在寄存器和中断共享变量里怎么用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来控制占空比。频率大概是定时器时钟除以(PSC1)再除以(ARR1)。占空比就是CCR / (ARR1)。如果只想改占空比不动频率运行中改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-DR、ADC-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 分钟而是连续跑 2472 小时同时看 High Water Mark确认栈还有余量再做回归测试。
返回列表