目录
🕕ARM 通用寄存器中 3 个特殊寄存器的名字和作用是什么?
🕜软件中断与硬件中断的区别是什么?ARM 提供的软件中断指令是什么?
🕡U-Boot 中 bootcmd 和 bootargs 分别有什么作用?
🕢vmlinux、Image、zImage、uImage 的区别是什么?
🕣Linux 内核中 Makefile、Kconfig、.config 的关系是什么?
🕛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),它完成硬件初始化并加载内核镜像与启动参数,随后跳转到内核入口函数。
内核从压缩镜像中解压自身,初始化中断、内存管理、设备驱动、文件系统等,最终挂载根文件系统并启动用户空间的第一个进程(通常是
init
或systemd
),至此完成系统启动。
🕥简述 Linux 开发板的启动过程。
首先,上电后执行 BootROM(固化在芯片中的初级引导程序),它加载并启动 BootLoader(如 U-Boot);
BootLoader 初始化基本硬件,加载内核镜像、设备树和启动参数;
然后控制权转交给 Linux 内核,内核完成系统初始化并挂载根文件系统,启动用户空间程序(如
init
或systemd
),最终进入系统正常运行状态。
🕦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 结构体
定义并实现
open
、read
、write
、release
等接口函数,用于处理用户空间请求。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
),在运行时通过insmod
或modprobe
加载,支持动态插拔。N(No):
不编译该驱动,最终不会包含在内核或模块中。
🕗有没有做过 Linux 的驱动开发?
是的,我有做过 Linux 驱动开发,主要涉及字符设备驱动和平台设备驱动。
具体工作包括:
编写字符设备驱动,使用
register_chrdev
注册设备号,使用file_operations
实现open
、read
、write
等接口;使用设备树匹配设备(
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)
现在只有一把打印机(共享资源),只能一个人用,需要申请钥匙(互斥量)。
步骤演示(未使用优先级继承时会发生的问题):
实习生(任务B)先来了,拿到了打印机钥匙,开始慢慢打印。
这时经理(任务A)来了,也要用打印机,但钥匙在实习生手里,于是他只能等着。
正当实习生想把打印完,这时普通员工(任务C)来了,他虽然优先级比实习生高,但比经理低。
因为调度器默认按优先级安排工作,所以员工插队开始干活(抢占任务B)。
实习生继续被压着没机会释放打印机钥匙,经理只能一直等 → 优先级反转发生了!
引入互斥量的优先级继承机制后:
当经理(任务A)发现钥匙被实习生(任务B)拿着时,系统做了件事:
系统临时把实习生的优先级提升为和经理一样高!
这样普通员工(任务C)就插不进队,实习生能立刻完成打印。
这样经理就不会因为「实习生+员工」这俩人组合拖延了自己的工作。
实习生释放钥匙,经理马上用上,实习生优先级恢复。
🕐什么是可重入函数(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 中的常见中断类型:
使用中断的基本流程:
开启外设时钟:
__HAL_RCC_GPIOx_CLK_ENABLE();
配置外设为中断模式(如 EXTI):
配置 GPIO 为输入模式
设置为中断触发(上升沿/下降沿)
初始化 EXTI 线
使能中断并设置优先级:
使用
HAL_NVIC_SetPriority()
和HAL_NVIC_EnableIRQ()
配置中断控制器 NVIC编写中断服务函数(ISR):
函数名通常为:
void XXX_IRQHandler(void)
在函数内部处理中断事件,并清除中断标志位
🕐STM32 中定时器(Timer)的类型、主要功能、使用场景及配置方法?
定时器类型(以 STM32F1/F4 为例):
主要功能:
定时/计时功能:可配置为以固定周期触发中断
PWM 输出:用于电机控制、LED 调光等
输入捕获:测量外部信号频率、脉宽
输出比较:用于控制输出翻转或事件触发
编码器接口模式:支持与编码器配合使用
使用流程:
打开时钟
配置定时器参数(如分频器、计数器模式、周期)
使能中断并配置中断优先级
开启定时器和中断
编写中断服务函数
应用场景:
定周期任务调度(如 RTOS tick)
PWM 控制电机、舵机
红外测距信号脉宽测量
精确延时(比
delay()
更准确)事件触发、测速、编码器方向检测
🕑STM32 中 GPIO 的输入输出模式分类及其适用场景?