
问题:如 STM32IO 内部框图中 A、B、C、D 4 个信号点哪个是 GPIO 作为 AD 采样时输入的信号端?理由是?
答案 :C 点。理由:AD 采样是 "模拟信号输入",需经过施密特触发器前的模拟通道(C 点对应模拟输入路径,而 A/B/D 对应数字 I/O 或输出路径)。

问题:以下有关 SPI 说法正确的是()选项:A.SPI 有 3 中工作模式;B.MOSI 是主机的通信输入引脚;C.MISO 是从机通信输入引脚;D. 在工作方式一中,时钟下降沿数据有效
答案 :无正确选项(若题目存在表述误差,实际 SPI 有 4 种工作模式;MOSI 是主机输出 / 从机输入;MISO 是主机输入 / 从机输出;方式一下时钟上升沿采样)。
SPI 的 4 种工作模式由 **CPOL(时钟极性)和CPHA(时钟相位)** 两个参数组合决定:
| 工作模式 | CPOL(时钟空闲电平) | CPHA(数据采样时刻) | 通信逻辑 |
|---|---|---|---|
| 模式 0 | 0(空闲时 SCLK 为低) | 0(第 1 个时钟沿采样) | SCLK 空闲低→第 1 个上升沿采样数据,第 1 个下降沿更新数据 |
| 模式 1 | 0(空闲时 SCLK 为低) | 1(第 2 个时钟沿采样) | SCLK 空闲低→第 1 个下降沿更新数据,第 2 个上升沿采样数据 |
| 模式 2 | 1(空闲时 SCLK 为高) | 0(第 1 个时钟沿采样) | SCLK 空闲高→第 1 个下降沿采样数据,第 1 个上升沿更新数据 |
| 模式 3 | 1(空闲时 SCLK 为高) | 1(第 2 个时钟沿采样) | SCLK 空闲高→第 1 个上升沿更新数据,第 2 个下降沿采样数据 |
简单记:CPOL 决定空闲时钟的高低,CPHA 决定 "第 1 个沿是采样还是更新"。

问题:关于中断嵌套,以下说法正确的是()选项:A. 中断嵌套会增加栈空间的使用;B. 中断嵌套不会影响程序执行效率;C. 所有单片机都支持中断嵌套;D. 中断嵌套与优先级无关
答案 :A。解析:中断嵌套时,每次中断都会压栈保存现场,因此会增加栈空间占用;B(嵌套会降低效率)、C(并非所有单片机支持)、D(嵌套依赖优先级)均错误。

问题:以下代码在单片机中运行,可能导致什么问题?
void func(){
int large_array[1024*1024];
//其他操作
}
选项:A. 栈溢出;B. 堆溢出;C. 内存泄漏;D. 无问题
答案 :A。解析:局部变量(large_array)存储在栈中,1024*1024 的 int 数组(约 4MB)远超单片机栈的默认大小,会导致栈溢出。

问题:在单片机中,以下哪种方式可以确保中断服务程序 (ISR) 的原子性?选项:A. 使用全局变量;B. 使用 volatile 关键字;C. 禁用中断;D. 使用动态内存分配
答案 :C。解析:原子性指操作不可被打断,禁用中断可避免 ISR 执行时被其他中断打断;A(全局变量不保证原子性)、B(volatile 仅保证内存可见性)、D(动态分配与原子性无关)均错误。

1. 宏定义表达式
问题 :#define HW_KEY_Y (0x01 << 4),HW_KEY_Y 的十六进制值 =?十进制值 =?计算0XC3 & (0X80)=?答案:
- 十六进制:
0x10(0x01<<4即1×16=16,对应十六进制 0x10) - 十进制:
16 0XC3 & 0X80:0xC3 是11000011,0X80 是10000000,按位与结果为10000000,即0X80(十进制 128)
2. 宏定义运算
问题 :#define MAX(x,y) x>y?x:y,int a=3,b=2时,执行MAX(a++,++b)后,结果、a、b 分别是?答案 :宏展开为a++>++b?a++:++b:
- 先算
a++>++b:a=3(后自增),b 先自增为 3 →3>3不成立; - 执行
++b:b 变为 4; - 最终:结果 = 4,a=4(a++ 执行后),b=4。
3. 数组与指针
问题 :int *p[10]中 p 表示?int (*q)[10]中 q 表示?答案:
int *p[10]:p 是指针数组(存储 10 个 int 类型指针的数组);int (*q)[10]:q 是数组指针(指向 "包含 10 个 int 元素的数组" 的指针)。

