嵌入式软件开发面试题汇总

发布于:2025-06-30 ⋅ 阅读:(16) ⋅ 点赞:(0)

目录

🕐什么是字节对齐?有什么作用?

🕑列举 ARM 处理器的主要特点?

🕒ARM 有多少个寄存器?

🕓ARM 处理器的 7 种工作模式分别是什么?

🕔ARM 内核和 ARM SoC 处理器的异同是什么?

🕕ARM 通用寄存器中 3 个特殊寄存器的名字和作用是什么?

🕖描述 CPSR 寄存器中相关 Bit 的含义和作用?

🕗什么是立即数?使用时的注意要点是什么?

🕘什么是处理器现场?如何保存现场?

🕙什么是满堆栈和空堆栈?

🕚什么是满递减栈、空递减栈、满递增栈、空递增栈?

🕛ATPCS 规定的参数传递规则是什么?

🕜软件中断与硬件中断的区别是什么?ARM 提供的软件中断指令是什么?

🕝什么是异常?

🕞ARM 架构支持的七种异常类型是什么?

🕟boot loader 的主要作用是什么?

🕠U-Boot 是如何启动内核的?

🕡U-Boot 中 bootcmd 和 bootargs 分别有什么作用?

🕢vmlinux、Image、zImage、uImage 的区别是什么?

🕣Linux 内核中 Makefile、Kconfig、.config 的关系是什么?

🕤简述 Linux 内核的总体启动流程。

🕥简述 Linux 开发板的启动过程。

🕦Linux 中字符设备和块设备的主要区别是什么?

🕧为什么开发板一般不需要静态库?

🕐Linux 有哪几种驱动类型?

🕑Linux 中编写一个字符设备驱动程序的基本步骤?

🕒什么是设备树?设备树的作用是什么?

🕓什么是文件系统?其功能包括哪些部分?

🕔什么是根文件系统?

🕕GCC 编译器编译的完整流程是什么?各阶段的作用是什么?

🕖在 make menuconfig 界面下,驱动的三种状态(Y、N、M)分别表示什么含义?

🕗有没有做过 Linux 的驱动开发?

🕘FreeRTOS 有哪些特征?

🕙FreeRTOS 中任务状态有哪些,怎么转换的?

🕚FreeRTOS 任务默认调度方式是什么?

🕛FreeRTOS 中任务的优先级如何设置?可以设置多少级?每级优先级的含义?


🕐什么是字节对齐?有什么作用?

指在内存中存储数据时,按照特定规则对齐数据地址。
它的目的是提高内存访问效率,避免 CPU 在访问数据时跨越多个内存单元。

🕑列举 ARM 处理器的主要特点?

低功耗、节能:非常适合电池供电设备,如手机、平板等。

RISC架构:采用精简指令集,执行效率高,硬件设计简洁。(RISC:Reduced Instruction Set Computer RISC)

高集成度:集成度高,可嵌入多个外设模块,适合 SoC 设计。

可授权架构:ARM 公司授权 IP,厂商可自主定制 CPU 内核。

良好的生态支持:拥有成熟的编译器、工具链、操作系统支持(如 Linux、Android)。

🕒ARM 有多少个寄存器?

ARM 通常提供 37 个寄存器,其中 31 个为通用寄存器(含用户模式和异常模式下的别名),以及 6 个状态寄存器。在正常执行中,程序员最常接触的是前 16 个通用寄存器(R0–R15)和一个程序状态寄存器 CPSR,其余用于异常处理和模式切换。

🕓ARM 处理器的 7 种工作模式分别是什么?

1.用户模式(USR):正常程序执行模式,不能直接切换到其他模式
2.系统模式(SYS):运行操作系统的特权任务,与用户模式类似,但具有可以直接切换到其他模式等特权
3.快中断模式(FIQ):支持高速数据传输及通道处理,FIQ异常响应时进入此模式
4.中断模式(IRQ):用于通用中断处理,IRQ异常响应时进入此模式
5.管理模式(SVC):操作系统保护模式,系统复位和软件中断响应时进入此模式(由系统调用执行软中断SWI命令触发)
6.中止模式(ABT):用于支持虚拟内存和/或存储器保护,在ARM7TDMI没有大用处
7.未定义模式(UND):支持硬件协处理器的软件仿真,未定义指令异常响应时进入此模式

🕔ARM 内核和 ARM SoC 处理器的异同是什么?

ARM 内核(Core)是指 CPU 的处理核心本身,负责指令执行、寄存器操作和基本运算;

而 ARM SoC 是基于 ARM 内核构建的完整系统芯片,除了 CPU 核心外还集成了内存控制器、图形处理器、I/O 接口等多个模块。

🕕ARM 通用寄存器中 3 个特殊寄存器的名字和作用是什么?

R13 - SP(Stack Pointer)栈指针
指向当前栈顶地址,管理函数调用过程中的局部变量、返回地址、参数压栈等。

R14 - LR(Link Register)链接寄存器
保存函数调用返回地址,BL(Branch with Link)指令会把返回地址保存在 LR 中,供返回时使用。

R15 - PC(Program Counter)程序计数器
指向当前正在执行的指令地址。ARM 中由于流水线,PC 实际值可能略超前当前执行指令地址(通常+8字节偏移)。

🕖描述 CPSR 寄存器中相关 Bit 的含义和作用?

CPSR(Current Program Status Register)是 ARM 中用于记录程序当前状态的寄存器。

它包含条件位(指令进行算术运算后的结果是否有进位,借位等),I位(IRQ异常允许位),F位(FIQ异常允许位),T位(ARM/Thumb工作状态),M位(处理器工作模式)。

🕗什么是立即数?使用时的注意要点是什么?

在 ARM 指令集中,立即数是指直接写入指令中的常数值,用于操作数或寻址。

使用时需注意两点:

(1)立即数前要加 # 号表示常量(如 MOV R0, #5);

(2)ARM 指令是 32 位长度,其中用于立即数的字段为 12 位:8 位表示有效数值(基数 B)+ 4 位表示右旋次数 M,最终立即数等于 B 循环右移 M×2 位组成一个 32 位值。

