最近,试图找一些公司的技术面试机会锻炼,发现我在项目经历的发挥不错,但是在一些技术栈方面还是有挺大的遗漏,于是打算积累面试的问题。
技术栈类
移植freertos的步骤
准备开发环境
IDE选择: 根据你使用的微控制器型号选择合适的集成开发环境(IDE),例如 STM32CubeIDE(适用于STM32系列)、Keil MDK 或 IAR Embedded Workbench 等。
工具链: 确保安装对应的编译器,如 GCC(GNU编译器集合)、Arm Compiler 或 IAR Compiler。
获取FreeRTOS源码
从 FreeRTOS官网下载最新版本的源码。
解压源码包,你会看到
Source文件夹,其中包含了内核的所有核心文件。
配置项目工程结构
在你的项目目录下创建一个文件夹(如
FreeRTOS)来存放源码。将下载的
Source文件夹内容复制到你的工程目录中。关键是要将portable文件夹下与你编译器和处理器架构相关的文件添加到工程里。例如,对于 Keil 环境下的 Cortex-M3 内核,需要添加FreeRTOS/Source/portable/RVDS/ARM_CM3目录下的文件。从
MemMang文件夹中选择一种内存管理方案(如heap_4.c)并添加到项目中,它负责管理 FreeRTOS 运行时动态分配内存。
配置 FreeRTOS 内核
这是移植的核心步骤,主要通过创建和修改
FreeRTOSConfig.h头文件来完成。这个文件包含了所有用于裁剪和配置 FreeRTOS 功能的宏定义。下表列出了一些最关键的配置项:配置项目工程结构
在你的项目目录下创建一个文件夹(如
FreeRTOS)来存放源码。将下载的
Source文件夹内容复制到你的工程目录中。关键是要将portable文件夹下与你编译器和处理器架构相关的文件添加到工程里。例如,对于 Keil 环境下的 Cortex-M3 内核,需要添加FreeRTOS/Source/portable/RVDS/ARM_CM3目录下的文件。从
MemMang文件夹中选择一种内存管理方案(如heap_4.c)并添加到项目中,它负责管理 FreeRTOS 运行时动态分配内存。
配置 FreeRTOS 内核
这是移植的核心步骤,主要通过创建和修改
FreeRTOSConfig.h头文件来完成。这个文件包含了所有用于裁剪和配置 FreeRTOS 功能的宏定义。下表列出了一些最关键的配置项:配置项目工程结构
在你的项目目录下创建一个文件夹(如
FreeRTOS)来存放源码。将下载的
Source文件夹内容复制到你的工程目录中。关键是要将portable文件夹下与你编译器和处理器架构相关的文件添加到工程里。例如,对于 Keil 环境下的 Cortex-M3 内核,需要添加FreeRTOS/Source/portable/RVDS/ARM_CM3目录下的文件。从
MemMang文件夹中选择一种内存管理方案(如heap_4.c)并添加到项目中,它负责管理 FreeRTOS 运行时动态分配内存。
配置 FreeRTOS 内核
这是移植的核心步骤,主要通过创建和修改
FreeRTOSConfig.h头文件来完成。这个文件包含了所有用于裁剪和配置 FreeRTOS 功能的宏定义。下表列出了一些最关键的配置项
5. 配置硬件资源
系统定时器(SysTick): FreeRTOS 需要一个硬件定时器来产生周期性的系统时钟中断(Tick Interrupt)。通常使用 Cortex-M 内核内置的 SysTick 定时器。你需要确保该定时器已正确初始化并启动。
中断控制器(NVIC): 正确配置中断优先级分组。特别注意,SysTick 中断和 PendSV 中断的优先级通常需要设置为最低,以确保系统调度不会阻塞更高优先级的硬件中断。
不同内存地址的线程如何交换数据
共享内存
开辟一块多个线程或进程都能访问的内存区域。
同一进程的线程或同一主机上的进程,要求高性能、大数据量交换。
速度最快,但需要自行处理同步(如使用信号量、互斥锁),否则易产生数据竞争。
消息传递
线程通过发送和接收消息(数据包)来通信,不直接共享内存。
分布式系统、异构平台、需要解耦的生产者-消费者模型。
天然避免数据竞争,解耦性好,但有一定性能开销(序列化、网络传输等)。常见实现有消息队列。
管道/匿名管道
提供一个单向的字节流通道,数据像水流一样从一端写入,另一端读出。
同一进程的线程或具有亲缘关系的进程间(如父子进程)的线性数据流。
实现简单,但通常是单向通信,如需双向通信需建立两个管道。
远程过程调用 (RPC)
让线程能够像调用本地函数一样调用远程(其他进程或机器上)的函数。
分布式系统,希望隐藏底层通信细节,提供类似本地调用的体验。
对程序员透明,RPC框架自动处理参数传递、网络通信等复杂细节。
信号量/互斥锁等同步原语
通过计数器(信号量)或锁(互斥锁)来控制多个线程对共享资源的访问顺序。
主要作为辅助同步手段,与共享内存等机制配合使用,确保数据一致性。
解决并发访问冲突,防止数据损坏。是安全使用共享内存等机制的基石
调试类
如果发现mcu执行的时候卡住了怎么办
基础硬件检查:确认供电电压稳定且在MCU要求范围内。检查复位电路是否正常,以及主时钟是否正常起振(可用示波器查看)。
软件日志与LED指示:在没有仿真器或问题难复现时,这招很实用。通过串口输出日志(
printf),在关键函数、循环、中断入口处打印信息,帮助定位卡死前最后执行的代码。用LED灯指示程序状态(如不同任务对应不同闪烁模式)也很有效。使用仿真器深入排查:若可用仿真器,发现问题时暂停程序,查看调用栈,常能直接定位卡死函数。检查关键寄存器,如程序计数器、链接寄存器等,有助于分析。
🔁 软件逻辑问题
1.死循环:条件永远不满足。
2.外设等待:等待某个标志位,但条件永不满足。
1. 为循环和等待添加超时退出机制。
2. 检查外设初始化配置和通信时序。
⚡ 中断服务程序
1.未清除中断标志:导致中断不断触发,CPU频繁进入中断。
2.中断处理时间过长或中断优先级配置不当导致嵌套混乱。
1. 确保在中断服务函数中正确清除中断标志位。
2. 优化中断服务函数,使其尽可能短小精悍。合理配置中断优先级。
💾 内存管理问题
1.堆栈溢出:函数调用层次过深、大型局部变量、递归无出口等。
2.内存访问越界:数组越界、野指针等非法内存写入,可能破坏关键数据或代码。
1. 在启动文件或链接脚本中增大堆栈大小。减少函数嵌套层级和大型局部变量。
2. 使用静态代码分析工具检查数组和指针操作。在HardFault_Handler中分析故障状态寄存器定位非法访问。
🔒 多任务资源竞争
多任务环境下,任务间对共享资源(如全局变量、外设)的访问未正确同步,导致死锁。
使用互斥锁、信号量等同步机制确保对共享资源的互斥访问。注意避免循环等待条件。
⚙️ 看门狗定时器
看门狗溢出时间设置不当,或系统繁忙未能及时“喂狗”,导致MCU被不断复位。
合理配置看门狗超时时间,确保在系统正常运行时能及时“喂狗”。在调试时可能需要暂时关闭看门狗。
🔧 高级调试技巧:Crash Dump
对于极难复现的卡死,可在产品固件中植入故障转储机制。当卡死或异常发生时,将关键信息(如函数调用栈、寄存器值)保存到非易失性存储器中。事后通过工具解析这些信息,结合编译生成的符号表文件,可还原故障现场,精确定位问题代码。
此方法对资源有限的MCU有一定挑战,但非常强大。
对于进程调度算法有哪些
基本调度方式
协同式调度
线程主动让出CPU,实现简单但可靠性差,一个线程故障可导致系统阻塞 。
抢占式调度
操作系统分配CPU时间片,可在时间片用完后强制挂起当前线程,更通用和可靠,是现代系统主流 。
常见调度算法
先来先服务
按到达顺序执行,实现简单,但对短作业不友好,平均等待时间较长 。
短作业优先
优先调度预计执行时间短的线程,能优化平均等待时间,但可能使长线程饥饿 。
优先级调度
为线程分配优先级,高优先级线程先执行。可分为静态优先级和动态优先级 。
时间片轮转
为每个线程分配一个时间片,时间片用完后重新排队,保证公平性和响应能力,适用于分时系统 。
多级反馈队列
综合多种算法优点,设置多个优先级不同的队列,并允许线程在不同队列间移动,兼具响应速度和吞吐量 。
多处理器调度
负载共享
维护一个全局就绪队列,所有处理器从中选取线程执行,能自动均衡负载,但队列可能成为性能瓶颈 。
成组调度
将一组关联线程同时调度到一组处理器上运行,利于线程间紧密协作,减少相互等待 。
专用处理器分配
为应用线程固定分配处理器,在执行期间专用,减少了切换开销,用于处理器资源丰富场景