1. 简述中断处理流程

  1. 中断请求:外设产生中断信号,发送给 CPU;
  2. 中断响应:CPU 检测到中断,保存当前程序计数器 PC、寄存器等上下文(压栈),关闭总中断;
  3. 跳转中断服务函数:根据中断向量表,跳转到对应中断服务程序;
  4. 中断处理:在中断函数中完成外设数据读取、状态清除等业务逻辑;
  5. 恢复上下文:执行完毕后,恢复之前保存的寄存器、PC 值,开启总中断;
  6. 返回原程序:CPU 回到被打断的代码处继续执行。

2. 堆和栈的区别

  1. 管理方式:栈由系统自动分配释放;堆由程序员手动malloc/free申请释放。
  2. 内存大小:栈空间小、固定;堆空间大、动态分配。
  3. 生长方向:栈向下生长(向低地址);堆向上生长(向高地址)。
  4. 分配效率:栈分配快,硬件直接支持;堆分配慢,需要内存管理算法。
  5. 碎片问题:栈无碎片;堆频繁分配释放易产生内存碎片。
  6. 存储内容:栈存局部变量、函数参数、函数返回地址;堆存动态申请的全局数据。

3. volatile 关键字的作用

volatile告诉编译器:变量值可能被硬件、中断、多任务意外修改,禁止编译器优化,每次都必须从内存读取,不使用寄存器缓存。核心场景

  • 寄存器映射变量;
  • 中断中修改的全局变量;
  • 多线程共享变量。不加volatile会导致编译器优化,读取旧值,出现逻辑 bug。

4. 什么是内存对齐

内存对齐是编译器自动将变量存储在特定地址(通常是自身大小整数倍)的规则。

  • 原因:CPU 访问对齐数据速度更快;部分硬件只能访问对齐地址,否则报错。
  • 对齐规则:
    1. 成员对齐:每个成员偏移地址为自身大小整数倍;
    2. 整体对齐:结构体总大小为最大成员大小整数倍。

5. 解释大小端模式

多字节数据在内存中的存储顺序,以0x1234为例:

  • 大端模式(Big‑Endian)高位字节存低地址0x12在前,0x34在后,网络协议常用。
  • 小端模式(Little‑Endian)低位字节存低地址0x34在前,0x12在后,ARM、x86 单片机默认小端。

6. 如何判断系统是大端还是小端

方法 1:共用体(最常用)

union test{
    int a;
    char b;
}u;
u.a = 0x01;
if(u.b == 1) 小端;else 大端。

方法 2:指针强制转换

int num=0x1;
char *p=(char*)#
*p==1 → 小端,否则大端。

7. 什么是中断嵌套

CPU 在处理一个中断时,允许响应优先级更高的中断,暂停当前中断,执行更高优先级中断,执行完后依次返回。作用:保证紧急事件优先处理,提高实时性;注意:同优先级中断一般禁止嵌套。

8. 中断和轮询的区别

  1. 轮询:CPU 不断循环查询外设状态,CPU 占用高、效率低、实时性差,适合低速外设;
  2. 中断:外设就绪后主动通知 CPU,CPU 空闲时做其他事,CPU 利用率高、实时性强,适合高速、紧急外设。

9. 看门狗的工作原理

看门狗(WDT)是独立硬件定时器,用于防止程序跑飞、死循环死机。

  1. 启动后计数器自动递减;
  2. 程序正常运行时,定期喂狗(重置计数器);
  3. 程序卡死 / 跑飞,无法喂狗,计数器归零;
  4. 看门狗触发系统复位,单片机重启恢复正常。

10. 常用的串口通信协议

  1. UART:异步串口,TX/RX 两根线,全双工,最常用;
  2. RS232:电平标准,远距离传输,电平 ±12V;
  3. RS485:差分信号,抗干扰强,支持多节点、远距离,半双工;
  4. TTL 串口:单片机直接电平(3.3V/5V),板间通信;
  5. USB 串口:虚拟串口,高速通信。

11. I2C 和 SPI 的区别

  1. 引脚:I2C 仅 2 根线(SDA/SCL);SPI4 根线(SCLK/MOSI/MISO/CS);
  2. 通信方式:I2C 半双工;SPI 全双工;
  3. 速度:I2C 低速(最高几 MHz);SPI 高速;
  4. 寻址:I2C 设备有地址,支持多主机;SPI 无地址,靠片选,单主机;
  5. 抗干扰:I2C 有应答机制;SPI 无应答。

12. 如何配置 GPIO(以 STM32 为例)

  1. 开启 GPIO 对应端口时钟;
  2. 配置模式:输入 / 输出 / 复用功能 / 模拟模式;
  3. 配置输出类型:推挽 / 开漏;
  4. 配置上下拉:上拉 / 下拉 / 浮空;
  5. 配置输出速度;
  6. (可选)开启外部中断,配置触发方式。

13. ADC 采样精度受哪些因素影响

  1. 硬件:参考电压稳定性、电源噪声、输入阻抗、接地;
  2. ADC 自身:位数、采样速率、转换时间;
  3. 软件:采样时间、多次采样取平均、滤波算法;
  4. 环境:温度漂移、电磁干扰。

14. 什么是 PWM 波

脉冲宽度调制波:周期固定,通过调节高电平占空比,实现等效模拟输出。公式:占空比 = 高电平时间 / 周期。用途:电机调速、LED 调光、DAC 模拟输出、电源控制。

15. 如何实现低功耗设计

硬件

  1. 选用低功耗 MCU;
  2. 闲置 IO 口配置为输入上拉 / 下拉,避免浮空漏电;
  3. 外设不用时断电;

软件

  1. 空闲时进入休眠、停止、待机模式;
  2. 关闭不用的时钟、外设;
  3. 用中断代替轮询,CPU 空闲休眠;
  4. 降低系统主频。

16. 解释 DMA 工作原理

DMA(直接内存访问),无需 CPU 参与,硬件直接搬运数据

  1. CPU 配置 DMA:源地址、目的地址、传输长度、触发方式;
  2. 外设 / 内存触发 DMA 请求;
  3. DMA 直接搬运数据,CPU 同时执行其他任务;
  4. 传输完成后,DMA 触发中断通知 CPU。作用:解放 CPU,提升高速数据传输效率。

17. 什么是内存泄漏

动态申请的堆内存(malloc),使用结束后没有 free 释放,程序结束前一直占用内存。危害:长期运行的设备内存越来越少,最终内存耗尽、死机。

18. 如何避免内存碎片

内存碎片:频繁 malloc/free 后,出现大量零散小内存块,无法分配大块内存。解决:

  1. 尽量使用静态内存、全局数组,少用动态堆;
  2. RTOS 中使用内存池分配固定大小块;
  3. 统一申请释放,减少频繁分配;
  4. 选择合适内存管理算法。

19. 任务间通信方式有哪些(RTOS,如 FreeRTOS)

  1. 消息队列:传递数据、消息;
  2. 信号量:二值 / 计数信号量,同步、互斥;
  3. 互斥锁:保护临界资源,防止多任务抢占;
  4. 事件标志组:多事件触发任务;
  5. 任务通知:轻量级通信,最快;
  6. 共享内存 + 互斥保护

