卓驭嵌入式底软面试经验&&零跑BMS软件工程师

卓驭

自我介绍

1介绍项目
2自己负责哪一部分的
3项目当中遇到的难点以及怎么解决的
4在项目当中学习到了什么

讲一下什么是优先级反转

定义

优先级反转是指:
一个高优先级任务等待一个被低优先级任务持有的资源,而此时中等优先级任务不断运行,导致高优先级任务无法获得资源,从而“反转”了原有的调度优先级逻辑

例子

任务 优先级 说明
Task_H 要访问共享资源 A
Task_M 与资源 A 无关,做其他事
Task_L 正在使用共享资源 A

执行过程:
1.Task_L 获取了 互斥锁 Mutex_A;

2.此时 Task_H 准备运行,也要访问资源 A;

3.Task_H 被挂起,等待 Task_L 释放 Mutex;

4.在这期间,Task_M 不断运行;

5.Task_L 被饿死,不能释放 Mutex,Task_H 也永远等不到资源。

➡️ 高优先级任务 Task_H 被中优先级任务 Task_M 间接阻塞了

注意情况

在实时系统中,任务优先级的调度顺序非常关键;
如果高优先级任务不能及时运行,可能导致系统崩溃或硬件故障(如航天器控制、汽车安全系统);
历史上最著名的案例:
NASA “火星探路者”号因优先级反转导致系统频繁重启

如果指针执行++操作,指针移动了几个字节

指针执行 ++ 操作时,它会移动**sizeof(所指类型)**个字节。

1
2
3
4
5
6
7
int *p_int;
char *p_char;
double *p_double;

p_int++; // 移动 4 字节(假设 int 是 4 字节)
p_char++; // 移动 1 字节
p_double++; // 移动 8 字节(假设 double 是 8 字节)

讲一下常量指针和指针常量

常量指针(const int *ptr)是指指向常量的指针,不能通过指针修改值,但可以改变指针的指向;指针常量(int *const ptr)是指自身是常量的指针,不能改变指向,但可以通过它修改指向地址上的值;如果写成 const int *const ptr,则指针和它指向的数据都不能修改

讲一下静态变量和静态函数

静态变量

本质与存储特性

在 C 语言中,使用 static 修饰的变量具备静态存储期(Static Storage Duration),即:
编译时分配内存,程序整个生命周期内保持存在,直到程序结束才释放。
它与变量的作用域无关 —— 即使定义在局部作用域中,也不会在函数退出时被销毁。

作用域与可见性

若在函数内部声明,变量作用域仍然是该函数本地,但生命周期变成全局;
若在文件级作用域声明(即不在任何函数中),static 限定其链接属性为内部链接,使该变量只能在本文件中访问,防止外部符号冲突。

初始化行为

静态变量在程序加载时由系统初始化(未显式赋值时默认初始化为 0);
它只会在程序启动阶段初始化一次,即使函数被调用多次,也不会重复初始化。

典型应用场景

记忆函数执行状态或计数值(如单例、自增 ID);
限制全局变量的可见性,实现模块封装;
在驱动开发中,维护设备状态结构体的静态引用。

静态函数

本质:链接属性为内部链接

函数默认具有外部链接性(external linkage),可以被其他文件引用(通过 extern)。
而 static 修饰函数后,会将其链接属性修改为 内部链接(internal linkage),即:
编译器在链接阶段不会将该符号导出给其他编译单元(.o 文件),只能在本文件内解析。

作用域与可见性

静态函数的作用域限制在当前编译单元(源文件)内;
不能通过其他模块的 extern 声明来访问,提高封装性和模块隔离性;
编译器对静态函数有更多优化空间(如内联、去除未引用的函数)。

典型应用场景

实现模块私有函数,防止命名冲突;
在设备驱动、协议栈、库开发中,常用 static 函数将接口函数与实现函数解耦;
与 static 变量配合,实现静态私有状态封装(类比面向对象中的 private 成员)。


零跑BMS软件工程师

简历

我面的是BMS部门,对我的简历问的比较细,就问了一个八股文,经典就是这个项目背景是什么,你是怎么做的,遇到什么困难,学到什么。
1.你项目用到哪些驱动
2.你这个项目驱动是你自己写的吗
3.FreeRTOS是你自己移植的吗

ARM内核单片机上电到main函数之前做了什么工作

ARM Cortex-M 单片机上电后,核心会首先从向量表中读取初始 SP 和复位地址,进入启动代码中的 Reset_Handler。启动流程包括初始化堆栈、复制 .data 段到 RAM、清空 .bss 段、配置系统时钟(调用 SystemInit)、初始化 C/C++ 运行环境,最终跳转到 main()。这个流程由汇编启动文件和链接脚本共同驱动,是整个系统可靠启动的基础。
[1] 上电复位

[2] CPU从向量表中取复位中断地址

[3] 进入启动文件的 Reset_Handler(汇编写的 startup.s)

[4] 初始化堆栈指针(MSP)

[5] 初始化 .data 段(从 Flash 拷贝到 RAM)

[6] 清空 .bss 段(全局未初始化变量清零)

[7] 调用 SystemInit()(配置时钟、PLL、FPU等)

[8] 调用 C 库初始化(可能包含构造函数)

[9] 跳转到 main() 函数


卓驭嵌入式底软面试经验&&零跑BMS软件工程师
https://chrisy0618.github.io/2025/05/12/zhuoyu/
作者
Chris.Y
发布于
2025年5月12日
许可协议