由于这种编码方式限制了立即数的表示范围,因此并不能表示任意数值,使用时需判断是否为合法立即数

🕘什么是处理器现场?如何保存现场?

处理器现场是指进程在被中断打断时刻的各种寄存器的值。

保存现场的核心是将这些信息压到内核栈,中断结束时再恢复这些信息。

🕙什么是满堆栈和空堆栈?

满堆栈(Full Stack)指栈顶指针指向当前已使用的栈顶位置,入栈前需要先移动指针再写入数据;

空堆栈(Empty Stack)则指栈顶指针始终指向下一个可用的空位置,入栈时直接写入当前指针位置的数据,然后更新指针。

🕚什么是满递减栈、空递减栈、满递增栈、空递增栈?

这些是栈的组织方式,区别在于栈顶指针的位置语义(满 or 空)栈增长方向(递增 or 递减)。

  • “满”表示栈顶指针指向当前栈顶数据

  • “空”表示栈顶指向下一个空位

  • “递增”表示入栈时地址从低地址向高地址增长

  • “递减”则表示地址从高地址向低地址增长

满递减栈(Full Descending Stack) ← ARM 默认

  • 栈顶指向当前元素

  • 新元素入栈:指针先减,数据写入低地址

  • 栈从高地址向低地址增长

  • 常用于嵌入式处理器(如 ARM)

空递减栈(Empty Descending Stack)

  • 栈顶指向空地址

  • 新元素入栈:数据写入当前地址,然后指针减

  • 也从高地址向低地址增长

满递增栈(Full Ascending Stack)

  • 栈顶指向当前元素

  • 新元素入栈:指针先加,数据写入高地址

  • 栈从低地址向高地址增长

空递增栈(Empty Ascending Stack)

  • 栈顶指向空地址

  • 新元素入栈:数据写入当前地址,然后指针加

🕛ATPCS 规定的参数传递规则是什么?

ATPCS(ARM Procedure Call Standard)是 ARM 平台上的函数调用约定,规定了函数参数和返回值的传递方式。
一般来说,当参数个数不超过4个时,使用r0~r3这4个寄存器来传递参数;

如果参数个数超过4个,剩余的参数通过数据栈来传递。

🕜软件中断与硬件中断的区别是什么?ARM 提供的软件中断指令是什么?

硬件中断是由外部硬件设备发起的中断信号,处理器响应后暂停当前程序执行,进入中断服务程序;

软件中断是程序内部通过指令主动触发的一种中断,通常用于系统调用或异常处理。

ARM 中触发软件中断的指令是 SWI(Software Interrupt),现在新版本也用 SVC(Supervisor Call)。

🕝什么是异常?

由于内部或者外部的一些事件 , 导致处理器停下正在处理的工作, 转而去处理这些发生的事;当遇到异常的时候, 先将处理器状态保存起来, 以便执行完异常处理程序后, 可以恢复处理器状态, 继续执行异常出现点下面的代码;

在一个时间点可以出现 多个异常;当异常发生的时候, 程序被强行从一个固定的内存地址执行, 每个种类的异常都有对应的一固定内存地址, 这个内存地址就是异常向量;

🕞ARM 架构支持的七种异常类型是什么?

1).Reset : 处理器在工作时, 突然按下重启键, 就会触发该异常;
2).Undefined instructions : 处理器无法识别指令的异常, 处理器执行的指令是有规范的, 如果尝试执行不符合要求的指令, 就会进入到该异常指令对应的地址中;
3).Software interrupt (SWI) : 软中断, 软件中需要去打断处理器工作, 可以使用软中断来执行 ;
4).Prefetch Abort (instruction fetch memory abort) : 预取指令失败, ARM 在执行指令的过程中, 要先去预取指令准备执行, 如果预取指令失败, 就会产生该异常;
5).Data Abort (data access memory abort) : 读取数据失败;
6).IRQ (interrupt) : 普通中断;
7).FIQ (fast interrupt) : 快速中断, 快速中断要比普通中断响应速度要快一些;

🕟boot loader 的主要作用是什么?

Boot Loader 是系统上电启动后运行的第一个软件程序,它的主要作用是完成硬件初始化、加载操作系统内核并将控制权移交给内核。

🕠U-Boot 是如何启动内核的?

uboot启动内核分为两个步骤:第一步是将内核镜像从启动介质中加载到DDR中,第二步是去DDR中启动内核镜像。

🕡U-Boot 中 bootcmd 和 bootargs 分别有什么作用?

在 U-Boot 中,bootcmd 表示启动时自动执行的命令序列,通常用来加载内核和设备树并启动系统;

bootargs 是传递给内核的启动参数,比如根文件系统路径、控制台设置等,内核会根据这些参数完成初始化配置。

🕢vmlinux、Image、zImage、uImage 的区别是什么?

vmlinux 是编译后未压缩、带符号的可执行内核文件,主要用于调试;

Image 是去掉调试信息后的裸内核镜像;

zImage 是对 Image 进行压缩后的版本,便于嵌入式设备使用;

uImage 则是在 zImage 基础上添加 U-Boot 头部,供 U-Boot 引导时识别使用。

🕣Linux 内核中 Makefile、Kconfig、.config 的关系是什么?

在 Linux 内核中,Kconfig 定义内核配置选项及其依赖关系,用户通过配置工具(如 menuconfig)选择需要的功能后生成 .config 文件,该文件保存所有配置结果;

Makefile 根据 .config 中的选项控制编译流程,决定哪些模块被编译、如何编译。

🕤简述 Linux 内核的总体启动流程。

Linux 内核的启动流程通常包括:

处理器上电后运行 Bootloader(如 U-Boot),它完成硬件初始化并加载内核镜像与启动参数,随后跳转到内核入口函数。

内核从压缩镜像中解压自身,初始化中断、内存管理、设备驱动、文件系统等,最终挂载根文件系统并启动用户空间的第一个进程(通常是 initsystemd),至此完成系统启动。

🕥简述 Linux 开发板的启动过程。

首先,上电后执行 BootROM(固化在芯片中的初级引导程序),它加载并启动 BootLoader(如 U-Boot);

BootLoader 初始化基本硬件,加载内核镜像、设备树和启动参数;

