嵌 入 式 软 件 笔 试 题
要求:闭卷考试(不能翻书、不能开电脑);作答时间50分钟;共10道题目。
- volatile的作用有哪些
volatile: 防止编译器对代码进行优化,直接从内存中取最新的值 应用场景: 1、多线程使用同一资源时 2、单片机开发中
volatile 的作用:
1. 核心功能:告知编译器变量的值可能被当前代码块外的因素(如中断服务程序、硬件寄存器、其他线程)异步修改,禁止编译器对该变量进行 “将内存值缓存到寄存器” 的优化,确保每次访问都直接读取内存最新值。
应用场景:
1. 多线程 / 多任务环境中,共享变量(如线程间标志位);
2. 嵌入式硬件寄存器访问(如单片机的 GPIO 数据寄存器、定时器计数寄存器);
3. 中断服务程序(ISR)与主程序共享的全局变量。
- 关键字const 和static有什么含意
Const :“只读属性”,限制变量 / 指针 / 参数的值不可被修改,编译时会检查写操作并报错,
Static:静态函数,可以延长生命周期和限定作用域
1. const 关键字含义:
用于定义 “只读属性”,限制变量 / 指针 / 参数的值不可被修改,编译时会检查写操作并报错,常见场景:
- 修饰变量:const int a = 10;(a 的值不可修改);
- 修饰指针:
- const int* p(指针指向的值不可改);
- int* const p(指针本身地址不可改);
- 修饰函数参数:void func(const int x)(函数内不可修改 x);
- 修饰函数返回值:const int func()(返回值不可被赋值修改)。
2. static 关键字含义:
用于 “延长生命周期” 和 “限定作用域”,分三类场景:
- 局部静态变量:void func(){ static int a = 0; a++; }(生命周期延长至程序结束,作用域仅在函数内,初始化仅 1 次);
- 全局静态变量:static int g_a = 10;(作用域限定在当前.c 文件,避免外部文件通过extern调用);
- 静态函数:static void func(){}(作用域限定在当前.c 文件,防止与外部文件函数重名冲突)。
- 用变量a给出下面的定义
1) 一个整型数 int a
2)一个指向整型数的指针 int *a
3)一个指向指针的的指针,它指向的指针是指向一个整型数 :int **a; - 下面的代码输出是什么,为什么?(printf为打印函数)
void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b > 6) ? printf("> 6") : printf("<= 6");
}
输出是>6,因为不同无符号 / 有符号整型运算时,会触发 “隐式类型转换”—— 将int(有符号)转换为unsigned int(无符号):
C 语言中,不同无符号 / 有符号整型运算时,会触发 “隐式类型转换”—— 将int(有符号)转换为unsigned int(无符号):
1. 变量值:a = 6(unsigned int,二进制为000...000110),b = -20(int,32 位补码为111...1101100);
2. 转换后:b作为 unsigned int 时,值为2^32 - 20 = 4294967276;
3. 计算:a + b = 6 + 4294967276 = 4294967282(远大于 6),故执行printf("> 6")。
- 中断是嵌入式系统中重要的组成部分,这导致了许多编译开发商提供一种扩展:让标准C支持中断,产生了一个新的关键字__interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序,请指出以下这段代码错误的地方。
__interrupt double compute_area(double radius)
{
double area = PI * radius *radius;
printf("nArea = %f", area);
return area;
} 该中断服务子程序(ISR)存在 5 处核心错误:
1. 返回值错误:ISR 是异步触发的 “被动执行函数”,没有调用者接收返回值,必须定义为void,不能返回double;
2. 参数错误:中断触发时无法传递参数(无调用上下文),ISR 不能带参数(如double radius);
3. 调用非可重入函数:printf是标准库函数,内部包含浮点运算、全局缓冲区操作,且可能依赖中断使能,属于 “非可重入函数”;ISR 要求 “快进快出”,禁止调用非可重入、耗时函数;
4. 浮点运算风险:嵌入式系统中,double浮点运算需硬件 FPU 支持,且运算耗时较长,不符合 ISR “短延迟” 要求;
5. PI 未定义:若未通过#define PI 3.14159宏定义 PI,编译会报 “未声明标识符” 错误(非核心,但需修正)。 - 嵌入式系统中经常要用到无限循环,用C语言编写死循环的代码
While(1)1. while(1){}(最常用,明确循环体为空);
2. for(;;){}(for循环的初始化、条件、增量均可省略,条件省略视为 “永真”);
3. do{}while(1);(先执行一次循环体,再判断永真条件)。
- 给定一个整型变量a,写两段代码,第一个设置a的bit 3,第二个清除a 的bit 3。在以上两个操作中,要保持其它位不变。
设置: aI=(0x3<<偏移量) 设置 a&= ~(0x3<<偏移量)
- 已知 int 数组a[1000],需要将数组的后 100 个数据移动到前面,前面的数据依次后退。例如,若数组初始存入的数据是 1、2、3……1000,移动后的数据结果是 901、902……1000、1、2……900。用代码实现。
使用memcoy
#include <string.h>
void move_array(int a[], int n, int m) {
int t[100];
memcpy(t, a + n - m, m * sizeof(int));
for(int i = n - 1; i >= m; i--)
a[i] = a[i - m];
memcpy(a, t, m * sizeof(int));
}
int main() {
int a[1000];
for(int i = 0; i < 1000; i++)
a[i] = i + 1;
move_array(a, 1000, 100);
return 0;
}
- 简述SPI的传输特点、方式并画出工作时序
传输特点:
1.通信属性:串行(数据逐位传),同步(依赖sclk(spi)时钟同步),全双工(同一时钟周期内,主机经mosi发、从机经miso发,双向同时传);
- 速率与数据::“高速 3.4Mbps” 是 HS-mode,需区分 “标准模式(100Kbps)、快速模式(400Kbps)、高速模式(3.4Mbps)速率达mbps级;最小单位为字节(8/16位),1时钟周期传1位,1字节需8时钟周期;
- 主从模式:支持主从机,常用“单主机多从机”,主机控制sck时钟和nss片选,从机被动响应
- 从机选择:通过专属的nss/ncs片选线,主机拉低目标从机nss电平建立通信,其他从机nss保持高电平不响应
传输方式:
- 主从逻辑:主机输出sck和nss,经mosi发数据;从机按sck节奏收mosi数据,经miso回传数据
- 全双工实现:如主机发 0xFF、从机发 0x00,SCK 上升沿时二者分别经 MOSI/MISO 发 1 位,下降沿时分别读对方数据;8 时钟周期后,双方均完成 “发 + 收”;
- 多从机传输:四线制连接(sck、mosi、miso共线,各从机独立接主机nss),主机拉低对应从机nss实现“一对一”通信,避免冲突。
工作时序图:
- 简述I2C的传输特点、方式并画出工作时序(从机地址、寄存器地址、数据自定义)
一、I2C 传输特点
- 传输类型:串行(逐位传)、同步(依赖 SCL 时钟同步)、半双工(同一时间单向传);
- 硬件结构:仅 2 根双向线(SCL 时钟、SDA 数据),均需外接上拉电阻(空闲时保高电平、稳电路);
- 速率分级:低速 100Kbps、中速 400Kbps、高速 3.4Mbps;
- 主从架构:支持单 / 多主机多从机,主机主动发起 / 结束通信,从机被动响应;
- 唯一寻址:从机均有唯一 7 位地址(如 SHT20 为 0x40),主机通过地址定位从机;
- 应答机制:每传 1 字节(8 位),接收器第 9 时钟周期回 ACK(0,成功)或 NACK(1,失败 / 停止)。
二、I2C 传输方式
1. 主机→从机(写传输)
- 主机发起始信号(S),占总线;
- 发 “7 位从机地址 + W(0)”(如 SHT20 写地址 0x80);
- 从机回 ACK;
- 发目标寄存器地址(如 SHT20 温度寄存器 0xE3);
- 从机回 ACK;
- 发自定义数据(如配置值 0x55);
- 从机回 ACK;
- 主机发终止信号(P),释总线。
2. 主机←从机(读传输,先写后读)
- 主机发起始信号(S);
- 发 “7 位从机地址 + W”(如 0x80),从机回 ACK;
- 发目标寄存器地址(如 SHT20 湿度寄存器 0xE5),从机回 ACK;
- 主机发重复起始信号(S);
- 发 “7 位从机地址 + R(1)”(如 SHT20 读地址 0x81),从机回 ACK;
- 从机发自定义数据(如 2 字节湿度值 0x1234),每字节主机回 ACK;
- 主机收完回 NACK(停传);
- 主机发终止信号(P)。
三、I2C 工作时序(以 SHT20 读温度为例)
1. 时序参数
- 从机地址:7 位 0x40;
- 寄存器地址:0xE3(温度寄存器);
- 自定义数据:2 字节温度值(0x1A、0x5B);
- 时钟周期:1 个高 + 低电平,传 1 位需 1 周期。
2. 时序文字示意
信号 | 时序(高电平 “┌───┐”,低电平 “───”) | 阶段说明 |
SCL | ──┐ ┌───┐×8 ┌───┐ ┌───┐×8 ┌───┐×2 ┌───┐ | 时钟同步 |
SDA | ──┼───┼───┼×8───┼───┼───┼×8───┼───┼───┼×2───┼───┘ | 数据 / 控制信号 |
阶段 | S → 写寻址(0x80)→ ACK → 寄存器(0xE3)→ ACK → 重复 S → 读寻址(0x81)→ ACK → 数据(0x1A→ACK→0x5B→NACK)→ P | 传输流程 |
3. 时序步骤
- S(起始):SCL 高时,SDA 高→低(下降沿);
- 写寻址:SCL 高时,SDA 传 0x80(8 位),从机回 ACK;
- 寄存器地址:SCL 高时传 0xE3,从机回 ACK;
- 重复 S:SCL 高时,SDA 高→低;
- 读寻址:SCL 高时传 0x81,从机回 ACK;
- 传数据:SCL 高时从机传 0x1A(高 8 位),主机回 ACK;再传 0x5B(低 8 位),主机回 NACK;
- P(终止):SCL 高时,SDA 低→高(上升沿)。
答题区:
答题要求:闭卷考试(不能翻书、不能开电脑);作答时间50分钟;共10道题目。
(请保留第原题目,答题区请备注好做题序号;只能写在答题纸上拍照粘贴到文档里-答题区,请保证照片清晰)
发送时:请将文档命名更改为:本人姓名_软件笔试题