小鹰锐视-嵌入式开发 二面 面经

1. 简单介绍一下你自己和你最擅长的技术领域

参考答案

面试官您好,我是 XXX。我主要的技术方向是嵌入式系统开发,有两年多的项目经验。

我最擅长的是 STM32 的开发和 Linux 系统编程。

STM32 方面:

  • 熟悉各种外设的使用,包括 GPIO、定时器、UART、SPI、I2C、ADC、DMA 等
  • 做过多个基于 STM32 的项目,从底层驱动到应用逻辑都有涉及
  • 对 FreeRTOS 比较熟悉,能够设计合理的任务架构,处理好任务间的同步和通信

Linux 方面:

  • 熟悉系统编程,包括进程线程管理、网络编程、文件 IO 等
  • 做过高性能服务器项目,对 epoll、多线程、性能优化有深入理解
  • 了解一些 Linux 内核的知识,比如虚拟内存、进程调度等

我对嵌入式系统的底层原理很感兴趣,喜欢深入研究技术细节,解决复杂的技术问题。希望能在贵公司继续深入学习和成长。

2. 说说你对 DMA 的理解,DMA 的工作原理是什么?在什么场景下使用 DMA?使用时要注意什么?

参考答案

DMA 基本概念:

DMA 是 Direct Memory Access(直接内存访问),允许外设直接访问内存,不需要 CPU 干预。

  • 传统 IO 方式:CPU 从外设读数据到寄存器,再写入内存,CPU 全程参与,效率低
  • DMA 方式:CPU 配置好 DMA 控制器后,DMA 控制器接管总线,直接在外设和内存之间传输数据,传输完成后通过中断通知 CPU

DMA 工作原理:

  1. CPU 配置 DMA 控制器,包括源地址、目标地址、传输大小、传输方向、优先级等
  2. 启动 DMA 后,DMA 控制器向总线仲裁器请求总线使用权
  3. 获得总线后开始传输数据,每传输一个数据,地址指针自动递增或递减
  4. 传输完成后,DMA 控制器触发中断,通知 CPU

DMA 传输模式:

  • 外设到内存 (P2M):UART 接收、ADC 采样
  • 内存到外设 (M2P):UART 发送、DAC 输出
  • 内存到内存 (M2M):内存拷贝

DMA 的优势:

释放 CPU,提高系统吞吐量,特别适合大量数据传输的场景:

  • UART 高速收发:DMA 可以在后台接收数据,不需要 CPU 轮询或频繁中断
  • SPI 传输大量数据:用 DMA 可以提高速度
  • ADC 连续采样:用 DMA 可以自动存储采样结果

使用 DMA 的注意事项:

  1. Cache 一致性如果 MCU 有 Cache,DMA 直接访问物理内存,绕过了 Cache,可能导致数据不一致发送数据前要 flush Cache,确保数据写入内存接收数据后要 invalidate Cache,确保 CPU 读到最新数据
  2. 内存对齐DMA 通常要求数据地址和大小对齐,比如 4 字节或 32 字节对齐不对齐可能导致传输失败或效率低
  3. 内存区域有些 DMA 控制器只能访问特定的内存区域比如 STM32 的 DMA 不能访问 CCM(Core Coupled Memory),要用 SRAM
  4. 并发访问DMA 传输期间不能修改缓冲区,要用标志或信号量同步DMA 传输完成会触发中断,中断处理函数中要检查传输状态,处理错误
  5. 循环模式DMA 支持循环模式,传输完成后自动重新开始,适合连续采集场景使用双缓冲可以避免数据覆盖,一个缓冲区 DMA 写入,另一个缓冲区 CPU 处理

项目经验:

在我的项目中,我用 DMA 实现了 UART 的高速收发,接收速率达到了几百 KB/s,CPU 占用率很低。还用 DMA 实现了 ADC 的连续采样,配合定时器触发,实现了高精度的数据采集。

3. 说说你对 PID 控制算法的理解,PID 的三个参数分别起什么作用?如何调参?

参考答案

PID 基本概念:

PID 是比例-积分-微分控制算法,是工业控制中最常用的算法。PID 控制器根据误差计算控制量,使系统输出接近期望值。

PID 数学表达式:

u(t) = Kp * e(t) + Ki * ∫e(t)dt + Kd * de(t)/dt

其中:

  • e(t) 是误差,等于期望值减去实际值
  • u(t) 是控制量
  • KpKiKd 是三个参数

三个参数的作用:

  1. 比例 P 项:Kp * e(t)与当前误差成正比作用:快速响应误差,误差越大,控制量越大缺点:单纯的 P 控制会有稳态误差,无法完全消除误差Kp 太大会导致超调和振荡,太小响应慢
  2. 积分 I 项:Ki * ∫e(t)dt是误差的累积作用:消除稳态误差,只要有误差,积分项就会不断累积,直到误差为零缺点:会导致超调,响应变慢Ki 太大会导致振荡,太小消除误差慢
  3. 微分 D 项:Kd * de(t)/dt是误差的变化率作用:预测误差的趋势,提前调整,减少超调,加快响应缺点:对噪声敏感,噪声会导致微分项剧烈变化Kd 太大会放大噪声,太小抑制超调效果不明显

离散化 PID 算法实现:

float pid_control(float setpoint, float measured_value) {
    static float integral = 0;
    static float prev_error = 0;
    
    float error = setpoint - measured_value;
    
    // 比例项
    float p_term = Kp * error;
    
    // 积分项
    integral += error * dt;
    // 积分限幅,防止积分饱和
    if (integral > integral_max) integral = integral_max;
    if (integral < integral_min) integral = integral_min;
    float i_term = Ki * integral;
    
    // 微分项
    float derivative = (error - prev_error) / dt;
    float d_term = Kd * derivative;
    
    prev_error = error;
    
    // 控制量
    float output = p_term + i_term + d_term;
    
    // 输出限幅
    if (output > output_max) output = output_max;
    if (output < output_min) output = output_min;
    
    return output;
}

PID 调参方法:

  1. 经验法先设置 Ki=0,Kd=0,只调 Kp观察响应,逐渐增大 Kp 直到出现振荡,然后减小到振荡消失再加入 Ki,消除稳态误差最后加入 Kd,减少超调
  2. Ziegler-Nichols 法先设置 Ki=0,Kd=0,增大 Kp 直到系统持续振荡记录临界增益 Ku 和振荡周期 Tu根据公式计算: Kp = 0.6 * KuKi = 1.2 * Ku / TuKd = 0.075 * Ku * Tu
  3. 试凑法如果响应慢,增大 Kp如果有稳态误差,增大 Ki如果超调大,增大 Kd 或减小 Kp如果振荡,减小 Kp 和 Ki

实际应用注意事项:

  • 积分饱和:积分项累积过大,导致系统响应变慢,可以用积分限幅或积分分离解决
  • 微分噪声:可以用低通滤波或不完全微分解决

项目经验:

我在项目中用 PID 实现过温度控制,通过调节加热功率,使温度稳定在设定值。经过调参,温度波动控制在 ±0.5℃ 以内,效果很好。

4. 说说你对卡尔曼滤波的理解,卡尔曼滤波解决什么问题?基本原理是什么?

参考答案

卡尔曼滤波基本概念:

卡尔曼滤波是一种最优估计算法,用于从含有噪声的测量数据中估计系统的状态。它广泛应用于导航、目标跟踪、传感器融合等领域。

解决的问题:

系统的状态无法直接测量,只能通过含有噪声的传感器间接测量。比如:

  • 飞机的位置和速度:GPS 测量有误差,加速度计积分也有误差
  • 卡尔曼滤波融合多个传感器的数据,给出最优估计

基本原理:

假设系统的状态转移和测量过程都是线性的,噪声是高斯白噪声。通过预测和更新两个步骤,递推地估计系统状态。

预测步骤:

根据系统模型预测下一时刻的状态和协方差:

状态预测:x_pred = A * x + B * u
协方差预测:P_pred = A * P * A^T + Q