然后控制权转交给 Linux 内核,内核完成系统初始化并挂载根文件系统,启动用户空间程序(如 initsystemd),最终进入系统正常运行状态。

🕦Linux 中字符设备和块设备的主要区别是什么?

字符设备是以字节为单位进行顺序读写的设备,如串口、GPIO;

块设备以块(通常是 512 字节或更大)为单位进行随机访问读写,如硬盘、SD 卡等。

字符设备不经过缓存,操作简单;

块设备通常通过页缓存管理,可支持更高效的数据访问和文件系统操作。

🕧为什么开发板一般不需要静态库?

开发板资源有限,为了节省存储空间和内存,一般不使用体积较大的静态库,而使用动态库可以实现多个程序共享一份代码,减少冗余;

此外,动态库易于更新维护,无需重新编译所有程序。

而静态库在每个程序中都会重复打包,浪费资源,不适合嵌入式设备的轻量化需求。

🕐Linux 有哪几种驱动类型?

字符设备驱动(Character Device Driver)

  • 按字节流读写设备

  • 典型设备:串口、GPIO、I2C、传感器等

  • 通过 cdev 注册,使用 read/write 等系统调用接口

块设备驱动(Block Device Driver)

  • 按块(如512字节)读写,可随机访问

  • 典型设备:SD卡、eMMC、硬盘

  • 支持文件系统挂载

网络设备驱动(Network Device Driver)

  • 管理网络接口卡(NIC),处理数据包的收发

  • 提供 net_device 接口,供 TCP/IP 协议栈使用

  • 如以太网驱动、WiFi 驱动

平台驱动(Platform Driver)

  • 配合设备树或 ACPI 进行 SoC 内部设备的管理

  • 通常用于片上资源(如 SPI、I2C 控制器)

总线驱动(Bus Driver)

  • 管理设备与驱动的匹配与注册,如 I2C、SPI、PCI、USB 总线

  • 通常配合子设备(设备树)进行匹配

中断驱动(Interrupt Handler/Driver)

  • 响应外设产生的中断,完成事件驱动处理

  • 应用场景:按键输入、数据就绪等

电源管理驱动(PM Driver)

  • 处理设备休眠、唤醒、功耗调节

  • 用于低功耗场景,节能优化

输入设备驱动(Input Driver)

  • 管理输入事件,如触摸屏、键盘、鼠标

  • 与 Linux 输入子系统结合,生成标准事件上报接口

🕑Linux 中编写一个字符设备驱动程序的基本步骤?

 1. 分配/注册设备号

使用 register_chrdev_region()alloc_chrdev_region() 注册主设备号和次设备号。✅ 2. 初始化并添加 cdev 结构体

使用 cdev_init() 初始化字符设备结构,并通过 cdev_add() 添加到内核。

 3. 实现并注册 file_operations 结构体

定义并实现 openreadwriterelease 等接口函数,用于处理用户空间请求。

 4. 创建设备节点(可选)

使用 class_create()device_create()/dev 下创建设备节点,方便用户访问。

 5. 模块加载与卸载函数

编写 module_init()module_exit(),分别完成驱动注册和资源释放。

🕒什么是设备树?设备树的作用是什么?

设备树是一种数据结构,用于描述硬件系统的层次结构和属性。它通常由一系列节点和属性组成,每个节点代表一个设备或子系统,每个属性描述了设备的特性或配置信息。

它将设备的地址、中断、时钟等硬件资源信息从驱动程序中分离出来,内核在启动时解析设备树,从而动态识别和初始化平台上的外设。这样可以提高驱动的可移植性,降低驱动开发与硬件平台的耦合度。

🕓什么是文件系统?其功能包括哪些部分?

文件系统是操作系统用于明确存储设备(常见的是磁盘,也有基于NAND Flash的固态硬盘)或分区上的文件的方法和数据结构,即在存储设备上组织文件的方法。

操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。

文件系统的功能包括:

管理和调度文件的存储空间,提供文件的逻辑结构、物理结构和存储方法;

实现文件从标识到实际地址的映射,实现文件的控制操作和存取操作,实现文件信息的共享并提供可靠的文件保密和保护措施,提供文件的安全措施。

🕔什么是根文件系统?

根文件系统是 Linux 系统启动后挂载的第一个文件系统,位于路径 /,它包含操作系统正常运行所需的基本目录结构、系统命令、库文件、配置文件、设备节点等资源,是系统启动和运行的基础环境。

🕕GCC 编译器编译的完整流程是什么?各阶段的作用是什么?

 1. 预处理(Preprocessing)

  • 命令:gcc -E source.c -o source.i

  • 作用:处理 #include#define、条件编译等指令,将所有宏展开、头文件展开,生成纯净 C 代码。

2. 编译(Compilation)

  • 命令:gcc -S source.i -o source.s

  • 作用:将预处理后的 C 源码翻译成汇编代码,包括词法分析、语法分析、语义分析、优化等。

3. 汇编(Assembly)

  • 命令:gcc -c source.s -o source.o

  • 作用:将汇编代码翻译成目标文件(机器码 + 符号信息),生成 .o 文件。

4. 链接(Linking)

  • 命令:gcc source.o -o a.out

  • 作用:将多个目标文件和所需库文件链接,解决函数/变量地址,生成可执行文件。

🕖在 make menuconfig 界面下,驱动的三种状态(Y、N、M)分别表示什么含义?

Y(Yes)
将驱动编译进内核,开机时自动加载,不能卸载或重新加载。

M(Module)
将驱动编译成模块文件.ko),在运行时通过 insmodmodprobe 加载,支持动态插拔。

N(No)
不编译该驱动,最终不会包含在内核或模块中。

🕗有没有做过 Linux 的驱动开发?

是的,我有做过 Linux 驱动开发,主要涉及字符设备驱动和平台设备驱动。
具体工作包括:

  • 编写字符设备驱动,使用 register_chrdev 注册设备号,使用 file_operations 实现 openreadwrite 等接口;

  • 使用设备树匹配设备(of_match_table);

  • 使用内核日志(printk)调试;

  • 熟悉内核模块编写、编译、加载(insmod / rmmod)以及 udev 设备节点的自动创建;

  • 也做过简单的 I2C/SPI 外设驱动开发,包括读取寄存器和中断处理。

