(六)嵌入式面试题收集:20道
问题 1
题目:代码质量保证优先原则是什么?答案:代码质量保证通常遵循以下优先原则:
- 正确性优先:确保代码逻辑正确,功能符合需求,无业务逻辑错误。
- 可读性优先:代码结构清晰、命名规范、注释合理,便于维护和团队协作。
- 可维护性优先:模块解耦、代码可扩展,便于后续需求变更和缺陷修复。
- 性能与安全性平衡:在保证功能正确的前提下,优化性能(如算法效率、资源占用),同时保障代码安全(如防溢出、防注入、边界检查)。注释:这些原则确保代码在功能、维护、性能和安全维度的综合质量,是工程化开发的基础准则。
问题 2
题目:在具有对码功能的产品中,如何用软件的方式产生随机码?答案:可通过以下软件方式生成随机码:
- 基于硬件随机源:若系统有硬件随机数发生器(如某些 MCU 的随机模块),直接读取其输出作为随机码基础。
- 基于时间与事件的混合算法:利用系统时间(如毫秒级时间戳)、用户操作事件(如按键时间间隔)、硬件状态(如 ADC 噪声)等作为种子,通过伪随机数算法(如线性同余法、梅森旋转算法)生成随机码。
- 多因素组合:将多个不确定因素(如时间戳的低字节、IO 口电平波动、定时器计数余数)进行异或、哈希等运算,增强随机性。示例代码(伪代码):
unsigned int generateRandomCode() {
unsigned int seed = 0;
// 结合时间戳和硬件状态作为种子
seed = (unsigned int)getSystemTime() ^ (readADCNoise() & 0xFF) ^ (getIOState() << 8);
// 用种子生成伪随机数(以线性同余为例)
return (seed * 1103515245 + 12345) % 0xFFFF; // 生成16位随机码
}
注释:软件生成随机码需注意 “伪随机” 的局限性,若对随机性要求极高(如加密场景),需结合硬件随机源或专业加密算法;对码场景中,只要保证每次对码的随机码不重复且不可预测即可。
问题 3
题目:画出 IIC 通信方式的起始位、停止位、应答位的时序及扩展两个 AT24C01 的硬件电路图?答案:
(1)IIC 时序图
- 起始位(START):SCL 高电平时,SDA 从高电平跳变到低电平。
- 停止位(STOP):SCL 高电平时,SDA 从低电平跳变到高电平。
- 应答位(ACK):接收方在第 9 个时钟周期将 SDA 拉低,表示应答;若保持高电平,表示非应答(NACK)。(时序图示意:横轴为时间,纵轴为 SDA/SCL 电平;START 为 SCL 高→SDA 低;STOP 为 SCL 高→SDA 高;ACK 为 SCL 第 9 个时钟时 SDA 低。)
(2)扩展两个 AT24C01 的硬件电路图
AT24C01 是 IIC 接口的 EEPROM,通过 ** 硬件地址引脚(A0/A1/A2)** 区分设备:
- 电路连接:
- 单片机的 SDA、SCL 引脚分别连接两个 AT24C01 的 SDA、SCL 引脚,并通过上拉电阻(如 4.7kΩ)上拉到 VCC。
- 第一个 AT24C01 的 A0/A1/A2 接地(地址设为
0xA0);第二个 AT24C01 的 A0 接 VCC、A1/A2 接地(地址设为0xA2)。 - 每个 AT24C01 的 VCC 接电源,GND 接地。(电路图示意:MCU 的 SDA→上拉→AT24C01_1.SDA 和 AT24C01_2.SDA;MCU 的 SCL→上拉→AT24C01_1.SCL 和 AT24C01_2.SCL;AT24C01_1 的 A0/A1/A2→GND;AT24C01_2 的 A0→VCC,A1/A2→GND。)注释:IIC 是两线制总线,多个设备共享 SDA 和 SCL,通过地址引脚区分不同设备;上拉电阻保证总线空闲时为高电平,满足 IIC 的电平要求。
问题 4
题目:简述超声波测距的原理?答案:超声波测距基于回声定位原理,步骤如下:
- 发射超声波:超声波模块的发射端发出超声波脉冲。
- 传播与反射:超声波在空气中传播,遇到障碍物后反射。
- 接收回声:超声波模块的接收端接收反射回来的回声。
- 计算距离:根据超声波的传播速度(空气中约 340m/s)和 “发射→接收” 的时间差t,利用公式 \(距离 = \frac{340 \times t}{2}\) 计算出障碍物的距离(除以 2 是因为超声波走了往返路程)。注释:该原理利用了超声波的指向性和反射特性,适用于短距离(通常 0.1~10 米)、无强光干扰的场景,如倒车雷达、液位检测等。
填空题 1
问题:OTP 是______,MTP 是______。答案:一次性可编程(One Time Programmable);多次可编程(Multiple Time Programmable)注释:OTP 芯片只能编程一次,数据写入后无法修改;MTP 芯片支持多次擦写和编程,灵活性更高,适用于需要多次更新数据的场景。
填空题 2
问题:把数据 35 分别转换为以下数制形式:二进制为______、八进制为______、十进制为______、十六进制为______。答案:100011;43;35;23注释:
- 十进制 35 转二进制:除 2 取余得
100011; - 转八进制:将二进制每 3 位分组(
100 011),对应4 3即43; - 十进制本身即为
35; - 转十六进制:每 4 位分组(
10 0011),对应2 3即23。
填空题 3
问题:Vref=5V,被测量电压为 2V 时,用 A/D 为 10bit 的单片机测量时,所测得的值应该为______(用十六进制表示)。答案:0x199注释:10bit ADC 的量化范围是 0~1023(\(2^{10}-1\)),对应电压 0~5V。计算公式:测量值 = (2V / 5V) × 1023 ≈ 409.2,取整为 409,十六进制为0x199。
填空题 4
问题:RSSI 的中文意思是______。答案:接收信号强度指示(Received Signal Strength Indication)注释:RSSI 用于量化无线信号的接收强度,值越大表示信号越强,常用于无线通信中的链路质量评估、距离估算等。
填空题 5
问题:FSK 的中文名为:,PSK 的中文名为:,DTMF 的中文名:______。答案:频移键控;相移键控;双音多频注释:
- FSK 通过载波频率的变化表示数字信号(如 0 和 1 对应不同频率);
- PSK 通过载波相位的变化表示数字信号;
- DTMF 是电话拨号中用两个不同频率组合表示一个按键的编码方式(如 “1” 对应 697Hz 和 1209Hz)。
填空题 6
问题:超声波的频率为______KHz,若用定时中断来产生此频率,则定时设置的延时时间应该是为______(s)。答案:40;1.25×10⁻⁵(即 12.5μs)注释:超声波测距常用 40KHz 信号,其周期为1/40000 = 25μs。定时中断需每半周期(12.5μs)翻转一次电平以生成方波,故延时时间为 12.5μs(即1.25×10⁻⁵秒)。
填空题 7
问题:1K 字节______Bytes,AT24C01 中有______Bytes。答案:1024;128注释:
- 存储容量中,二进制的 “1K” 表示
2¹⁰=1024,故 1K 字节 = 1024 Bytes; - AT24C01 型号中 “01” 指 1Kbit(比特),因 1 Byte=8 bit,故换算为字节是
1024 bit ÷ 8 = 128 Bytes。
填空题 8
问题:代码效率分为______、______、及。______是站在整个系统的角度上的系统效率;______是站在模块或函数角度上的效率;______是程序处理输入任务所需的时间长短;______是程序所需内存空间,如机器代码空间大小、数据空间大小、栈空间大小等。答案:系统效率;模块效率;时间效率;空间效率;系统效率;模块效率;时间效率;空间效率注释:代码效率从不同维度衡量:系统效率关注整体性能,模块效率关注局部功能,时间效率反映执行速度,空间效率反映内存占用,四者共同决定代码质量。
填空题 9
问题:C 语言的数据类型分为______、构造类型、、、。其中构造类型又分为:、、、枚举类型。答案:基本类型;指针类型;空类型(void);派生类型;数组类型;结构体类型;共用体(联合体)类型注释:C 语言数据类型体系中,基本类型是基础(如int、char),构造类型由基本类型组合而成(数组、结构体等),指针类型存储地址,空类型表示无返回值或无类型指针,派生类型基于其他类型扩展(如数组指针、函数指针)。
题目 6
问题:串口在不使用校验位时,波特率 115200 条件下,1 秒钟可以传输多少个字节数据?答案:11520 字节注释:串口无校验时,每字节由 “1 起始位 + 8 数据位 + 1 停止位” 组成,共 10 位。波特率是每秒传输的位数,因此每秒传输字节数为 \(115200 \div 10 = 11520\) 字节。
题目 7
问题:定义一个宏 MIN,返回 2 个数之间的较小的那个。答案:#define MIN(a, b) ((a) < (b) ? (a) : (b))注释:通过三元运算符比较a和b,返回较小值。给参数加括号避免宏展开时因运算优先级导致逻辑错误。
题目 8
问题:程序的局部变量存在于()中,全局变量存在于()中,动态申请数据存在于()中。答案:栈;数据段;堆注释:局部变量由编译器自动分配 / 释放,存储在栈;全局变量在程序加载时分配,存储在数据段;动态申请的内存(如malloc)由程序员手动管理,存储在堆。
题目 9
问题:对 STM32 来说,程序定义int **a[3][4],则变量占有的内存空间大小是______字节;STM32F103 使用的是______内核,其主频一般是______MHz,共有______个可编程中断优先级。答案:48;Cortex-M3;72;16注释:
int **a[3][4]是 3 行 4 列的指针数组,每个int**指针占 4 字节,总大小为 \(3×4×4 = 48\) 字节。- STM32F103 基于 Cortex-M3 内核,主频通常为 72MHz;中断优先级由 4 位配置,共 \(2^4 = 16\) 个可编程级别。
题目 10
问题:STM32F103 使用的是______内核,STM32 常用的仿真调试工具具有______个可编程中断优先级。答案:Cortex-M3;J-Link/ST-Link(任选其一);16注释:STM32F103 采用 Cortex-M3 内核;常见调试工具如 J-Link、ST-Link 支持其调试;STM32 中断优先级共 16 个,由 4 位优先级寄存器控制。
编程题(算术表达式求值,分数表示)
问题:计算字符串算术表达式的值,支持+、-、*、/和整数,结果用分数表示,非法表达式输出 “非法表达式”。
答案:
c
运行
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int num; // 分子
int den; // 分母
} Fraction;
// 分数加法
Fraction add(Fraction a, Fraction b) {
Fraction res;
res.den = a.den * b.den;
res.num = a.num * b.den + b.num * a.den;
return res;
}
// 分数减法
Fraction sub(Fraction a, Fraction b) {
Fraction res;
res.den = a.den * b.den;
res.num = a.num * b.den - b.num * a.den;
return res;
}
// 分数乘法
Fraction mul(Fraction a, Fraction b) {
Fraction res;
res.num = a.num * b.num;
res.den = a.den * b.den;
return res;
}
// 分数除法
Fraction divi(Fraction a, Fraction b) {
if (b.num == 0) { // 分母不能为0
Fraction err = {0, 0};
return err;
}
Fraction res;
res.num = a.num * b.den;
res.den = a.den * b.num;
return res;
}
// 约分(最大公约数)
int gcd(int a, int b) {
a = abs(a);
b = abs(b);
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
// 约简分数
Fraction reduce(Fraction f) {
if (f.den == 0) return f; // 非法标记
int d = gcd(f.num, f.den);
f.num /= d;
f.den /= d;
if (f.den < 0) { // 保证分母为正
f.num = -f.num;
f.den = -f.den;
}
return f;
}
// 解析数字
int parseNum(char *expr, int *pos) {
int num = 0;
while (expr[*pos] >= '0' && expr[*pos] <= '9') {
num = num * 10 + (expr[*pos] - '0');
(*pos)++;
}
return num;
}
// 递归解析表达式(支持四则运算和括号)
Fraction parseExpr(char *expr, int *pos);
Fraction parseTerm(char *expr, int *pos);
Fraction parseFactor(char *expr, int *pos);
Fraction parseExpr(char *expr, int *pos) {
Fraction res = parseTerm(expr, pos);
while (expr[*pos] == '+' || expr[*pos] == '-') {
char op = expr[*pos];
(*pos)++;
Fraction r = parseTerm(expr, pos);
if (op == '+') res = add(res, r);
else res = sub(res, r);
}
return res;
}
Fraction parseTerm(char *expr, int *pos) {
Fraction res = parseFactor(expr, pos);
while (expr[*pos] == '*' || expr[*pos] == '/') {
char op = expr[*pos];
(*pos)++;
Fraction r = parseFactor(expr, pos);
if (op == '*') res = mul(res, r);
else res = divi(res, r);
if (res.den == 0) return res; // 除法分母为0,标记非法
}
return res;
}
Fraction parseFactor(char *expr, int *pos) {
if (expr[*pos] == '(') {
(*pos)++;
Fraction res = parseExpr(expr, pos);
if (expr[*pos] != ')') { // 括号不匹配
Fraction err = {0, 0};
return err;
}
(*pos)++;
return res;
} else if (expr[*pos] >= '0' && expr[*pos] <= '9') {
int num = parseNum(expr, pos);
Fraction f = {num, 1};
return f;
} else {
Fraction err = {0, 0};
return err; // 非法字符
}
}
int main() {
char expr[100];
fgets(expr, sizeof(expr), stdin);
expr[strcspn(expr, "\n")] = 0; // 去掉换行符
int pos = 0;
Fraction res = parseExpr(expr, &pos);
res = reduce(res);
if (res.den == 0 || pos != strlen(expr)) {
printf("非法表达式\n");
} else {
if (res.den == 1) {
printf("%d\n", res.num);
} else {
printf("%d/%d\n", res.num, res.den);
}
}
return 0;
}
注释:
- 核心逻辑:通过递归下降法解析表达式(先算乘除后算加减,支持括号),用分数结构体存储中间结果(避免浮点精度丢失)。
- 非法检测:包括括号不匹配、除零错误、非法字符、解析未完成等场景,均输出 “非法表达式”。
- 结果输出:分数约分后,分母为 1 时输出整数,否则输出分数形式(如
5/3)。
该代码在面试中属于中等难度的算法题,考察语法解析、数据结构设计和边界条件处理能力,是嵌入式 / 后端开发面试中常见的考点类型。
通常情况下,SPI比I2C快,两者速率差异源于通信机制的本质不同。
从典型速率对比:
• I2C:常见最高速率为1Mbps(快速增强模式),少数特殊场景可达5Mbps,但应用极少;
• SPI:速率无严格协议上限,主要取决于硬件(MCU、外设及布线),常规应用中轻松达到10Mbps~20Mbps,高性能场景下可突破100Mbps。
核心原因是通信结构差异:
• SPI是全双工、四线制(SCL、MOSI、MISO、CS),数据通过独立的发送/接收线传输,且无需地址寻址过程,信号传输效率更高;
• I2C是半双工、二线制(SCL、SDA),单条数据线需双向传输数据,且通信前需发送从设备地址进行寻址,存在额外开销,速率受限更明显。
不过I2C在多设备组网(仅需两根线)和布线简化上更有优势,并非速率越高越适用,需结合场景选择。
更多推荐
所有评论(0)