面灵AI→

科大讯飞嵌入式软件一面:通信帧设计与 I2C/SPI 时序

轮次
一面
时间
2026-09
来源
牛客网

《面试题目》

  1. 讲一下 MCU 的项目
  2. 介绍一下你项目的整体架构,数据从采集到最终处理 / 输出经历了哪些环节?
  3. 在项目中是怎么设计通信数据帧的?如果出现粘包、拆包或者数据丢失怎么处理?
  4. 项目中的数据量比较大时,你是怎么考虑缓存、数据处理和传输效率的?
  5. 多个传感器的数据采样频率不同,你的软件层面怎么设计的?
  6. 在实际开发中修改一个外设寄存器为什么经常使用位操作,而不是直接给整个寄存器赋值?
  7. 如果让你自己写一个 GPIO 驱动,从官方文档中重点看哪些内容?
  8. 具体讲一下 I2C 一次完整的数据传输时序
  9. SPI 发送的数据和接收到的数据不一致,你会重点检查哪些地方?
  10. 自我介绍

《参考解析》

数据帧设计与粘包 / 拆包 / 丢包:串口这类字节流必须封帧才能划边界,典型格式是 帧头 + 长度 + 命令字 + 序号 + Payload + CRC:帧头(如 0xAA55 或自定义双字节)确定帧起点,长度字段告诉接收端这帧多长,命令字区分业务,序号用于发现丢包、重复和乱序,CRC 校验数据是否被破坏。接收侧用状态机或环形缓冲区:数据不完整就继续累积(应对拆包),一次收到多帧就按帧头和长度字段循环解析(应对粘包)。丢包靠序号发现(收到 1001、1002、1004 就知道 1003 丢了),要求可靠就加 ACK + 超时重传 + 去重窗口,实时数据流则允许丢旧帧保实时。最后一道是 CRC 校验,失败丢帧并计数,连续失败触发重传或上报故障。落地细节:长度字段的字节序、最大帧长上限、缓冲区越界保护。

大数据量下的缓存与传输效率:先算数据量再谈架构——采样率 × 每点字节数 × 通道数,例如 16kHz、16bit、单通道音频是 32KB/s,再和 UART 的实际有效吞吐对比(标称波特率要扣掉起止位和协议开销,115200bps 实测有效也就 11KB/s 左右),这才知道有没有带宽瓶颈。缓存侧用 ADC → DMA → 双缓冲 / 环形缓冲区 → 处理 → 发送,让 DMA 承担搬运、CPU 只处理数据。处理侧批量处理,别每收一个字节就进一次中断;采集与处理拆成不同任务或中断 / 主循环两级,通过队列解耦。传不动就提高波特率、降低采样率、批量发送、压缩数据,或者换成 SPI / USB / 以太网。核心判断是”数据产生速度必须小于系统长期平均处理与传输能力”——生产长期快于消费,缓冲区再大也会溢出。

多传感器不同采样率怎么设计:不做统一周期,按频率和实时性分层。比如 IMU 1kHz、压力 100Hz、温度 10Hz,用各自的硬件定时器触发,RTOS 下就是三个任务(vTaskDelayUntil 保证周期稳定),采集结果写进各自的环形缓冲区或消息队列。数据融合时用采集时间戳对齐,而不是”收到数据的时间”——Sensor A timestamp=100ms、B=98ms、C=101ms 要靠时间戳插值 / 就近匹配。还要给每个传感器加超时和错误恢复:I2C 设备无响应不能一直阻塞整个系统,要设超时、错误计数、重试和重新初始化。

寄存器为什么用位操作:一个寄存器里往往有多个功能 bit 段,改其中一个不能影响其他位。置位用 REG |= (1 << 3),清零用 REG &= ~(1 << 3),改字段用 REG = (REG & ~MASK) | (VALUE << SHIFT);直接 REG = 0x08 会把其他已经配好的位全部覆盖。加分点在后面这句:不是所有寄存器都能读—改—写,只读寄存器、写 1 清零(W1C)的状态寄存器、读取会产生副作用的寄存器,都必须按 Reference Manual 规定的方式访问。

自己写 GPIO 驱动要看哪些文档:三类。Datasheet 确认引脚复用表(哪些脚可作 GPIO、复用功能编号)、电气特性(最大输出电流、上下拉能力、电平标准);Reference Manual 的 GPIO 章节看时钟使能、输入输出模式、推挽 / 开漏、上下拉、输出速度、置位 / 复位寄存器、中断配置;Errata 看有没有已知硬件限制。开发顺序是开时钟 → 配模式 → 配上下拉 / 输出类型 / 速度 → 配复用 → 读写数据寄存器 → 用示波器验证实际波形。用 HAL 库时也要回头对照寄存器,确认库函数到底改了哪些位。

I2C 一次完整传输时序:I2C 是开漏加外部上拉的结构,SCL 由主机产生,数据在 SCL 低电平期间变化、高电平期间保持稳定。写操作:START(SCL 高时 SDA 出现下降沿)→ 7 位从机地址 + 写位(0)→ 从机在第 9 个时钟拉低 SDA 回应 ACK → 寄存器地址 → ACK → 数据字节 → ACK →……→ STOP(SCL 高时 SDA 上升沿)。读操作中间要插 Repeated START:地址 + 写 → 寄存器地址 → ACK → Repeated START → 地址 + 读 → 从机发数据,主机收完除最后一个字节外都要 ACK,最后一个字节回 NACK 再发 STOP。要能顺口说出速率档位(标准 100k、快速 400k、高速 3.4M)和时钟拉伸;总线被从机拉死时的恢复手段(发 9 个 SCL 脉冲或硬件复位)也是常见追问。

SPI 收发数据不一致怎么查:SPI 是全双工移位寄存器,你收到的就是对方在你发送时移回来的内容,所以先怀疑配置再怀疑硬件。按顺序查:① CPOL / CPHA 模式(0~3)是否与从机手册一致,这是最高频的原因;② 位序是 MSB first 还是 LSB first;③ 数据位宽 8 / 16 位与帧格式;④ 片选时序——CS 必须在整帧期间保持有效,多从机时确认没有串扰,有些器件要求 CS 拉低后延时再发时钟;⑤ 时钟频率过高、走线长或上拉太弱导致边沿变缓、采样错位,降频试一下立刻能区分;⑥ 主从都配成了主机,或者 MISO 悬空只能读到 0xFF / 0x00;⑦ DMA 传输长度、缓冲区对齐和中断里被覆盖。验证手段很直接:发 0xAA / 0x55 看回读,把 MISO 与 MOSI 短接做回环测试验证配置,再用逻辑分析仪把 SCK 与 MOSI / MISO 对齐看采样点。