🕘FreeRTOS 有哪些特征?

轻量级内核:代码体积小,可运行在资源有限的 MCU 上(如 STM32、AVR)。

可移植性强:支持多种 CPU 架构,移植简单。

支持多任务:可创建多个任务并调度执行。

抢占式调度:默认支持基于优先级的抢占式调度,也支持协作式调度。

任务优先级管理:最多可设置 configMAX_PRIORITIES 个优先级。

时间管理:支持任务延时(vTaskDelay())、超时等待、滴答定时器。

多种通信机制

  • 队列(Queue)

  • 信号量(Semaphore:二值、计数)

  • 互斥量(Mutex:含递归互斥量)

  • 事件组(Event Group)

软件定时器:支持回调函数的定时执行。

内存管理:支持多种动态/静态内存分配方式(heap_1 ~ heap_5)。

支持钩子函数:如空闲钩子(Idle Hook)、滴答钩子(Tick Hook)等,用于系统自定义行为。

🕙FreeRTOS 中任务状态有哪些,怎么转换的?

Ready(就绪):已准备好执行,只等调度器分配时间片。

Running(运行):当前 CPU 正在执行的任务。

Blocked(阻塞):等待某个事件(如时间、信号量、队列等),暂时不能运行。

Suspended(挂起):任务被显式挂起(vTaskSuspend()),不会被调度,除非手动恢复。

Deleted(删除):任务已经被删除,等待资源回收(由空闲任务完成)。

任务状态的转换由调度器根据任务优先级、延时、事件等待情况等条件决定,例如任务创建后进入就绪态,由调度器选中后进入运行态,调用 vTaskDelay() 会进入阻塞态,等待时间结束后重新进入就绪态。

🕚FreeRTOS 任务默认调度方式是什么?

FreeRTOS 的默认调度方式是优先级抢占式调度(Preemptive Priority Scheduling)

在这种模式下,系统总是运行最高优先级的就绪任务,如果有更高优先级的任务变为就绪态,将立即中断当前任务并切换到高优先级任务运行,从而实现实时响应。

🕛FreeRTOS 中任务的优先级如何设置?可以设置多少级?每级优先级的含义?

在 FreeRTOS 中,任务优先级用整数表示,从 0(最低)到 configMAX_PRIORITIES - 1。数值越大表示优先级越高。

优先级的最大数量由宏 configMAX_PRIORITIES 决定,通常用户在 FreeRTOSConfig.h 中配置。

每个任务创建时可指定其优先级,调度器总是选择就绪任务中优先级最高的一个运行。优先级相同的任务会按照时间片轮转调度(若启用 configUSE_TIME_SLICING)。

🕜为什么 FreeRTOS 应用程序中必须使用空闲任务?

在 FreeRTOS 中,空闲任务(Idle Task)是由内核自动创建的一个最低优先级任务,始终存在且不可删除。

它的作用是保证当没有任何用户任务就绪时,CPU 有任务可运行,维持调度器的运行;此外,空闲任务还负责清理被删除任务的资源,如果启用了钩子函数,还可以用于系统空闲时执行低优先级后台任务(如进入低功耗状态)。

🕝什么是可剥夺型内核(Preemptive Kernel)?适用场景是什么?

可剥夺型内核指的是一种任务调度机制,当有更高优先级的任务变为就绪状态时,系统会立即中断当前正在运行的低优先级任务,切换执行更高优先级的任务。嵌入式 RTOS(如 FreeRTOS、RT-Thread)常采用此机制。

它适用于需要快速响应外部事件、并确保高优先级任务获得及时处理的实时系统,例如嵌入式控制系统、医疗设备、工业自动化等场景。

🕞什么是不可剥夺型内核(Non-preemptive Kernel)?适用场景是什么?

不可剥夺型内核是一种任务调度机制,其中正在运行的任务不会被其他任务中断,即使有更高优先级的任务变为就绪,也要等当前任务主动让出 CPU(如调用阻塞函数或结束)之后,调度器才会切换任务。

这种机制适合任务间切换控制严格、实时性要求不高的场景,调试简单,但容易导致高优任务响应延迟。

🕟FreeRTOS 抢占式任务调度机制适用于哪些场景?

外部中断唤醒高优先级任务
如串口/按键中断中唤醒一个高优先级任务,通过 xSemaphoreGiveFromISR() 触发上下文切换。

 软件中释放资源,唤醒高优先级任务
例如任务 A 释放一个信号量,唤醒等待该信号量的高优任务 B,此时会发生抢占切换。

定时任务到时唤醒
使用 vTaskDelay()xTaskDelayUntil() 等函数的任务被系统时钟唤醒,如果其优先级高于当前任务,则立即调度。

任务优先级动态提升
使用 vTaskPrioritySet() 提升某任务优先级后,如果该任务处于就绪态且优先级更高,也会触发抢占。

中断服务函数通知任务(task notification)
在 ISR 中使用 xTaskNotifyGiveFromISR() 等 API 通知高优任务,触发立即切换。

🕠FreeRTOS 中 IPC可以通过哪些方式实现?

IPC 的全称是 ‌Inter-Process Communication(进程间通信)。

常见 IPC 通信方式:

  • 队列(Queue)

        用于在任务间传递数据(如结构体、消息、命令等)。

        线程安全,支持阻塞等待,最常用的通信方式之一。

  • 二值信号量(Binary Semaphore)

        用于事件同步或中断通知,表示“某个事件发生了”。

        不传递数据,仅用于唤醒任务。

  • 计数信号量(Counting Semaphore)

        管理多个资源单位(如多个连接),用于资源计数同步。

  • 互斥量(Mutex)

        用于多个任务访问共享资源时的互斥控制。

        支持优先级继承,避免优先级反转。

  • 递归互斥量(Recursive Mutex)

        同一个任务可以重复获取该互斥锁,适用于嵌套函数共享资源的情况。

  • 事件组(Event Groups)

        通过设置/清除 bit 位表示多个事件状态。

        支持等待多个事件“或/与”条件,适合复杂同步需求。

  • 任务通知(Task Notification)

        每个任务默认有一个轻量级的通知通道。

        比信号量和队列更快,适合高性能、简单通信场景。