20. 解释互斥锁和信号量

  1. 信号量
    • 二值信号量:用于任务同步(通知);
    • 计数信号量:用于资源计数、多任务同步。
  2. 互斥锁(互斥信号量):专门用于保护临界资源,同一时间仅一个任务访问;自带优先级继承,解决优先级反转。核心区别:互斥锁只能用于互斥;信号量多用于同步。

21. 什么是优先级反转

高优先级任务,因等待低优先级任务持有的互斥锁,被中间优先级任务抢占,导致高优先级任务长时间得不到执行。举例:任务 A (高)、B (中)、C (低);C 占用锁→A 等待→B 抢占 C→A 一直等待。

22. 如何解决优先级反转

  1. 优先级继承(互斥锁自带):低优先级任务占用锁时,临时提升为最高优先级,防止被中间任务抢占;
  2. 优先级天花板协议:占用锁的任务直接提升到所有可能使用该锁任务的最高优先级;
  3. 减少临界区代码长度。

23. 简述 RTOS 的调度机制

  1. 抢占式调度(主流):高优先级任务就绪,立即抢占低优先级任务;
  2. 时间片轮转:同优先级任务,按固定时间片轮流执行;
  3. 合作式调度:任务主动释放 CPU,不会被抢占,实时性差;FreeRTOS 默认:抢占式 + 同优先级时间片轮转

24. 什么是临界区

访问共享资源的代码段,这段代码执行期间,不允许被打断。共享资源:全局变量、硬件寄存器、队列、缓冲区等。保护方法:关中断、使用互斥锁。

25. 如何优化代码执行效率

  1. 算法优化:选择时间复杂度更低的算法;
  2. 编译器优化:开启 O2/O3 优化;
  3. 变量优化:频繁使用变量用register,局部变量代替全局变量;
  4. 减少循环:循环内减少计算,提前计算常量;
  5. 硬件利用:使用 DMA、硬件外设代替软件;
  6. RTOS 优化:合理分配任务优先级,减少任务切换;
  7. 精简代码:减少冗余判断、嵌套。

26. 什么是死锁?如何避免?

死锁:两个或多个任务互相等待对方持有的资源,导致所有任务都无法继续执行。产生条件:互斥、占有并等待、不可剥夺、循环等待。避免方法

  1. 破坏循环等待:所有任务按相同顺序申请资源;
  2. 一次性申请所有需要的资源;
  3. 资源超时释放;
  4. 避免嵌套使用互斥锁。

27. static 关键字的作用

  1. 修饰局部变量:延长生命周期至程序结束,只初始化一次;
  2. 修饰全局变量:限制作用域仅在当前.c 文件;
  3. 修饰函数:限制作用域仅在当前.c 文件,防止命名冲突。

28. const 关键字的作用

const定义只读变量,告诉编译器该变量不能被修改。

  • 修饰变量:const int a=10; a 不可修改;
  • 修饰指针:
    • const int *p:指向的内容不可改,指针可改;
    • int *const p:指针不可改,指向的内容可改;
    • const int *const p:指针和内容都不可改;
  • 修饰函数参数:防止参数在函数内被修改。

29. 指针和数组的区别

  1. 本质:指针是地址变量;数组是连续内存块的别名;
  2. 大小:指针大小固定(32 位 4 字节,64 位 8 字节);数组大小 = 元素个数 × 元素大小;
  3. 赋值:指针可任意赋值;数组名是常量,不能赋值;
  4. 访问:指针间接访问;数组直接访问;
  5. 传参:数组传参退化为指针。

30. sizeof 和 strlen 的区别

  1. sizeof:运算符,计算变量 / 类型占用的总字节数,编译时确定;
  2. strlen:函数,计算字符串实际长度(不含 '\0'),运行时确定。例:char arr[10]="abc";sizeof(arr)=10strlen(arr)=3

31. 结构体和联合体的区别

  1. 内存分配:结构体每个成员独立分配内存;联合体所有成员共享同一块内存;
  2. 大小:结构体大小 = 所有成员大小之和 + 对齐填充;联合体大小 = 最大成员大小;
  3. 成员访问:结构体可同时访问所有成员;联合体同一时间只能访问一个成员。

32. 什么是位域?有什么用?

位域是 C 语言中将一个字节的不同位分配给多个变量的语法。

struct{
    unsigned int a:1; // a占1位
    unsigned int b:2; // b占2位
}

作用:节省内存,常用于硬件寄存器操作、协议帧定义。

33. 什么是野指针?怎么避免?

野指针:指向未知内存地址的指针。产生原因:指针未初始化、free 后未置空、指针越界。避免方法

  1. 指针定义时初始化为NULL
  2. free 后立即将指针置为NULL
  3. 指针使用前检查是否为NULL
  4. 避免指针越界访问。

34. 什么是悬空指针?怎么避免?

悬空指针:指向已经被释放的内存的指针。产生原因:free 内存后,指针未置空,仍指向原地址。避免方法:free 后立即将指针置为NULL;使用智能指针(C++)。

35. 函数指针的作用

函数指针是指向函数的指针,存储函数的入口地址。用途

  1. 实现回调函数;
  2. 实现函数表、状态机;
  3. 动态调用函数。例:void (*pfun)(int); 定义一个指向参数为 int、返回值为 void 的函数指针。

36. 回调函数的作用

回调函数是通过函数指针调用的函数,由调用者注册,被调用者在特定事件发生时执行。用途

  1. 中断服务函数;
  2. 事件驱动编程;
  3. 异步通知;
  4. 解耦代码。

37. 什么是递归?优缺点

递归:函数直接或间接调用自身。优点:代码简洁,适合解决分治问题(如阶乘、二叉树遍历)。缺点

  1. 栈开销大,易栈溢出;
  2. 存在重复计算,效率低;
  3. 调试困难。

38. 什么是宏定义?和函数的区别

宏定义#define预处理指令,编译时进行文本替换。