其中:

  • x 是状态
  • A 是状态转移矩阵
  • B 是控制输入矩阵
  • u 是控制输入
  • P 是协方差矩阵
  • Q 是过程噪声协方差

更新步骤:

根据测量值更新状态估计:

计算卡尔曼增益:K = P_pred * H^T * (H * P_pred * H^T + R)^(-1)
状态更新:x = x_pred + K * (z - H * x_pred)
协方差更新:P = (I - K * H) * P_pred

其中:

  • z 是测量值
  • H 是测量矩阵
  • R 是测量噪声协方差
  • K 是卡尔曼增益

卡尔曼增益决定了预测值和测量值的权重:

  • 如果测量噪声小,K 大,更相信测量值
  • 如果过程噪声小,K 小,更相信预测值

简化的一维卡尔曼滤波示例:

typedef struct {
    float x;  // 状态估计
    float P;  // 估计协方差
    float Q;  // 过程噪声协方差
    float R;  // 测量噪声协方差
} KalmanFilter;

void kalman_init(KalmanFilter *kf, float Q, float R) {
    kf->x = 0;
    kf->P = 1;
    kf->Q = Q;
    kf->R = R;
}

float kalman_update(KalmanFilter *kf, float measurement) {
    // 预测
    // x_pred = x (假设状态不变)
    float P_pred = kf->P + kf->Q;
    
    // 更新
    float K = P_pred / (P_pred + kf->R);  // 卡尔曼增益
    kf->x = kf->x + K * (measurement - kf->x);
    kf->P = (1 - K) * P_pred;
    
    return kf->x;
}

优缺点:

  • 优点:计算量小,适合实时系统,能够融合多个传感器的数据,给出最优估计
  • 缺点:只适用于线性系统和高斯噪声,对于非线性系统需要用扩展卡尔曼滤波 (EKF) 或无迹卡尔曼滤波 (UKF)

应用场景:

  • 姿态估计:融合加速度计和陀螺仪的数据,得到准确的姿态角
  • GPS 和 IMU 融合:提高定位精度

项目经验:

我在项目中用卡尔曼滤波处理过传感器数据,滤除了噪声,提高了测量精度。虽然算法看起来复杂,但理解了原理后,实现起来并不难。

5. 说说你对嵌入式系统功耗优化的理解,有哪些常用的低功耗技术?

参考答案

嵌入式系统特别是电池供电的设备,功耗优化非常重要。功耗优化需要从硬件和软件两个方面入手。

硬件方面:

  • 选择低功耗的 MCU,比如 STM32L 系列,支持多种低功耗模式
  • 选择低功耗的外设和传感器,查看数据手册的功耗指标
  • 优化电源设计,使用高效的 DC-DC 转换器,减少压降
  • 使用低功耗的显示屏,比如电子墨水屏或低功耗 OLED

软件低功耗技术:

1. 睡眠模式

让 MCU 在空闲时进入低功耗状态。STM32 有几种睡眠模式:

  • Sleep 模式:CPU 停止,外设运行,唤醒快,功耗中等
  • Stop 模式:CPU 和大部分外设停止,只保留 RTC 和备份域,功耗低,唤醒较慢
  • Standby 模式:只保持备份域,功耗最低,唤醒最慢,相当于复位

根据应用需求选择合适的睡眠模式:

  • 需要快速响应:用 Sleep 模式
  • 可以容忍较长的唤醒时间:用 Stop 或 Standby 模式

2. 唤醒源选择

  • RTC 定时唤醒:定期采集数据

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

嵌入式面试八股文全集 文章被收录于专栏

这是一个全面的嵌入式面试专栏。主要内容将包括:操作系统(进程管理、内存管理、文件系统等)、嵌入式系统(启动流程、驱动开发、中断管理等)、网络通信(TCP/IP协议栈、Socket编程等)、开发工具(交叉编译、调试工具等)以及实际项目经验分享。专栏将采用理论结合实践的方式,每个知识点都会附带相关的面试真题和答案解析。

全部评论

相关推荐

评论
点赞
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务