🕡FreeRTOS 中任务之间的通讯方式有哪些?

常见通信方式:

  • 队列(Queue)

        用于在任务间传递数据(如结构体、消息、命令等)。

        线程安全,支持阻塞等待,最常用的通信方式之一。

  • 二值信号量(Binary Semaphore)

        用于事件同步或中断通知,表示“某个事件发生了”。

        不传递数据,仅用于唤醒任务。

  • 计数信号量(Counting Semaphore)

        管理多个资源单位(如多个连接),用于资源计数同步。

  • 互斥量(Mutex)

        用于多个任务访问共享资源时的互斥控制。

        支持优先级继承,避免优先级反转。

  • 递归互斥量(Recursive Mutex)

        同一个任务可以重复获取该互斥锁,适用于嵌套函数共享资源的情况。

  • 事件组(Event Groups)

        通过设置/清除 bit 位表示多个事件状态。

        支持等待多个事件“或/与”条件,适合复杂同步需求。

  • 任务通知(Task Notification)

        每个任务默认有一个轻量级的通知通道。

        比信号量和队列更快,适合高性能、简单通信场景。

🕢IPC 通信和任务之间通讯是一个意思吗?

IPC(Inter-Process Communication)通信是一个广义概念,指进程/线程/任务之间的数据交换或同步机制。

在 FreeRTOS 或嵌入式 RTOS 中,通常说的 IPC 就是任务之间的通信方式。

🕣操作系统中的自旋锁和信号量有什么区别?

自旋锁是一种轻量级的锁机制,在竞争资源时,线程不会休眠,而是持续循环检查锁是否可用(即“自旋”),直到获取锁或被系统打断。自旋锁适用于多核系统中的短临界区保护。

信号量则可以让线程阻塞等待资源,适合任务或线程之间的同步与互斥。

由于自旋锁是一种忙等待锁,占用 CPU 资源较多,所以 像 FreeRTOS 这种轻量实时系统中通常不使用自旋锁,因为嵌入式单核系统或低资源环境下它的成本太高。

🕤什么是临界资源和临界区?为什么要有临界区?

临界资源是指多个线程或任务可能同时访问的共享资源,比如全局变量、设备寄存器、文件等。
临界区是访问临界资源的那一段代码,它必须被互斥保护,否则可能导致数据竞争、资源冲突、结果不一致等问题。
因此,必须引入临界区的概念并通过锁机制保护它,来保证系统的正确性和线程安全。

🕥在 FreeRTOS 中,互斥量(Mutex)和信号量(Semaphore)的区别?

互斥量是基于信号量实现的一种特殊二值信号量,它用于保护临界区,支持优先级继承机制,防止优先级反转;

信号量既可以是二值的,也可以是计数型的,主要用于任务同步或多资源管理。

二者在用法上类似,但互斥量更适合用于互斥访问共享资源,而信号量更适合用于事件通知和资源计数管理

🕦说一下FreeRTOS中的优先级反转?有什么危害?

指低优先级任务持有高优先级任务所需的资源(如互斥锁)时,高优先级任务被阻塞,而中等优先级任务却能抢占低优先级任务执行的现象。

危害:

  • 中优先级任务插队加剧问题

  • 高优先级任务延迟执行

  • 实时性失效

  • 系统调度逻辑混乱

  • 可能导致死锁

 🕧为什么FreeRTOS中的互斥量能解决优先级反转的问题?

互斥量解决优先级反转问题,是通过优先级继承机制(Priority Inheritance)实现的。
当高优先级任务因等待一个被低优先级任务持有的互斥量而阻塞时,系统会
临时提升低优先级任务的优先级
,使其尽快释放互斥量,避免中间被更低优先级任务打断,从而减少高优任务的等待时间。

场景例子(现实生活类比):

你在公司有三个同事:

  • 👨‍💼 高优先级:经理(任务A)

  • 👷‍♂️ 低优先级:实习生(任务B)

  • 🧑‍🔧 中优先级:普通员工(任务C)

现在只有一把打印机(共享资源),只能一个人用,需要申请钥匙(互斥量)

步骤演示(未使用优先级继承时会发生的问题):

  1. 实习生(任务B)先来了,拿到了打印机钥匙,开始慢慢打印。

  2. 这时经理(任务A)来了,也要用打印机,但钥匙在实习生手里,于是他只能等着

  3. 正当实习生想把打印完,这时普通员工(任务C)来了,他虽然优先级比实习生高,但比经理低。

  4. 因为调度器默认按优先级安排工作,所以员工插队开始干活(抢占任务B)。

  5. 实习生继续被压着没机会释放打印机钥匙,经理只能一直等 → 优先级反转发生了!

引入互斥量的优先级继承机制后:

  1. 当经理(任务A)发现钥匙被实习生(任务B)拿着时,系统做了件事:

  2. 系统临时把实习生的优先级提升为和经理一样高

  3. 这样普通员工(任务C)就插不进队,实习生能立刻完成打印。

  4. 这样经理就不会因为「实习生+员工」这俩人组合拖延了自己的工作。

  5. 实习生释放钥匙,经理马上用上,实习生优先级恢复。

🕐什么是可重入函数(Reentrant Function)?

可重入函数是指能被多个线程或中断安全调用的函数,它不依赖全局或静态变量,只使用局部变量和传入参数,因此不会互相干扰【指多个执行流(线程、中断等)同时调用可重入函数时,函数的执行状态和结果不会因并发调用而产生错误或不一致】。

// 可重入函数示例
int sum(int a, int b) {
    return a + b;
}

//不可重入函数示例

int counter = 0;

int add_one() {
    return ++counter;  // 使用了共享的全局变量,不可重入
}

🕑FreeRTOS 的内存管理是如何实现的?

🕒FreeRTOS 中断的工作流程知道吗?

1.中断发生

  • 硬件触发中断,自动跳转到 ISR(中断服务程序)。

2.保存现场

  • CPU 自动压栈部分寄存器(如程序计数器 PC、程序状态寄存器 CPSR、部分通用寄存器)。

  • FreeRTOS/编译器 额外保存其他需要的寄存器(R4-R11)以保证任务上下文完整。