特性 宏定义 函数
执行时间 编译时替换 运行时调用
类型检查 严格类型检查
代码长度 展开后变长 代码复用,长度不变
执行效率 高,无调用开销 低,有调用开销
副作用 易产生(如#define MAX(a,b) a>b?a:b

39. 什么是内联函数?和宏的区别

内联函数inline关键字修饰的函数,编译时将函数体展开到调用处。和宏的区别

  1. 内联函数有类型检查,宏没有;
  2. 内联函数可以调试,宏不能;
  3. 内联函数不会产生宏的副作用;
  4. 内联函数是函数,宏是文本替换。

40. 什么是栈溢出?怎么避免?

栈溢出:栈空间被耗尽,通常是局部变量过大、递归过深导致。避免方法

  1. 避免定义过大的局部数组;
  2. 限制递归深度;
  3. 增大栈空间(不推荐);
  4. 大内存使用堆分配。

41. 什么是缓冲区溢出?危害

缓冲区溢出:向缓冲区写入超过其容量的数据,覆盖相邻内存。危害:程序崩溃、数据被篡改、执行恶意代码。避免方法:使用安全函数(如strncpy代替strcpy)、检查输入长度。

42. C 语言中内存分配的方式有哪些

  1. 静态分配:全局变量、静态变量,编译时分配,程序结束释放;
  2. 栈分配:局部变量、函数参数,函数调用时分配,函数返回释放;
  3. 堆分配malloc/calloc/realloc申请,free释放,程序员手动管理。

43. malloc 和 calloc 的区别

  1. malloc:申请指定大小的内存,不初始化,内容随机;
  2. calloc:申请 n 个大小为 size 的内存,初始化为 0
  3. 例:calloc(10, sizeof(int)) 等价于 malloc(10*sizeof(int)) + memset(0)

44. free 之后指针会变成什么?

free 只是释放指针指向的内存,指针本身的值不变,变成悬空指针必须:free 后立即将指针置为NULL

45. 什么是内存越界?危害

内存越界:访问了不属于当前变量的内存地址。危害:数据被篡改、程序崩溃、死锁、安全漏洞。常见场景:数组下标越界、指针越界、字符串操作越界。

46. 什么是类型转换?隐式和显式的区别

类型转换:将一种数据类型转换为另一种。

  1. 隐式转换:编译器自动进行,可能丢失精度(如 int 转 float,long 转 int);
  2. 显式转换(强制转换):程序员手动指定,(类型)变量,风险高,需谨慎。

47. 什么是枚举?和宏的区别

枚举enum定义的一组命名整数常量。和宏的区别

  1. 枚举有类型检查,宏没有;
  2. 枚举可以自动赋值,宏需要手动赋值;
  3. 枚举便于调试,宏不能;
  4. 枚举作用域明确,宏全局有效。

48. 什么是 typedef?和 #define 的区别

typedef:给已有类型起别名,编译时处理。和 #define 的区别

  1. typedef 是编译时处理,#define 是预处理时文本替换;
  2. typedef 有类型检查,#define 没有;
  3. typedef 可以定义指针类型,#define 容易出错;例:typedef int* PINT;PINT a,b; a 和 b 都是 int*;#define PINT int*PINT a,b; a 是 int*,b 是 int。

49. C 语言中 static 和 extern 的区别

  1. static:限制作用域在本文件,延长局部变量生命周期;
  2. extern:声明全局变量 / 函数,作用域跨多个文件;
  3. 全局变量默认 extern,static 全局变量只能在本文件使用。

50. 全局变量和局部变量的区别

  1. 存储位置:全局变量存静态区;局部变量存栈;
  2. 生命周期:全局变量程序全程存在;局部变量函数调用时存在;
  3. 作用域:全局变量全局有效;局部变量函数内有效;
  4. 初始化:全局变量默认初始化为 0;局部变量默认随机值。

51. 什么是寄存器变量?有什么限制?

寄存器变量register关键字修饰,建议编译器将变量存到 CPU 寄存器,提高访问速度。限制

  1. 不能取地址(寄存器无地址);
  2. 数量有限,编译器可能忽略;
  3. 只能修饰局部变量和函数参数。

52. 什么是 const 指针和指向 const 的指针

  1. 指向 const 的指针const int *p,指针指向的内容不可修改,指针本身可修改;
  2. const 指针int *const p,指针本身不可修改,指向的内容可修改;
  3. 指向 const 的 const 指针const int *const p,指针和内容都不可修改。

53. 什么是函数重载?C 语言支持吗?

函数重载:同一作用域内,函数名相同,参数列表(个数 / 类型 / 顺序)不同。C 语言不支持函数重载,因为 C 编译器编译后函数名只有函数名本身;C++ 支持,因为编译后函数名包含参数信息(名字修饰)。

54. 什么是多态?C 语言怎么实现?

多态:同一接口,不同实现。C 语言通过函数指针 + 结构体实现多态。例:定义一个包含函数指针的结构体,不同对象赋值不同的函数实现。

55. 什么是面向对象?C 语言怎么实现?

面向对象:封装、继承、多态。C 语言实现:

  1. 封装:结构体封装数据和函数指针;
  2. 继承:结构体嵌套;
  3. 多态:函数指针。

56. STM32 的启动流程

  1. 上电复位:CPU 从启动地址(0x08000000 Flash/0x1FFF0000 系统存储器 / 0x20000000 SRAM)读取栈指针 SP;
  2. 执行启动文件:初始化栈指针,设置中断向量表;
  3. 调用 SystemInit:配置系统时钟(PLL、AHB、APB);
  4. 调用__main:初始化全局变量、静态变量,初始化堆;
  5. 调用 main 函数:进入用户主程序。

57. STM32 的时钟系统

STM32 时钟源:

  1. HSI:内部高速时钟(8MHz/16MHz),精度低,启动快;
  2. HSE:外部高速时钟(4-26MHz),精度高;
  3. LSI:内部低速时钟(32kHz),用于独立看门狗、RTC;
  4. LSE:外部低速时钟(32.768kHz),用于 RTC。系统时钟 SYSCLK 由 HSI/HSE/PLL 提供,最高可达 72MHz(F1)、168MHz(F4)、400MHz(H7)。

58. STM32 的中断优先级分组

STM32 中断优先级分为抢占优先级响应优先级

  • 抢占优先级高的中断可以嵌套抢占低优先级中断;
  • 同抢占优先级,响应优先级高的先执行;
  • 同抢占 + 同响应,按中断向量表顺序执行。优先级分组:将 4 位优先级位分配给抢占和响应,如分组 2:2 位抢占(0-3),2 位响应(0-3)。

59. STM32 的外部中断线

STM32F1 有 16 个外部中断线 EXTI0-EXTI15,每个 GPIO 端口的相同引脚共享一个中断线。例:PA0、PB0、PC0... 都共享 EXTI0 线。配置步骤:开启 GPIO 时钟、开启 AFIO 时钟、配置 GPIO 为输入、配置 EXTI 线、配置中断优先级、开启中断。

60. STM32 的定时器有哪些类型

  1. 基本定时器:TIM6、TIM7,仅用于定时、DAC 触发;
  2. 通用定时器:TIM2-TIM5,支持定时、输入捕获、输出比较、PWM;
  3. 高级定时器:TIM1、TIM8,支持通用定时器所有功能,还有互补输出、死区插入、刹车功能,用于电机控制。

61. STM32 高级定时器和通用定时器的区别

高级定时器比通用定时器多:

  1. 互补输出通道;
  2. 死区时间插入;
  3. 刹车功能(紧急停止);
  4. 重复计数器;
  5. 支持三相电机驱动。

62. STM32 的 DMA 有哪些通道?支持哪些外设?

STM32F1 有 2 个 DMA 控制器,DMA1 有 7 个通道,DMA2 有 5 个通道。每个通道对应固定的外设请求,如:

  • DMA1 通道 1:ADC1;
  • DMA1 通道 2:SPI1_RX;
  • DMA1 通道 3:SPI1_TX;
  • DMA1 通道 4:USART1_TX;
  • DMA1 通道 5:USART1_RX。支持外设:ADC、SPI、UART、I2C、定时器、DAC 等。

63. STM32 的 ADC 有哪些工作模式

  1. 单次转换模式:转换一次后停止;
  2. 连续转换模式:转换完成后自动开始下一次;
  3. 扫描模式:转换多个通道;
  4. 间断模式:扫描模式下,每次转换 n 个通道;
  5. 注入转换模式:插入常规转换,用于紧急采样。

64. STM32 的 DAC 工作原理

DAC(数模转换器)将数字量转换为模拟电压。STM32F4 有 2 个 12 位 DAC 通道,支持:

  1. 8 位 / 12 位分辨率;
  2. 单次转换 / 连续转换;
  3. 定时器触发转换;
  4. 输出缓冲(提高驱动能力)。

65. STM32 的低功耗模式有哪些?区别

模式 功耗 唤醒方式 保留内容
运行模式 最高 - 全部
睡眠模式 任何中断 全部
停止模式 更低 外部中断、RTC 寄存器、SRAM
待机模式 最低 唤醒引脚、RTC、看门狗 仅备份寄存器

66. STM32 的看门狗有哪些?区别

  1. 独立看门狗(IWDG):独立时钟(LSI),不受系统时钟影响,用于防止程序跑飞;
  2. 窗口看门狗(WWDG):系统时钟驱动,有窗口时间,只能在窗口内喂狗,用于检测程序异常超时。

67. STM32 的 GPIO 有哪些模式

  1. 输入模式:浮空输入、上拉输入、下拉输入、模拟输入;
  2. 输出模式:推挽输出、开漏输出;
  3. 复用功能模式:推挽复用、开漏复用;
  4. 模拟模式:ADC/DAC 使用。

68. STM32 的 USART 有哪些工作模式

  1. 异步模式:最常用,无需时钟线;
  2. 同步模式:带时钟线,高速传输;
  3. 半双工模式:单线传输;
  4. 多处理器模式:多机通信;
  5. 智能卡模式IrDA 红外模式LIN 模式

69. STM32 的 I2C 有哪些工作模式

  1. 主机模式:发起通信;
  2. 从机模式:响应主机;
  3. 标准模式:100kbps;
  4. 快速模式:400kbps;
  5. 快速模式 +:1Mbps;
  6. 高速模式:3.4Mbps。

70. STM32 的 SPI 有哪些工作模式

  1. 主机模式:提供时钟,发起通信;
  2. 从机模式:接收时钟,响应主机;
  3. 全双工模式:同时收发;
  4. 半双工模式:单线收发;
  5. 单向模式:仅发送 / 仅接收。

71. STM32 的 CAN 总线工作原理

CAN 是差分串行总线,抗干扰强,支持多主多从。

  • 帧类型:数据帧、远程帧、错误帧、过载帧;
  • 仲裁机制:ID 越小,优先级越高;
  • 错误处理:主动错误、被动错误、总线关闭。STM32 有 bxCAN 控制器,支持 CAN 2.0A/B 标准。

72. STM32 的 USB 工作原理

USB 是串行总线,支持热插拔,差分信号传输。STM32 支持:

  1. USB 2.0 全速:12Mbps;
  2. USB 2.0 高速:480Mbps(部分型号);
  3. 设备模式、主机模式、OTG 模式。

73. STM32 的 FMC/FSMC 工作原理

FMC/FSMC 是灵活的静态存储器控制器,用于扩展外部 SRAM、NOR Flash、NAND Flash、LCD 等。

  • FSMC:STM32F1/F4,支持静态存储器;
  • FMC:STM32H7/L4,增强版,支持更多存储器类型。

74. STM32 的 CRC 计算单元

STM32 内置硬件 CRC 计算单元,支持 CRC32 算法,多项式 0x04C11DB7。用途:数据校验、通信帧校验、固件校验。优点:比软件计算快几十倍。

75. STM32 的 RTC 实时时钟

RTC 是独立的实时时钟,使用 LSE 或 LSI 时钟,掉电后可由备用电池供电。功能:

  1. 日历功能(年、月、日、时、分、秒);
  2. 闹钟功能;
  3. 周期性唤醒;
  4. 时间戳功能。

76. FreeRTOS 任务状态有哪些

  1. 运行态:CPU 正在执行该任务;
  2. 就绪态:任务已就绪,等待 CPU 调度;
  3. 阻塞态:任务等待信号量、队列、延时,主动放弃 CPU;
  4. 挂起态:任务被手动挂起,不参与调度。

77. FreeRTOS 任务栈有什么作用

  1. 保存任务上下文(寄存器、PC),用于任务切换;
  2. 存储局部变量、函数调用栈;
  3. 每个任务独立栈,防止任务间栈溢出干扰。

78. FreeRTOS 任务切换时机

  1. 定时器滴答中断:同优先级时间片轮转切换;
  2. 高优先级任务就绪:抢占式调度立即切换;
  3. 任务主动阻塞:调用vTaskDelay、获取信号量失败等;
  4. 手动触发调度taskYIELD()强制任务切换。

79. FreeRTOS 空闲任务作用

  1. 系统最低优先级任务,无其他就绪任务时运行;
  2. 清理被删除任务的内存资源;
  3. 可在空闲任务钩子函数中实现低功耗休眠

80. FreeRTOS 钩子函数有哪些

  1. 空闲任务钩子:vApplicationIdleHook
  2. 滴答定时器钩子:vApplicationTickHook
  3. 任务栈溢出钩子:vApplicationStackOverflowHook
  4. 内存分配失败钩子:vApplicationMallocFailedHook

81. FreeRTOS 内存管理方式

  1. heap_1:最简单,只分配不释放;
  2. heap_2:动态分配释放,无碎片整理;
  3. heap_3:封装标准库malloc/free
  4. heap_4:支持碎片整理,最常用;
  5. heap_5:支持多块不连续内存区域。

82. FreeRTOS 消息队列工作原理

  1. 队列是环形缓冲区,存放固定长度数据;
  2. 入队:任务 / 中断发送数据,队列满则阻塞;
  3. 出队:任务读取数据,队列为空则阻塞;
  4. 支持多任务读写,线程安全。

83. FreeRTOS 任务通知优缺点

优点:

  1. 速度最快,比队列 / 信号量更快;
  2. 占用内存更小;缺点:
  3. 只能一对一通信;
  4. 中断只能发送通知,不能等待。

84. FreeRTOS 事件标志组使用场景

用于多事件触发,一个任务等待多个事件,任意一个或全部事件发生后唤醒。例:等待按键、串口接收、定时器触发任意一个事件。

85. 什么是软实时和硬实时

  1. 软实时:偶尔超时可接受,如 UI 界面、日志打印;
  2. 硬实时:必须在截止时间内完成,超时系统故障,如电机控制、工业控制、安全回路。

86. RTOS 如何保证实时性

  1. 抢占式调度,高优先级任务立即响应;
  2. 快速中断响应;
  3. 减少关中断时间;
  4. 合理划分任务优先级;
  5. 临界区代码尽可能短。

87. 什么是任务抖动,如何避免

任务抖动:任务执行时间不稳定、忽快忽慢。原因:频繁任务切换、中断过多、缓存抖动、优先级不合理。避免:

  1. 减少不必要任务切换;
  2. 精简中断服务函数;
  3. 合理分配优先级;
  4. 开启 CPU 缓存。

88. 什么是上下文切换,开销在哪

上下文切换:CPU 保存当前任务寄存器,加载下一个任务寄存器。开销:寄存器压栈出栈、缓存失效、流水线清空,切换越频繁 CPU 占用越高。

89. 什么是节拍定时器(SysTick)

SysTick 是 ARM Cortex‑M 内核自带 24 位定时器,用于 RTOS 系统滴答时钟,提供时间片、延时基准。

90. 中断服务函数中注意事项

  1. 禁止调用阻塞型 RTOS API(如xQueueReceive);
  2. 只能用带FromISR后缀的中断安全函数;
  3. 代码尽量短,快速清中断标志;
  4. 禁止使用浮点运算;
  5. 不做复杂逻辑。

91. 什么是中断延迟,如何减小

中断延迟:从中断触发到进入中断服务函数的时间。减小方法:

  1. 缩短关中断时间;
  2. 提高中断优先级;
  3. 精简临界区;
  4. 开启快速中断 FIQ。

92. 串口奇偶校验作用

校验数据传输是否出错:

  • 奇校验:数据位 + 校验位 1 的个数为奇数;
  • 偶校验:为偶数;仅检测奇数个错误,无法校验偶数位错误。

93. 串口波特率误差影响

误差过大会导致数据乱码、丢包。STM32 一般误差 < 2% 可正常通信。

94. 什么是 RS485 半双工、全双工

  1. 半双工:一对差分线,收发切换,常用;
  2. 全双工:两对差分线,同时收发,成本高。

95. CAN 总线仲裁机制

采用非破坏性逐位仲裁:ID 越小优先级越高,隐性电平(1)被显性电平(0)覆盖,优先级低的自动退出发送。

96. CAN 总线 5 种帧类型

  1. 数据帧:发送数据;
  2. 远程帧:请求对方发送数据;
  3. 错误帧:节点检测到错误发送;
  4. 过载帧:节点未就绪,延迟下一帧;
  5. 间隔帧:帧间间隔。

97. CAN 标准帧和扩展帧区别

  1. 标准帧:11 位 ID;
  2. 扩展帧:29 位 ID,可寻址更多节点。

98. I2C 仲裁与时钟拉伸

  1. 仲裁:多主机同时发送,SDA 冲突时低电平获胜;
  2. 时钟拉伸:从机拉低 SCL,强制主机等待,用于低速从机。

99. SPI 四种模式

CPOL 时钟极性、CPHA 时钟相位决定:

  • Mode0:CPOL=0,CPHA=0;最常用;
  • Mode1:CPOL=0,CPHA=1;
  • Mode2:CPOL=1,CPHA=0;
  • Mode3:CPOL=1,CPHA=1。

100. 什么是差分信号,优点

差分信号:两根信号线传输相反电平。优点:抗干扰强、抑制共模噪声、传输距离远、速率高。

101. 上拉电阻作用

  1. 提高驱动能力;
  2. 防止 IO 浮空;
  3. I2C 必须上拉;
  4. 匹配阻抗,减少信号反射。

102. 什么是开漏输出,推挽输出

  1. 推挽输出:高低电平都有驱动,输出强;
  2. 开漏输出:只能输出低电平,高电平需外部上拉,支持线与,用于 I2C。

103. 什么是阻抗匹配

高速信号时,源端、传输线、负载阻抗一致,防止信号反射、振铃、过冲。

104. 什么是 EMC/EMI,如何优化

  • EMI:电磁干扰;EMC:抗电磁干扰;优化:电源滤波、接地、差分走线、缩短走线、磁珠、屏蔽、降低时钟频率。

105. 电源滤波电容为什么一大一小

大电解电容滤低频干扰,小陶瓷电容滤高频干扰,覆盖全频段。

106. 什么是地弹噪声

开关电流流过地线阻抗产生电压波动,导致信号不稳定,通过多点接地、降低回路面积优化。

107. ADC 采样率、奈奎斯特采样定理

采样率必须大于信号最高频率 2 倍,否则混叠失真。

108. 什么是过采样,作用

多次采样取平均,提高 ADC 有效分辨率,抑制噪声。

109. DAC 输出为什么加运放

提高驱动能力、阻抗匹配、放大电压、缓冲隔离。

110. 硬件看门狗和软件看门狗区别

  1. 硬件看门狗:独立硬件,时钟独立,程序卡死必复位;
  2. 软件看门狗:任务检测,软件可控,可被恶意代码绕开。

111. 什么是 JTAG/SWD,区别

  1. JTAG:5 根线,调试下载,功能全;
  2. SWD:2 根线,引脚少,速度快,STM32 主流。

112. 程序下载方式有哪些

SWD/JTAG、串口 ISP、USB DFU、IAP 在线升级。

113. 什么是 IAP(在应用编程)

无需拆卸芯片,通过串口 / 网络 / USB 更新固件,分 Bootloader+App。

114. Bootloader 和 App 分区

Flash 分为引导区(Boot)、应用区(App),Boot 校验后跳转 App。

115. 程序跑飞常见原因

栈溢出、数组越界、指针错误、中断未清标志、硬件干扰、电源不稳。

116. 如何定位 HardFault 硬故障

  1. 读取 LR 寄存器返回地址;
  2. 查看栈内寄存器;
  3. 定位异常指令;
  4. Keil 开启硬件断点、内存监控。

117. 什么是内存屏障

防止 CPU 乱序执行,保证读写顺序,用于多核、DMA、寄存器访问。

118. 什么是 Cache,D‑Cache/I‑Cache

  • I‑Cache:指令缓存;
  • D‑Cache:数据缓存;提高访问速度,STM32H7/L4 常用。

119. Cache 一致性问题

DMA 读写内存时,Cache 数据和内存不一致,需刷新 / 清理 Cache

120. 什么是重入函数

可被中断 / 多任务安全调用的函数,不使用全局变量,只使用局部变量或加互斥保护。

121. 什么是竞态条件

多任务 / 多中断同时访问共享资源,执行顺序不确定导致错误,用临界区、互斥锁解决。

122. 什么是原子操作

不可分割的操作,执行中不会被打断,用于简单变量同步,无需锁。

123. 项目中如何做代码健壮性

  1. 指针判空;
  2. 数组越界检查;
  3. 输入参数校验;
  4. 异常处理;
  5. 看门狗;
  6. 日志调试;
  7. 超时机制。

124. 嵌入式常用调试手段

  1. 串口打印;
  2. Keil 在线调试、断点;
  3. 逻辑分析仪;
  4. 示波器;
  5. 硬件探针;
  6. 日志存储。

125. 如何排查串口乱码问题

  1. 波特率误差;
  2. 电平不匹配;
  3. 接地不良;
  4. 干扰;
  5. 数据位 / 停止位 / 校验位不一致;
  6. 收发时序问题。

126. Linux 常用基础命令(嵌入式必背)

  • 文件操作:lscdcpmvrmmkdirtouchchmodchown
  • 查看内容:catmorelessheadtailgrep
  • 系统状态:pstopfreedfduifconfigping
  • 压缩解压:targzipunzip
  • 其他:sudosurebootshutdownscp

127. Linux 进程和线程的区别

  1. 资源:进程是资源分配的基本单位,线程是 CPU 调度的基本单位;
  2. 开销:进程切换开销大,线程切换开销小;
  3. 地址空间:进程有独立地址空间,线程共享进程地址空间;
  4. 通信:进程间通信复杂,线程间通信简单(共享内存);
  5. 健壮性:进程崩溃不影响其他进程,线程崩溃会导致整个进程崩溃。

128. Linux 进程间通信(IPC)方式

  1. 管道 / 命名管道:简单,半双工,父子进程通信;
  2. 信号量:同步互斥;
  3. 消息队列:传递消息,异步;
  4. 共享内存:最快,需同步保护;
  5. 信号:异步通知;
  6. Socket:跨主机通信。

129. Linux 线程间同步方式

  1. 互斥锁:保护临界区;
  2. 条件变量:等待事件;
  3. 信号量:同步计数;
  4. 读写锁:读多写少场景。

130. 嵌入式 Linux 常用文件系统

  1. ext4:通用文件系统,稳定;
  2. YAFFS2:NAND Flash 专用,掉电安全;
  3. UBIFS:新一代 NAND Flash 文件系统,性能更好;
  4. JFFS2:NOR Flash 专用;
  5. tmpfs:内存文件系统,速度快,掉电丢失;
  6. FAT32:兼容 Windows,U 盘常用。

131. Linux 启动流程

  1. BIOS/UEFI:硬件自检,加载引导程序;
  2. Bootloader(U-Boot):初始化硬件,加载内核;
  3. Linux 内核:初始化内核,挂载根文件系统;
  4. init 进程:启动系统服务,进入用户态。

132. U-Boot 的作用

  1. 初始化硬件(DDR、Flash、串口、网络);
  2. 提供命令行交互;
  3. 加载 Linux 内核和设备树到内存;
  4. 传递启动参数给内核;
  5. 支持固件升级。

133. 什么是设备树(Device Tree)

设备树是描述硬件资源的数据结构,将硬件信息从内核代码中分离出来,内核通过解析设备树来识别硬件。

  • 优点:内核无需修改,只需更换设备树即可适配不同硬件;
  • 组成:.dts源文件、.dtsi头文件、.dtb二进制文件。

134. Linux 驱动分类及区别

  1. 字符设备驱动:按字节流访问,如串口、LED、按键;
  2. 块设备驱动:按块访问,如硬盘、Flash;
  3. 网络设备驱动:处理网络数据,如网卡。

135. 字符设备驱动基本框架

  1. 分配设备号(alloc_chrdev_region);
  2. 定义file_operations结构体,实现openreadwriteioctl等函数;
  3. 注册字符设备(cdev_add);
  4. 创建设备节点(class_createdevice_create);
  5. 注销设备。

136. 什么是平台总线(Platform Bus)

平台总线是 Linux 为无总线的外设设计的虚拟总线,将驱动和设备分离。

  • 设备端:描述硬件资源(地址、中断);
  • 驱动端:实现驱动逻辑;
  • 总线:匹配设备和驱动。

137. Linux 中断处理流程

  1. 硬件触发中断;
  2. CPU 跳转到中断向量表;
  3. 内核保存上下文,调用中断处理函数;
  4. 中断处理函数执行,清中断标志;
  5. 恢复上下文,返回。

138. Linux 内核空间和用户空间区别

  1. 地址空间:32 位系统内核空间 1GB(0xC0000000-0xFFFFFFFF),用户空间 3GB;
  2. 权限:内核空间最高权限,可直接访问硬件;用户空间最低权限;
  3. 通信:通过系统调用、ioctlmmap等方式通信。

139. 什么是 mmap,作用

mmap将设备内存或文件映射到用户空间,用户可直接读写,无需内核拷贝,提高效率。

  • 用途:高速数据传输、LCD 显示、摄像头数据采集。

140. FreeRTOS 和 UCOS-II 的区别

  1. 开源性:FreeRTOS 完全开源免费;UCOS-II 商业收费;
  2. 功能:FreeRTOS 功能精简,UCOS-II 功能更全;
  3. 资源占用:FreeRTOS 更小,适合资源受限的 MCU;
  4. 生态:FreeRTOS 生态更好,支持更多芯片。

141. FreeRTOS 和 RT-Thread 的区别

  1. 开源协议:FreeRTOS MIT 协议;RT-Thread Apache 协议;
  2. 组件:RT-Thread 组件更丰富(文件系统、网络、GUI);
  3. 内核:RT-Thread 支持优先级位图算法,调度更快;
  4. 生态:RT-Thread 国内生态更好,中文资料多。

142. RTOS 任务优先级分配原则

  1. 紧急优先:实时性要求高的任务优先级高;
  2. 短任务优先:执行时间短的任务优先级高;
  3. IO 密集型优先:频繁阻塞的任务优先级高;
  4. 避免优先级反转:使用互斥锁带优先级继承。

143. 中断优先级和任务优先级的区别

  1. 中断优先级:高于所有任务优先级,中断可抢占任何任务;
  2. 任务优先级:任务之间的调度优先级;
  3. 中断服务函数中不能阻塞,只能唤醒任务。

144. FreeRTOS 定时器实现原理

FreeRTOS 定时器分为软件定时器硬件定时器

  • 软件定时器:基于 SysTick 滴答时钟,精度低,资源占用少;
  • 硬件定时器:基于 MCU 硬件定时器,精度高,资源占用多。

145. 什么是任务栈溢出,如何检测

任务栈溢出:任务栈空间不足,覆盖其他内存。检测方法:

  1. FreeRTOS 开启栈溢出检测;
  2. 栈初始化时填充固定值,运行时检查;
  3. 预留足够的栈空间。

146. 什么是内存池,优点

内存池预先分配一块连续内存,分成固定大小的块,使用时直接分配,释放时归还。优点:

  1. 避免内存碎片;
  2. 分配释放速度快;
  3. 不会出现内存分配失败。

147. 嵌入式系统分层架构

  1. 硬件层:MCU、外设;
  2. 驱动层:硬件驱动程序;
  3. 操作系统层:RTOS/Linux 内核;
  4. 中间件层:协议栈、文件系统、GUI;
  5. 应用层:业务逻辑。

148. 什么是模块化设计,优点

模块化设计将系统分成独立的模块,模块之间通过接口通信。优点:

  1. 代码复用;
  2. 便于调试和维护;
  3. 便于团队协作;
  4. 便于升级和扩展。

149. 状态机的实现方式

  1. switch-case:简单状态机;
  2. 函数指针表:复杂状态机;
  3. 状态模式:面向对象实现。
  • 用途:按键处理、通信协议解析、流程控制。

150. 嵌入式系统错误处理机制

  1. 返回值检查:函数调用后检查返回值;
  2. 断言:调试阶段检查错误;
  3. 异常处理:HardFault、总线错误等;
  4. 看门狗:程序卡死复位;
  5. 日志记录:记录错误信息。

151. 嵌入式常用排序算法

  1. 冒泡排序:简单,适合小数据量;
  2. 选择排序:交换次数少;
  3. 插入排序:适合基本有序的数据;
  4. 快速排序:速度快,适合大数据量;
  5. 归并排序:稳定,适合大数据量。

152. 嵌入式常用查找算法

  1. 顺序查找:简单,无序数据;
  2. 二分查找:速度快,有序数据;
  3. 哈希查找:最快,需要哈希表。

153. CRC 校验原理

CRC(循环冗余校验)是一种数据校验算法,通过多项式除法计算校验值,检测数据传输错误。

  • 常用:CRC16(Modbus)、CRC32(以太网)。

154. 嵌入式常用滤波算法

  1. 限幅滤波:去除尖峰干扰;
  2. 中位值滤波:去除脉冲干扰;
  3. 算术平均滤波:去除随机噪声;
  4. 滑动平均滤波:实时性好;
  5. 卡尔曼滤波:适合动态系统。

155. 什么是 FIR 和 IIR 滤波器

  1. FIR 滤波器:有限长单位冲激响应,线性相位,稳定;
  2. IIR 滤波器:无限长单位冲激响应,非线性相位,可能不稳定,阶数低。

156. 项目中如何做低功耗优化

  1. 硬件:选用低功耗芯片,关闭不用的外设,使用低功耗电源;
  2. 软件
    • 空闲时进入低功耗模式;
    • 降低系统主频;
    • 关闭不用的时钟;
    • 用中断代替轮询;
    • 优化算法,减少 CPU 占用。

157. 如何排查内存泄漏

  1. 静态分析:使用代码检查工具(如 Cppcheck);
  2. 动态检测:使用 Valgrind(Linux)、FreeRTOS 内存跟踪;
  3. 日志记录:记录 malloc 和 free 的调用;
  4. 内存统计:定期查看内存使用情况。

158. 如何做单元测试

  1. 编写测试用例,覆盖正常、异常、边界情况;
  2. 使用单元测试框架(如 Unity、Google Test);
  3. 模拟硬件和依赖;
  4. 自动化测试。

159. 如何处理硬件故障

  1. 检测:定期检测硬件状态;
  2. 隔离:故障模块隔离,不影响其他模块;
  3. 降级:系统降级运行;
  4. 复位:硬件复位恢复;
  5. 报警:通知用户。

160. 什么是固件升级,如何实现

固件升级是更新设备程序的过程,分为:

  1. 本地升级:串口、USB、SD 卡;
  2. 远程升级:网络、OTA;
  • 实现:Bootloader+App 分区,校验固件完整性,备份旧固件。

161. OTA 升级注意事项

  1. 校验:固件 MD5/SHA 校验,防止损坏;
  2. 备份:备份旧固件,升级失败回滚;
  3. 断点续传:大文件支持断点续传;
  4. 安全:固件加密,防止恶意篡改;
  5. 不掉电:升级过程中防止掉电。

162. 什么是实时操作系统,和通用操作系统的区别

  1. 实时性:RTOS 保证任务在截止时间内完成;通用操作系统不保证;
  2. 调度:RTOS 抢占式调度;通用操作系统时间片轮转;
  3. 资源占用:RTOS 资源占用小;通用操作系统资源占用大;
  4. 可靠性:RTOS 可靠性高;通用操作系统可靠性低。

163. 什么是硬实时和软实时

  1. 硬实时:必须在截止时间内完成,超时系统故障,如工业控制、航空航天;
  2. 软实时:偶尔超时可接受,如视频播放、数据采集。

164. 什么是上下文切换,开销在哪里

上下文切换是 CPU 保存当前任务的寄存器,加载下一个任务的寄存器的过程。开销:

  1. 寄存器压栈出栈;
  2. 缓存失效;
  3. 流水线清空;
  4. 内核调度开销。

165. 什么是临界区,如何保护

临界区是访问共享资源的代码段,执行期间不能被打断。保护方法:

  1. 关中断;
  2. 互斥锁;
  3. 信号量;
  4. 原子操作。

166. 什么是优先级反转,如何解决

优先级反转是高优先级任务因等待低优先级任务持有的锁,被中间优先级任务抢占,导致高优先级任务长时间得不到执行。解决方法:

  1. 优先级继承;
  2. 优先级天花板;
  3. 减少临界区长度。

167. 什么是死锁,产生条件

死锁是两个或多个任务互相等待对方持有的资源,导致所有任务都无法继续执行。产生条件:

  1. 互斥;
  2. 占有并等待;
  3. 不可剥夺;
  4. 循环等待。

168. 什么是竞态条件,如何避免

竞态条件是多任务 / 多中断同时访问共享资源,执行顺序不确定导致错误。避免方法:

  1. 临界区保护;
  2. 原子操作;
  3. 避免共享资源。

169. 什么是原子操作,适用场景

原子操作是不可分割的操作,执行中不会被打断。适用场景:简单变量的加减、赋值,无需锁保护。

170. 什么是内存屏障,作用

内存屏障防止 CPU 乱序执行,保证读写操作的顺序。作用:

  1. 多核 CPU 之间的同步;
  2. DMA 和 CPU 之间的同步;
  3. 寄存器访问。

171. 什么是 Cache,作用

Cache 是 CPU 和内存之间的高速缓存,存放 CPU 最近使用的数据和指令。作用:提高 CPU 访问速度,减少内存访问次数。

172. Cache 一致性问题,如何解决

Cache 一致性问题是多个 CPU 或 DMA 访问同一内存时,Cache 数据和内存数据不一致。解决方法:

  1. 刷新 Cache;
  2. 使 Cache 无效;
  3. 禁用 Cache。

173. 什么是 DMA,优点

DMA(直接内存访问)是硬件直接在内存和外设之间传输数据,无需 CPU 参与。优点:

  1. 解放 CPU;
  2. 传输速度快;
  3. 适合大量数据传输。

174. 什么是中断,优点

中断是外设主动通知 CPU 的机制,CPU 无需轮询外设状态。优点:

  1. 提高 CPU 利用率;
  2. 实时性强;
  3. 响应速度快。

175. 什么是轮询,缺点

轮询是 CPU 不断循环查询外设状态。缺点:

  1. CPU 占用高;
  2. 实时性差;
  3. 功耗高。

176. 讲一个你最熟悉的嵌入式项目,你负责了哪些部分

标准口述模板:我做过基于 STM32+FreeRTOS 的工业采集 / 电机控制 / 智能设备项目,主要负责:

  1. 硬件外设驱动开发:GPIO、UART、SPI、I2C、ADC、DMA、定时器;
  2. RTOS 任务划分、优先级设计、消息队列、互斥锁、任务通知等通信机制;
  3. 通信协议实现:Modbus-RTU、串口协议、CAN 总线;
  4. 数据滤波、CRC 校验、低功耗、看门狗、异常处理;
  5. 代码模块化、单元测试、稳定性优化、OTA 升级。通过该项目掌握了 RTOS 调度、多任务同步、硬件底层调试,具备独立开发嵌入式固件能力。

177. 项目中遇到的最大 bug 是什么?怎么解决的

高频真实问题 + 标准答案问题:多任务下串口数据乱码、丢包、HardFault 死机。原因:中断里调用阻塞函数、共享缓冲区无互斥保护、栈溢出、DMA 缓存和 Cache 不一致、中断标志未清零。解决

  1. 中断仅做数据接收,通过队列抛给任务解析;
  2. 临界区加互斥锁 / 关中断;
  3. 增大任务栈、开启栈溢出检测;
  4. DMA 使用内存屏障、清理 Cache;
  5. 严格清除中断挂起标志位。

178. 如何保证嵌入式系统稳定性

  1. 软件层面:看门狗复位、超时检测、参数校验、指针判空、数组越界保护、异常处理、日志记录;
  2. RTOS 层面:合理划分优先级、避免优先级反转、临界区精简、内存池代替动态 malloc;
  3. 硬件层面:电源滤波、抗干扰、上拉下拉、EMC 优化、静电防护;
  4. 代码层面:模块化、可重入函数、减少全局变量、代码规范。

179. 你对 OTA 升级的理解,升级失败怎么处理

OTA 即远程固件升级,分为Bootloader+App架构。

  1. Bootloader 校验固件完整性(CRC/MD5);
  2. 校验通过则擦除旧固件,写入新固件;
  3. 升级失败:启用双备份分区,自动回滚旧固件,保证设备不死机;
  4. 升级过程做掉电保护、断点续传。

180. 什么是 Modbus 协议,RTU 和 TCP 区别

Modbus 是工业标准通信协议。

  1. Modbus‑RTU:串口 / 485 传输,二进制格式,CRC16 校验,半双工;
  2. Modbus‑TCP:以太网传输,TCP/IP 封装,MBAP 头,无 CRC 校验;常用功能码:读线圈、读保持寄存器、写寄存器。

181. 485 总线多节点通信注意事项

  1. A/B 线不能接反;
  2. 总线两端加 120Ω 终端电阻;
  3. 收发使能引脚正确切换,避免总线冲突;
  4. 地址唯一,避免多节点同时发送;
  5. 共地处理,减少干扰。

182. 如何实现通信协议解析,状态机怎么写

一般用状态机 + 环形缓冲区实现:

  1. 串口中断接收数据存入环形缓冲区;
  2. 任务循环读取缓冲区;
  3. 状态机:空闲→接收帧头→接收长度→接收数据→校验→解析;
  4. 校验失败直接丢弃,防止脏数据堆积。

183. 环形缓冲区作用及实现

环形缓冲区用于串口、DMA 接收,解决数据覆盖、丢包问题。结构:buf 数组、头指针、尾指针;判空:头 = 尾;判满:(尾 + 1)% size == 头;优点:FIFO 先进先出,读写互不干扰,支持异步接收。

184. 什么是重入函数,如何编写可重入函数

重入函数:可被中断、多任务多次安全调用。编写要求:

  1. 不使用全局变量、静态变量;
  2. 所有变量用局部变量;
  3. 访问共享资源加互斥保护;
  4. 不调用不可重入函数。

185. 嵌入式代码规范有哪些

  1. 命名规范:见名知意,驼峰 / 下划线命名;
  2. 注释规范:函数、关键逻辑注释;
  3. 禁止魔数,全部用宏定义;
  4. 模块分离,一个.c 对应一个功能;
  5. 禁止长函数、长循环;
  6. 输入参数检查、指针判空。

186. 什么是代码耦合,如何解耦

耦合:模块间依赖太强,修改一处多处受影响。解耦方式:

  1. 分层设计,硬件驱动与业务逻辑分离;
  2. 统一接口函数;
  3. 用消息队列、事件标志通信,不直接调用;
  4. 结构体封装数据。

187. 嵌入式低功耗设计从哪几个方面入手

  1. 硬件:关闭闲置外设电源、IO 配置浮空 / 上下拉;
  2. 时钟:关闭不用的 AHB/APB 时钟;
  3. 模式:空闲进入睡眠、停止、待机模式;
  4. 调度:用中断代替轮询,CPU 空闲休眠;
  5. 主频:降低系统时钟。

188. 硬件抗干扰怎么处理

  1. 电源:电源滤波电容、磁珠、LC 滤波;
  2. 布线:差分走线、缩短高速线、回路面积最小;
  3. 接地:单点接地、模拟地数字地分离;
  4. 软件:多次采样平均、看门狗、软件滤波;
  5. 屏蔽:增加屏蔽罩、静电防护。

189. HardFault 错误如何快速定位

  1. 进入 HardFault 后,读取 LR 寄存器,获取异常返回地址;
  2. 查看栈内 R0‑R15 寄存器,定位出错指令;
  3. Keil 反汇编查找对应代码行;
  4. 常见原因:空指针、数组越界、栈溢出、中断未清标志。

190. 内存泄漏和内存碎片的区别与处理

  1. 内存泄漏:malloc 未 free,长期运行内存耗尽;处理:少用动态内存,用内存池;
  2. 内存碎片:频繁分配释放产生零散小块,无法分配大块内存;处理:内存池、heap4 算法、静态数组。

191. FreeRTOS 中任务通知和消息队列怎么选

  1. 任务通知:速度最快、占用最小,一对一,适合简单同步;
  2. 消息队列:支持多对多、缓存多条数据,适合批量数据传输;简单同步用任务通知,复杂通信用队列。

192. 互斥锁和二值信号量区别

  1. 互斥锁:用于资源互斥,自带优先级继承,解决优先级反转;必须谁获取谁释放;
  2. 二值信号量:用于任务同步,无优先级继承,谁都可以释放;互斥锁保护资源,信号量用于通知。

193. 抢占式和时间片轮转调度区别

  1. 抢占式:高优先级就绪,立即抢占低优先级,实时性强;
  2. 时间片轮转:同优先级任务轮流执行,公平调度;FreeRTOS 默认:抢占式 + 同优先级时间片轮转。

194. 中断服务函数为什么要短

  1. 中断内执行太久,屏蔽其他中断,降低系统实时性;
  2. 容易导致中断丢失、数据丢失;
  3. 规范:中断只做接收 / 标记,业务逻辑交给任务处理。

195. 你为什么选择嵌入式行业,职业规划

面试标准答案:我喜欢软硬件结合,嵌入式贴近硬件、逻辑性强,稳定性要求高,适合长期深耕。短期 1‑2 年:熟练掌握 MCU 开发、RTOS、通信协议,独立负责项目;中期 3‑5 年:向 Linux 嵌入式、驱动开发、系统架构方向发展;长期成为软硬件综合型工程师。

196. 遇到不会的问题怎么处理

  1. 先查阅数据手册、官方参考手册;
  2. 搜索行业方案、参考成熟代码;
  3. 用示波器、逻辑分析仪定位问题;
  4. 总结复盘,沉淀到自己知识库,避免重复踩坑。

197. 怎么快速上手一个新的 MCU

  1. 看官方手册,熟悉时钟、GPIO、外设框架;
  2. 跑官方 Demo 例程;
  3. 从点灯、串口、定时器等基础外设逐个调试;
  4. 迁移 RTOS,搭建工程框架。

198. 团队合作中你扮演什么角色

注重模块化分工,负责底层驱动和核心逻辑开发;善于沟通,及时同步进度;遇到问题主动排查,配合队友联调;重视代码规范和稳定性,保障项目交付。

199. 你觉得嵌入式工程师最重要的能力是什么

  1. 扎实的 C 语言、硬件基础;
  2. 调试排错能力;
  3. 严谨细致,注重稳定性;
  4. 持续学习,跟进新技术;
  5. 软硬件结合思维。

200. 未来嵌入式发展方向

  1. 工业控制、物联网 IoT、智能硬件;
  2. 车载电子、新能源、电机控制;
  3. 嵌入式 Linux、驱动开发;
  4. AIoT 边缘计算、低功耗设备;行业需求稳定,长期前景好。
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