问题 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

题目:简述超声波测距的原理?答案:超声波测距基于回声定位原理,步骤如下:

  1. 发射超声波:超声波模块的发射端发出超声波脉冲。
  2. 传播与反射:超声波在空气中传播,遇到障碍物后反射。
  3. 接收回声:超声波模块的接收端接收反射回来的回声。
  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 分别转换为以下数制形式:二进制为______、八进制为______、十进制为______、十六进制为______。答案100011433523注释

  • 十进制 35 转二进制:除 2 取余得100011
  • 转八进制:将二进制每 3 位分组(100 011),对应4 343
  • 十进制本身即为35
  • 转十六进制:每 4 位分组(10 0011),对应2 323

填空题 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 语言数据类型体系中,基本类型是基础(如intchar),构造类型由基本类型组合而成(数组、结构体等),指针类型存储地址,空类型表示无返回值或无类型指针,派生类型基于其他类型扩展(如数组指针、函数指针)。


题目 6

问题:串口在不使用校验位时,波特率 115200 条件下,1 秒钟可以传输多少个字节数据?答案:11520 字节注释:串口无校验时,每字节由 “1 起始位 + 8 数据位 + 1 停止位” 组成,共 10 位。波特率是每秒传输的位数,因此每秒传输字节数为 \(115200 \div 10 = 11520\) 字节。

题目 7

问题:定义一个宏 MIN,返回 2 个数之间的较小的那个。答案#define MIN(a, b) ((a) < (b) ? (a) : (b))注释:通过三元运算符比较ab,返回较小值。给参数加括号避免宏展开时因运算优先级导致逻辑错误。

题目 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在多设备组网(仅需两根线)和布线简化上更有优势,并非速率越高越适用,需结合场景选择。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