3.执行 ISR

  • 中断服务函数执行逻辑,如处理外设数据、中断清除、发送信号等。

4.是否切换任务

  • 如果 ISR 中调用了 xSemaphoreGiveFromISR()xQueueSendFromISR() 等 API,可能唤醒高优先级任务。

  • portYIELD_FROM_ISR() 来判断是否需要上下文切换。

5.恢复现场

  • 如果无需切换任务,恢复原任务上下文。

  • 如果切换任务,将当前任务的上下文存栈,恢复新任务的上下文。

🕓前后台程序与实时操作系统的区别是什么?

前后台程序中,前台是中断服务程序,用于响应外设等突发事件;后台是主循环,用于轮询执行常规任务。

这种结构简单、资源占用低,但无法支持真正的多任务,实时性和可维护性差。

而 RTOS 中通过内核调度多个任务,结合任务优先级、中断嵌套与同步机制,支持高实时性和系统复杂性。

🕔实时系统的基本特性有哪些?

实时系统具有以下基本特性:

  • 确定性(Determinism):
    能在规定时间内完成特定任务,响应时间可预测。

  • 实时性(Timeliness):
    系统必须在时间约束下完成任务,分为硬实时与软实时。

  • 并发性(Concurrency):
    同时管理多个任务或事件,通过调度机制有序执行。

  • 可靠性(Reliability):
    系统需在长时间运行中保持稳定,容错能力强。

  • 可预见性(Predictability):
    对系统行为、资源占用和调度过程具有高度可控性。

🕕操作系统(如 Linux)中进程的状态有哪些?FreeRTOS 中任务的状态有哪些?

操作系统中的进程状态(以 Linux 为例):

  • 新建(New):进程正在创建。

  • 就绪(Ready):已分配资源,等待 CPU。

  • 运行(Running):正在执行。

  • 阻塞(Blocked / Waiting):等待 I/O 或事件。

  • (可选)挂起(Suspended):进程被换出主存。

  • 终止(Terminated):已完成或被杀死。

FreeRTOS 中的任务状态:

  • 就绪(Ready):可以执行,等待调度。

  • 运行(Running):占用 CPU 正在执行。

  • 阻塞(Blocked):等待事件或延时超时。

  • 挂起(Suspended):被挂起,无法调度执行。

  • 删除(Deleted):任务已标记删除,等待清除。

🕖什么是死锁?在操作系统或并发编程中,如何避免死锁?

死锁(Deadlock) 是指多个进程或线程因相互等待对方占有的资源而永久阻塞,导致系统无法继续推进的一种状态。

发生死锁必须满足四个条件(死锁的必要条件):

  • 互斥:资源不能被多个进程共享,只能一个占用。

  • 占有且等待:持有资源的同时等待其他资源。

  • 不剥夺:资源不能被强制夺取,只能主动释放。

  • 循环等待:形成一个资源等待的环形链。

如何避免死锁(常见方法):

  • 破坏必要条件

    • 禁止“占有且等待”:申请资源时一次性申请全部。

    • 支持“资源可剥夺”:允许强制释放已占有资源。

    • 打破“循环等待”:统一资源申请顺序,按序请求。

  • 使用超时/尝试锁机制

    • 使用 trylock 或设置锁超时,避免无限等待。

  • 死锁检测与恢复(适用于系统级):

    • 定期检测资源等待图,发现死锁后终止或回滚进程。

  • 采用银行家算法(资源调度中):

    • 保证系统始终处于安全状态,避免分配导致死锁。

🕗如何获取并搭建一个 FreeRTOS 项目的运行环境?

获取官方或芯片厂商提供的 FreeRTOS 源码,

选择适配的 芯片平台(如 STM32、ESP32 等),

配置 交叉编译工具链(如 arm-none-eabi-gcc),

基于 开发板或仿真器 进行开发调试,并使用 IDE(如 STM32CubeIDE、Keil、VS Code 等)搭建工程,

配置 FreeRTOSConfig.h 和任务代码,

最后烧录到目标板运行。

🕘什么是 UART?它是如何进行通信的?UART 的工作原理及其数据包结构是怎样的?

UART(通用异步收发 传输器,Universal Asynchronous Receiver/Transmitter) 是一种用于设备间串行 全双工 异步数据通信的协议,常见于单片机、模块、电脑串口等。

通信方式和原理:

  • 通信线:TX(发送)和 RX(接收)。

  • 通信方式:全双工 异步。不需要时钟线,而是通过设置一致的波特率(如9600bps)进行收发。

  • 每发送/接收一个字节的数据,UART 自动将数据转换为一帧格式。

数据包结构(字符帧):

  • 起始位(1位) | 数据位(5~9位) | 可选奇偶校验位(1位) | 停止位(1或2位)

  • 常见的UART配置:1 起始位 + 8 数据位 + 1 停止位(无校验) = 10位一帧

🕙串口异步通信中的一个字符帧由哪些部分组成?

串口(UART)异步通信中的一个字符帧(数据帧)通常由以下几部分组成

  • 起始位(Start Bit):1位,标志一个新字符的开始,始终为逻辑低电平(0)。

  • 数据位(Data Bits):5~9位,通常是 7 或 8 位,表示实际传输的数据内容。

  • 校验位(Parity Bit,可选):0 或 1 位,用于检测数据传输错误(奇校验或偶校验)。

  • 停止位(Stop Bit):1 或 2 位,逻辑高电平(1),标志一帧数据的结束。

🕚说一下RS-232?

RS-232 是由 EIA(电子工业协会)定义的一种 串行 全双工 异步 通信接口标准,用于在 DTE(数据终端设备)DCE(数据通信设备) 之间进行 低速、短距离、点对点 的数据通信。