指针与数组输出
问题:代码输出是?
int main(){
int arr[]={1,2,3,4,5};
int *p=(int*)(&arr+1);
printf("arr=%d,%d\n",*(arr+1),*(p-1));
}
答案:
*(arr+1):arr 是数组首地址,arr+1指向元素 2 → 输出 2;&arr+1:指向数组 arr 的 "下一个数组",p-1指向 arr 最后一个元素 5 → 输出 5;最终输出:arr=2,5。

结构体大小与输出
问题:
typedef struct{
char a;
unsigned short b;
}test_t;
int i;
test_t test={0x01,0x02};
char *p=(char*)&test;
for(i=0;i<sizeof(test_t);i++){
printf("%x,",p[i]);
}
- 结构体 test_t 大小是?
- printf 输出是?
- 题目条件不足的点是?
答案:
- 结构体大小:受内存对齐 影响,char 占 1 字节,unsigned short 占 2 字节,对齐后总大小为4 字节(a 占 1 字节,补 1 字节对齐,b 占 2 字节);
- 输出:依赖内存字节序 (小端 / 大端),若小端对齐:a=0x01,b=0x02(占 2 字节,小端存储为 0x02、0x00),补 1 字节为 0x00 → 输出
1,0,2,0,; - 条件不足:未说明内存对齐规则 和处理器字节序(小端 / 大端)。

1. 按键控制 LED 翻转
问题 :编写程序,通过按键输入控制 LED 状态翻转(按下按键时,LED 从亮变灭 / 从灭变亮)。已知函数:api_gpio_in()(读取按键 IO)、api_set_led_on()(亮灯)、api_set_led_off()(灭灯),补全代码:
void main(void){
//do thing....
While(1){
// 补全逻辑
}
}
答案 :需增加按键消抖 和状态变量,代码如下:
void main(void){
// 定义LED状态(0=灭,1=亮)
uint8_t led_state = 0;
// 按键状态(0=未按下,1=按下)
uint8_t key_state = 0;
// 初始化LED为灭
api_set_led_off();
While(1){
// 读取按键状态(假设按键按下时返回1)
key_state = api_gpio_in();
// 按键按下(消抖:简单延时后再确认)
if(key_state == 1){
// 消抖延时(比如10ms,根据实际需求调整)
delay_ms(10);
// 再次确认按键按下
if(api_gpio_in() == 1){
// 翻转LED状态
if(led_state == 0){
api_set_led_on();
led_state = 1;
}else{
api_set_led_off();
led_state = 0;
}
// 等待按键释放(避免重复触发)
while(api_gpio_in() == 1);
}
}
}
}

2. n×n 矩阵顺时针旋转 90 度
问题 :编写 C 函数rotateMatrix,将 n×n 二维矩阵顺时针旋转 90 度(如示例:3×3 矩阵旋转后行列交换并逆序)。
答案 :思路:先转置矩阵 ,再反转每一行,代码如下:
#define N 100
void rotateMatrix(int matrix[N][N]){
// 步骤1:转置矩阵(行变列,列变行)
for(int i = 0; i < N; i++){
for(int j = i + 1; j < N; j++){
// 交换matrix[i][j]和matrix[j][i]
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
// 步骤2:反转每一行的元素
for(int i = 0; i < N; i++){
for(int j = 0; j < N/2; j++){
// 交换matrix[i][j]和matrix[i][N-1-j]
int temp = matrix[i][j];
matrix[i][j] = matrix[i][N-1-j];
matrix[i][N-1-j] = temp;
}
}
}
示例验证:原矩阵:
1 2 3
4 5 6
7 8 9
转置后:
1 4 7
2 5 8
3 6 9
反转每一行后(即旋转 90 度结果):
7 4 1
8 5 2
9 6 3

3. 不均匀绳子计时问题
问题:粗细不均匀的绳子,烧完 1 根需 1 小时,如何用这批绳子计时 15 分钟、30 分钟、45 分钟?
答案 :利用 "绳子可以从两端同时点燃(烧完时间为原时间的 1/2)" 的特性:
- 30 分钟 :取 1 根绳子,从两端同时点燃,烧完即为 30 分钟。
- 15 分钟 :取 2 根绳子(记为 A、B):
- 同时点燃 A 的两端 + B 的一端;
- A 烧完时(30 分钟),立即点燃 B 的另一端;
- B 剩余部分从两端烧,烧完即为 15 分钟。
- 45 分钟 :取 3 根绳子(记为 A、B、C):
- 同时点燃 A 的两端 + B 的一端 + C 的一端;
- A 烧完时(30 分钟),立即点燃 B 的另一端;
- B 烧完时(额外 15 分钟),总时间为 30+15=45 分钟。