关键特性:

  • 通信线(以 DB9 为例):

            RXD:接收数据

            TXD:发送数据

            GND:信号地

            DTR:数据终端就绪

            DSR:数据设备就绪

            RTS:请求发送

            CTS:清除发送  

  • 通信方式:全双工  异步

  • 拓扑结构:点对点(1对1),常用的接口是 DB9(9针)或 DB25。

  • 波特率:通常在 1200~115200 bps 之间,较慢。

  • 电气特性:

            逻辑"1":–3V 到 –15V

            逻辑"0":+3V 到 +15V

            电平与 TTL 相反。

  • 传输距离:理论上最长 15 米,实际推荐 10 米以内。

  • 字符帧包含:

           起始位(1位)

           数据位(5~9位,常用8位)

           可选的奇偶校验位(1位)

           停止位(1或2位)

🕛说一下RS-485?

RS-485 是一种支持 多点总线通信 差分串行 异步通信接口标准,具有传输距离远、抗干扰能力强、通信速率高的特点,广泛应用于工业自动化、楼宇控制、安防等场景。

关键特性:

  • 接口引脚:

           通常使用A、B两根信号线(+GND),比RS232简洁

  • 通信方式:半双工(常见)或全双工(需双总线)

  • 拓扑结构:主从模式,支持多达32个设备并联(有的芯片扩展支持128/256个)

  • 电器特性:

           使用差分信号(A/B线),增强抗干扰性

           逻辑“1”:A>B

           逻辑“0”:A<B

  • 传输距离:

           最长可达1200米

           波特率与距离成反比

  • 终端电阻:

           通常在总线两端加120Ω终端电阻防止信号反射

🕜串口和并口的区别是什么?

串口是按位依次传输数据的通信方式,优点是线路少、成本低、传输距离远

并口是同时传输多个位(如8位或更多)的方式,线路多,传输速度快,传输距离短。

如今串口更常用于长距离、低速设备通信,而并口逐渐被高速串行总线(如USB)取代。

速记:串口线少、传得慢但远;并口线多、传得快但短。

🕝I2C 总线的基本原理、特点及应用场景。

I2C(Inter-Integrated Circuit)是一种两线式串行通信协议,由 SDA(数据线)SCL(时钟线) 构成,支持多主多从通信,数据通过地址匹配来识别从设备。

关键特性:

  • 通信线:SDA(数据线)和SCL(时钟线)

  • 通信方式:半双工 同步 

  • 拓扑结构:一主多从,或多主多从(多个主设备可控制总线,但需要仲裁机制)

  • 传输速率:标准模式(100kbps)、快速模式(400kbps)、高速模式(3.4Mbps)等

  • 寻址方式:每个从设备有唯一地址(7位或10位)

应用场景:

  • 读取传感器数据(如温湿度、加速度)

  • 控制 OLED 屏、LCD 屏

  • 访问 EEPROM、RTC 实时时钟

  • 音频芯片、PMIC(电源管理芯片)通信

🕝说一下SPI 总线的通信原理、特点和应用场景。

SPI(Serial Peripheral Interface)是一个全双工、同步、主从式串行通信协议,使用 4 根信号线(MOSI、MISO、SCLK、CS)进行通信,通信速度快、硬件实现简单。

关键特性:

  • 通信线:

          MOSI(主输出从输入)

          MISO(主输入从输出)

          SCLK(时钟信号)

          CS/SS(片选线,低电平有效)

  • 通信方式:全双工 同步

  • 拓扑结构:一主多从

  • 传输速率:可达几十Mbps

  • 寻址方式:片选信号(CS 引脚)

应用场景:

  • 外接 Flash、EEPROM

  • TFT/LCD 显示屏

  • SD 卡

  • 传感器或 ADC 芯片(如 MCP3008)

  • SPI 串口屏(如 Nextion)

🕞什么是 CAN 总线?请简述其工作原理、特点和应用场景。

CAN(Controller Area Network)总线是一种异步、半双工、差分式、多主机 串行通信协议。广泛应用于汽车电子、工业控制等场景。

关键特性:

  • 通信线:

           CAN_H(高电平线)

           CAN_L(低电平线)

           使用差分信号传输,增强抗干扰能力。

  • 通信方式:半双工  异步

  • 拓扑结构:总线型结构(多个节点并联在两条总线上)

  • 传输速率:常见为 125 kbps ~ 1 Mbps,距离越远速率越低

  • 优先级仲裁:基于标识符 ID,ID 越小,优先级越高;仲裁过程不丢帧(非破坏性)

应用场景:

  • 汽车电子系统(车灯控制、发动机、ABS、空调等)

  • 工业自动化(控制器、传感器、执行器通信)

  • 电梯、机器人、医疗设备、船舶系统

  • 无人机、AGV 等智能控制设备

🕟什么是 MODBUS?请简述其工作原理 和 应用场景。

MODBUS 是一种主从式通信协议,广泛应用于工业自动化领域中各类电子设备间的数据通信。它是一种开放协议,支持串口(如 RS-232/RS-485)和网络(如 TCP/IP)通信。

工作原理:

  • 主从架构:通信始终由主设备发起,从设备只能被动应答。

  • 请求-应答机制:主机发送请求帧(包含功能码和数据),从机根据请求进行操作并返回应答帧。

  • 寄存器访问:主机通过功能码读取/写入从机的线圈、输入、寄存器等资源。

应用场景:

  • PLC 与传感器/执行器通信(温度采集、继电器控制)

  • 智能仪表数据读取(电表、气表、液位传感器等)

  • 工业设备组网监控(人机界面 HMI、SCADA 系统)

  • 楼宇自动化(空调、照明、能耗监测系统)

  • 农业、能源、交通自动化系统

🕠说一下MODBUS 协议模式?

🕡LoRa 是什么,其工作原理是什么?应用场景?

LoRa (Long Range)是一种基于扩频技术的超远距离无线传输技术,属于物联网通信技术的一种。

它利用线性调频扩频(CSS)技术,将信号在较宽的频谱上进行扩展,从而提高信号的抗干扰能力和传输距离。

发送端将原始数据调制到 LoRa 信号上,通过天线发送出去,接收端则通过解扩等操作还原出原始数据。

应用场景:

  • 智慧农业(远程监测土壤、温湿度)

  • 城市管理(井盖、路灯、停车监控)

  • 工业现场(传感器状态上传、远程告警)

  • 能源管理(抄表、燃气监控)

🕢什么是 LoRaWAN?和 LoRa 有什么区别?

LoRa 是物理层的调制技术;LoRaWAN 是构建在 LoRa 之上的 MAC 层通信协议和网络架构,支持设备接入、认证、安全、数据传输架构 。

🕣请简述 WiFi 的主要工作模式及其典型应用场景。

  • STA 模式(Station):作为客户端连接外部路由器/热点,常用于上行数据传输

  • AP 模式(Access Point):自身充当热点,终端设备直连,适用于配置界面或局域网通信

  • STA+AP 混合模式:同时作为客户端和热点,用于桥接网络或现场设备配置

  • Mesh 模式:多节点自动组网,扩展覆盖范围,适合大规模 IoT 部署

🕤说一下蓝牙是什么?有几种工作模式?

蓝牙是一种短距离无线通信技术,主要用于低功耗、点对点或小规模组网的设备间通信。

模式分类:

  • 经典蓝牙(BR/EDR)  BR(Basic Rate)和 EDR(Enhanced Data Rate)

  • 低功耗蓝牙(BLE)Bluetooth Low Energy

  • 双模蓝牙(Dual Mode)

🕥常见的近距离无线通信协议?各自的特点和应用场景是什么?

常见的有 Bluetooth、Wi-Fi、ZigBee、NFC、Infrared、UWB 等。

  • 蓝牙(Bluetooth)

    • 通信距离:10~100 米

    • 特点:低功耗(BLE)、易配对

    • 应用:耳机、穿戴设备、传感器数据传输

  • Wi-Fi

    • 通信距离:数十米~百米

    • 特点:高速、宽带传输、支持 TCP/IP

    • 应用:无线局域网、视频传输、IoT 网关

  • ZigBee

    • 通信距离:10~100 米

    • 特点:低速率、低功耗、自组网

    • 应用:智能家居、工业控制、传感器网络

  • NFC(近场通信)

    • 通信距离:小于 10 厘米

    • 特点:点对点通信、无需配对

    • 应用:移动支付、门禁、电子票证

  • 红外(Infrared)

    • 通信距离:几米内,需视距

    • 特点:低成本、抗干扰性弱

    • 应用:电视遥控器、简单数据传输

  • UWB(Ultra Wide Band)超宽带

    • 通信距离:10~30 米,厘米级精度

    • 特点:高精度定位、抗干扰强

    • 应用:室内定位、智能穿戴、高安全场景

🕦常见的物联网(IoT)通信协议?它们的特点和适用场景分别是什么?

应用层协议(用于设备之间数据交换)

  • MQTT(Message Queuing Telemetry Transport)

    • 轻量级发布/订阅模式

    • 占用带宽小、低功耗、适合低带宽网络

    • 应用:传感器数据上传、智能家居

  • CoAP(Constrained Application Protocol)

    • 类似 HTTP,基于 UDP,适合资源受限设备

    • 小型二进制报文,支持多播

    • 应用:小型设备之间快速通信

  • HTTP/HTTPS

    • 基于 TCP,通用性强,适配 Web 应用

    • 数据开销大,实时性差

    • 应用:Web 服务对接、数据上报

  • LwM2M(Lightweight M2M)

    • 基于 CoAP,为设备管理和远程控制设计

    • 支持设备注册、远程配置和固件升级

    • 应用:设备远程管理、大型部署环境

  • AMQP(Advanced Message Queuing Protocol)

    • 面向消息队列,适合复杂消息交换场景

    • 适用于企业级 IoT 解决方案(如金融、医疗)

网络/传输层协议

  • LoRaWAN

    • 基于 LoRa 的低功耗广域网协议,星型拓扑

    • 适合远距离、低速率的传感器网络

    • 应用:远程抄表、环境监控、农业物联网

  • NB-IoT(Narrow Band IoT)

    • 基于蜂窝网络,低功耗广域(LPWAN)通信技术

    • 支持深度覆盖、海量连接、低成本

    • 应用:智能水表、电表、城市管理

  • ZigBee

    • 自组网能力强,低速率短距离

    • 应用:智能照明、家庭自动化、工业控制

  • Bluetooth LE(低功耗蓝牙)

    • 点对点通信、低功耗、近距离

    • 应用:智能穿戴、健康监测、智能门锁

🕧说一下 STM32 中的中断?为什么需要中断,有哪些中断,大概怎么做?

中断是一种处理异步事件的重要机制。

为什么需要中断?

  • 提升响应效率:无需轮询,响应外部事件迅速

  • 降低资源占用:CPU 在无任务时可休眠

  • 支持异步操作:如按键、串口、定时器、DMA等外设事件处理

STM32 中的常见中断类型:

使用中断的基本流程:

  1. 开启外设时钟:

    __HAL_RCC_GPIOx_CLK_ENABLE();

  2. 配置外设为中断模式(如 EXTI):

    1. 配置 GPIO 为输入模式

    2. 设置为中断触发(上升沿/下降沿)

    3. 初始化 EXTI 线

  3. 使能中断并设置优先级:

    使用 HAL_NVIC_SetPriority()HAL_NVIC_EnableIRQ() 配置中断控制器 NVIC

  4. 编写中断服务函数(ISR):

    函数名通常为:void XXX_IRQHandler(void)

    在函数内部处理中断事件,并清除中断标志位

🕐STM32 中定时器(Timer)的类型、主要功能、使用场景及配置方法?

定时器类型(以 STM32F1/F4 为例):

主要功能:

  • 定时/计时功能:可配置为以固定周期触发中断

  • PWM 输出:用于电机控制、LED 调光等

  • 输入捕获:测量外部信号频率、脉宽

  • 输出比较:用于控制输出翻转或事件触发

  • 编码器接口模式:支持与编码器配合使用

使用流程:

  1. 打开时钟

  2. 配置定时器参数(如分频器、计数器模式、周期)

  3. 使能中断并配置中断优先级

  4. 开启定时器和中断

  5. 编写中断服务函数

应用场景:

  • 定周期任务调度(如 RTOS tick)

  • PWM 控制电机、舵机

  • 红外测距信号脉宽测量

  • 精确延时(比 delay() 更准确)

  • 事件触发、测速、编码器方向检测

🕑STM32 中 GPIO 的输入输出模式分类及其适用场景?