考试时间: 120分钟
总分: 100分
注意: 编程题中所涉及的寄存器地址和功能说明会随题目提供,无需记忆。
一、 填空题 (每空1分,共20分)
- 计算机系统唯一能直接识别和执行的语言是_________语言。8位二进制补码能表示的十进制整数范围是_________。
- Cortex-M3处理器支持两种工作模式:_________模式和处理模式。处理器复位后,会进入_________模式。
- 在Cortex-M3中,堆栈指针SP指向栈顶,其操作模式为_________递减的_________栈模型。
- 若要将GPIO引脚用作外部中断输入,该引脚应配置为_________模式。
- STM32的通用定时器(TIM)的核心部件是16位的计数器、和。
- 异步串行通信(UART)的数据帧由1位起始位、8位数据位、1位可选的_________位和1或2位停止位组成。
- 一个12位的ADC,当参考电压
VREF+为3.3V时,其能分辨的最小电压变化量是_________V (结果保留三位有效数字)。 - 执行
BL指令时,下一条指令的地址会自动保存到_________寄存器中,以实现子程序返回。 - Cortex-M3的存储器映射中,片上外设区的起始地址为_________ (十六进制)。
- 已知
[X]补 = 1101 0100B,则其对应的真值X为_________(十进制)。 - 使用
LDR R0, [R1, #4]!指令加载数据后,R1寄存器的内容会_________。 - Cortex-M3内核支持_________个中断,其中包括16个内核异常和最多_________个外部中断。
- 要使寄存器R0的bit[3]置1,同时其他位保持不变,可以使用指令
ORR R0, R0, #_________。 - 在内存扩展中,若地址总线为24位,数据总线为16位,则该存储器的最大寻址空间为_________MB,其带宽与总线时钟频率有关。
二、 单项选择题 (每题2分,共20分)
- 下列哪个指令的执行结果不会影响APSR寄存器中的标志位?
A.ADDS R1, R2, R3
B.CMP R0, #10
C.MOV R0, R1
D.SUBS R0, R0, #1 - 关于Cortex-M3处理器的流水线,下列说法错误的是?
A. 采用三级流水线:取指、译码、执行。
B. 分支指令(如B, BL)的执行会导致流水线被清空。
C.MOV指令的执行时间通常为一个时钟周期。
D. 流水线技术主要是为了降低处理器的功耗。 - 在STM32中,配置一个GPIO引脚为推挽输出模式,当输出高电平时,其电平由哪个部件决定?
A. P-MOS管
B. N-MOS管
C. 外部上拉电阻
D. 施密特触发器 - 当一个抢占优先级为3,响应优先级为1的中断正在执行时,下列哪个中断可以将其打断(嵌套)?
A. 抢占优先级为3,响应优先级为0
B. 抢占优先级为3,响应优先级为2
C. 抢占优先级为2,响应优先级为3
D. 抢占优先级为4,响应优先级为0 - 已知STM32的APB1总线时钟为36MHz,若TIM2的时钟预分频系数为1,则TIM2的时钟频率为?
A. 18 MHz
B. 36 MHz
C. 72 MHz
D. 9 MHz - 在8位数据、无校验、1位停止位的异步串行通信中,波特率为9600 bps,理论上每秒最多能传输多少个完整字符?
A. 1200
B. 960
C. 1066
D. 9600 - 若要将存储在R0寄存器中的一个字节(8位)数据
0xAB,符号扩展为32位数据存入R1,应使用哪条指令?
A.UXTB R1, R0
B.SXTB R1, R0
C.REV R1, R0
D.AND R1, R0, #0xFF - 一个12位DAC的参考电压为5V,若要其输出2V电压,应向DAC数据寄存器写入的十六进制值最接近?
A.0xCCC
B.0x666
C.0x333
D.0x199 - 下列哪种存储器在断电后数据会丢失?
A. Flash Memory
B. EEPROM
C. SRAM
D. ROM - 在Cortex-M3中,执行
PUSH {R0, LR}指令后,堆栈指针SP的值会如何变化?
A. SP = SP + 8
B. SP = SP - 8
C. SP = SP + 4
D. SP = SP - 4
三、 简答题 (每题5分,共20分)
- 简述冯·诺依曼结构与哈佛结构的主要区别,并说明Cortex-M3内核更接近哪种结构及其优势。
- 什么是中断向量表?它在中断处理过程中的作用是什么?
- 简述在ARM汇编中,
B指令和BL指令的功能和主要应用场景上的区别。 - 简述GPIO的“推挽输出”和“开漏输出”两种模式的工作原理和主要应用区别。
四、 C与汇编程序分析题 (共20分)
1. C语言程序分析 (10分)
下面是一段STM32的C语言代码,用于初始化GPIO和定时器。
假设: SystemCoreClock 已被正确设置为72MHz。
void GPIO_Init_LED(void) {
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 1. 使能GPIOB时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // 2. 选择PB5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 3. 设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 4. 设置速度
GPIO_Init(GPIOB, &GPIO_InitStructure); // 5. 初始化GPIOB
}
void TIM3_Init_Timer(void) {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 6. 使能TIM3时钟
// APB1时钟36MHz, TIM3时钟为72MHz
TIM_TimeBaseStructure.TIM_Period = 4999; // 7. 自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler = 7199; // 8. 预分频值
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 9. 向上计数
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); // 10. 使能更新中断
TIM_Cmd(TIM3, ENABLE); // 11. 启动定时器
}
请回答:
(1) GPIO_Init_LED 函数完成了什么功能?
(2) TIM3_Init_Timer 函数设置的定时器中断周期是多长?请写出计算过程。
2. 汇编程序分析 (10分)
分析以下ARM汇编代码段,并回答问题。
假设程序开始执行时,R0 = 5, R1 = 0x20000100, R2 = 0。
内存地址 0x20000100 开始依次存放的32位字数据为: 10, -3, 8, 2, -7。
AREA MY_CODE, CODE, READONLY
ENTRY
START
LDR R3, [R1] ; (1)
ADD R1, R1, #4 ; (2)
CMP R3, #0 ; (3)
BPL POSITIVE ; (4)
B NEXT ; (5)
POSITIVE
ADD R2, R2, R3 ; (6)
NEXT
SUBS R0, R0, #1 ; (7)
BNE START ; (8)
STOP
B STOP ; (9)
请回答:
(1) 逐行解释指令(1)到(8)的功能。
(2) 当程序执行到 STOP 循环时,寄存器 R0 和 R2 的最终值分别是多少?
五、 汇编编程题 (共20分)
题目要求:
编写一段完整的ARM汇编程序,实现对一个32位有符号整数数组的冒泡排序(从小到大)。
已知条件与约定:
- 数组首地址存放在
R0寄存器中。 - 数组元素的个数(长度)存放在
R1寄存器中。 - 你可以使用
R2到R7作为通用寄存器。 - 程序需要包含数据定义部分,用于测试。
示例数据:
MyArray DCD 5, 2, 8, 1, 9
完成排序后,MyArray 中的数据应为: 1, 2, 5, 8, 9
请写出完整的、带注释的汇编代码。
参考答案及解析
一、 填空题 (每空1分,共20分)
- 机器 / 二进制, -128 ~ +127
- 解析: 计算机硬件只能理解由0和1组成的机器码。8位二进制补码的表示范围是 −28−1 到 28**−1−**1。
- 线程, 线程
- 解析: Cortex-M3主要在线程模式下执行普通程序,在发生异常(如中断)时进入处理模式。复位是一种特殊的异常,但复位后代码开始执行,进入的是线程模式。
- 向下, 满
- 解析: Cortex-M3采用满递减堆栈,即PUSH操作时SP先减小地址,再存入数据,SP始终指向栈顶最后一个有效数据。
- 输入
- 解析: 中断是外部信号触发的,GPIO引脚必须能读取外部电平变化,所以要配置为输入模式(浮空、上拉或下拉)。
- **预分频器 (PSC)**, 自动重装载寄存器 (ARR)
- 解析: 这三者构成了定时器的基本计时单元。时钟源经过预分频器分频后驱动计数器计数,当计数值达到自动重装载寄存器的值时产生事件(如中断)。
- 校验
- 解析: 异步通信帧中,校验位是可选的,用于数据校验,可以是奇校验或偶校验。
- 0.000806
- 解析: 分辨率 = VREF/2N**=3.3V**/212**=**3.3/4096**≈**0.00080566**V**。
- LR (R14)
- 解析:
BL(Branch with Link) 指令在跳转前,会将返回地址(下一条指令的地址)存入链接寄存器LR。
- 解析:
- 0x40000000
- 解析: 这是Cortex-M3标准存储器映射中,外设(Peripherals)区域的起始地址。
- -44
- 解析:
1101 0100是补码,最高位为1表示负数。求其原码步骤:符号位不变,数值位取反加一。101 0100-> 取反010 1011-> 加一010 1100。所以原码为1010 1100,值为 −(32+8+4)=−44。
- 自动增加4
- 解析:
!表示地址回写。LDR R0, [R1, #4]!是先变址后加载,即先计算R1 + 4作为加载地址,然后将这个新地址写回到R1中。
- 256, 240
- 解析: Cortex-M3支持256个中断,其中1-16号为系统内核异常,17-256号(共240个)为外部中断。
- 8 (或
0x8)
- 解析:
0x8的二进制是0b1000,ORR操作可以让bit[3]置1而不影响其他位。
- 16
- 解析: 寻址空间 = 2地址线位数**=224**=**16**,**777**,**216** 字节 = 16 MB。
二、 单项选择题 (每题2分,共20分)
- C.
MOV R0, R1- 解析:
ADDS和SUBS中的S后缀明确表示要更新APSR标志位。CMP指令的功能就是比较并更新标志位。常规的MOV指令不影响标志位。
- 解析:
- D. 流水线技术主要是为了降低处理器的功耗。
- 解析: 流水线技术通过并行处理指令的不同阶段,提高了指令的吞吐率和处理器的性能,而不是为了降低功耗。
- A. P-MOS管
- 解析: 在推挽输出(Push-Pull)模式下,输出高电平时,P-MOS管导通,将引脚上拉到VDD;输出低电平时,N-MOS管导通,将引脚下拉到VSS。
- C. 抢占优先级为2,响应优先级为3
- 解析: 中断嵌套只由抢占优先级决定。只有当新中断的抢占优先级高于当前正在执行的中断的抢占优先级时,才会发生嵌套。2 < 3,所以可以嵌套。
- C. 72 MHz
- 解析: 在STM32中,APB1总线时钟如果存在预分频(不为1),则其上的定时器时钟会自动倍频。若APB1时钟为36MHz(72/2),则TIM2-TIM7的时钟会恢复到72MHz。如果APB1预分频系数为1,则TIM时钟就是APB1时钟频率36MHz。题干这里有歧义,但通常意指APB1有分频的情况,则TIM时钟为72MHz。如果严格按APB1 36MHz算且预分频为1,则TIM时钟为36MHz。但根据STM32特性,选C更符合设计意图。
- B. 960
- 解析: 每传输一个字符需要
1 (起始位) + 8 (数据位) + 1 (停止位) = 10位。所以每秒传输的字符数 = 9600/10=960。
- 解析: 每传输一个字符需要
- B.
SXTB R1, R0- 解析:
SXTB(Sign Extend Byte) 指令将源寄存器中的一个字节(bit[7:0])进行符号扩展到32位。bit[7]是符号位,它会被复制到新寄存器的高24位。UXTB是无符号扩展。
- 解析:
- B.
0x666- 解析: 计算公式:
Value = (V_out / V_ref) * (2^N - 1)。Value = (2V / 5V) * 4095 = 0.4 * 4095 = 1638。转换成十六进制为0x666。
- 解析: 计算公式:
- C. SRAM
- 解析: SRAM (Static Random-Access Memory) 是易失性存储器,断电后数据会全部丢失。Flash, EEPROM, ROM 都是非易失性的。
- B. SP = SP - 8
- 解析:
PUSH指令遵循满递减堆栈模型。每压入一个32位寄存器,SP地址减4。压入两个寄存器(R0, LR),SP地址减8。
三、 简答题 (每题5分,共20分)
- 区别:
- 冯·诺依曼结构: 程序指令和数据存储在同一个存储空间中,共用一套地址总线和数据总线。
- 哈佛结构: 程序指令和数据存储在两个独立的存储空间中,各有独立的地址总线和数据总线。
Cortex-M3结构:
Cortex-M3内核采用了哈佛结构。
优势: 由于指令和数据总线分离,处理器可以同时进行取指令和读写数据操作,避免了访问冲突,提高了执行效率和数据吞吐率,这对于需要高速处理的嵌入式系统至关重要。
- 定义:
中断向量表是一个存储中断服务程序(ISR)入口地址的连续内存区域。它本质上是一个地址数组。
作用:
当一个中断发生时,CPU会停止当前任务,并根据中断源的唯一编号(中断号),自动地到中断向量表中查询对应的表项。从该表项中取出ISR的入口地址,然后跳转到该地址开始执行中断服务程序。它为CPU提供了一个快速、直接地定位和跳转到相应中断处理程序的机制。 - 区别:
B指令 (Branch): 这是一个简单的无条件跳转指令。它只是将程序计数器PC的值修改为目标地址,使程序从新的地址继续执行。它不保存返回地址,通常用于实现循环或程序内的简单跳转。BL指令 (Branch with Link): 这是一个带链接的跳转指令,主要用于调用子程序。在跳转到目标地址之前,它会把下一条指令的地址(即返回地址)保存在**链接寄存器LR (R14)**中。当子程序执行完毕后,可以通过MOV PC, LR或BX LR指令返回到主程序的调用点继续执行。
- 工作原理:
- 推挽输出 (Push-Pull): 由一个P-MOS管和一个N-MOS管组成。输出高电平时,P-MOS导通,N-MOS截止,引脚被"推"到高电平;输出低电平时,N-MOS导通,P-MOS截止,引脚被"拉"到低电平。
- 开漏输出 (Open-Drain): 只使用N-MOS管。输出低电平时,N-MOS导通,将引脚拉到低电平。当需要输出高电平时,N-MOS截止,引脚处于高阻态(浮空),需要外部上拉电阻将其拉到高电平。
应用区别: - 推挽输出: 驱动能力强(既能输出高电流也能灌入大电流),开关速度快。适用于驱动LED、驱动其他芯片的逻辑输入引脚等大多数场合。
- 开漏输出: 可以实现"线与"逻辑,即多个开漏输出引脚可以连接到同一根线上,只要有一个输出低电平,整条线就是低电平。常用于I2C、SMBus等总线通信,或需要灵活电平转换的场合。
四、 C与汇编程序分析题 (共20分)
1. C语言程序分析 (10分)
(1) GPIO_Init_LED 函数功能:
该函数初始化了STM32的GPIOB端口的第5个引脚(PB5)。它首先使能了GPIOB端口的时钟,然后将PB5引脚配置为高速(50MHz)的推挽输出模式。这通常是为驱动一个LED灯做准备。
(2) 中断周期计算:
* 定时器时钟频率 TIM_CLK = 72 MHz (因为APB1时钟为36MHz,有分频,所以TIM3时钟会倍频到72MHz)。
* 预分频后的计数器时钟 CNT_CLK = TIM_CLK / (Prescaler + 1) = 72,000,000 / (7199 + 1) = 72,000,000 / 7200 = 10,000 Hz。
* 溢出(更新)周期 T = (Period + 1) / CNT_CLK = (4999 + 1) / 10,000 = 5000 / 10,000 = 0.5 秒。
结论: 定时器中断周期为0.5秒。
2. 汇编程序分析 (10分)
(1) 指令功能解释:
* (1) LDR R3, [R1]: 将R1寄存器所指向的内存地址中的32位数据加载到R3寄存器。
* (2) ADD R1, R1, #4: R1寄存器的值加4,使其指向下一个32位字数据。
* (3) CMP R3, #0: 比较R3寄存器的值和0,并根据结果更新APSR标志位。
* (4) BPL POSITIVE: 如果比较结果为正数或零(Plus or zero, N=0),则跳转到POSITIVE标签处执行。
* (5) B NEXT: 如果不满足BPL的条件(即R3为负数),则无条件跳转到NEXT标签处。
* (6) ADD R2, R2, R3: 将R3的值加到R2上,实现累加。
* (7) SUBS R0, R0, #1: R0寄存器的值减1,并根据结果更新APSR标志位(因为有S后缀)。
* (8) BNE START: 如果SUBS操作的结果不为零(Z=0),则跳转回START标签处,继续循环。
(2) 最终值:
该程序的功能是遍历一个有5个元素的数组,并将其中所有的正数累加到R2中。
* 数组元素: 10, -3, 8, 2, -7
* 其中的正数: 10, 8, 2
* R0的最终值: R0作为循环计数器,从5开始,每次循环减1,执行5次后变为0。所以最终值为 0。
* R2的最终值: R2用于累加正数,10 + 8 + 2 = 20。所以最终值为 20 (十六进制为 0x14)。
五、 汇编编程题 (共20分)
; 冒泡排序ARM汇编程序
; 功能:对一个32位有符号整数数组进行从小到大排序
; 输入: R0 = 数组首地址, R1 = 数组元素个数
; 使用: R2-R7 作为临时寄存器
AREA BubbleSort, CODE, READONLY
ENTRY ; 程序入口
MAIN
LDR R0, =MyArray ; 加载数组首地址到R0
LDR R1, =ArrayLen; 加载数组长度地址
LDR R1, [R1] ; 加载数组长度值
; 外层循环控制排序的趟数 (n-1)趟
SUB R2, R1, #1 ; R2 = i = n-1 (外层循环计数器)
OUTER_LOOP
CMP R2, #0 ; 如果 i <= 0, 排序完成
BLE SORT_END
; 内层循环控制每趟的比较次数
MOV R3, #0 ; R3 = j = 0 (内层循环计数器)
MOV R4, R0 ; R4 = 当前比较元素的地址指针
INNER_LOOP
CMP R3, R2 ; 如果 j >= i, 当前这趟比较完成
BGE NEXT_PASS
LDR R5, [R4] ; 加载当前元素 list[j] 到 R5
LDR R6, [R4, #4] ; 加载下一个元素 list[j+1] 到 R6
CMP R5, R6 ; 比较 list[j] 和 list[j+1]
BLE NO_SWAP ; 如果 list[j] <= list[j+1],不交换
; 交换两个元素
STR R6, [R4] ; list[j] = R6 (原list[j+1])
STR R5, [R4, #4] ; list[j+1] = R5 (原list[j])
NO_SWAP
ADD R3, R3, #1 ; j++
ADD R4, R4, #4 ; 指针移到下一个元素
B INNER_LOOP ; 继续内层循环
NEXT_PASS
SUB R2, R2, #1 ; i--
B OUTER_LOOP ; 开始下一趟排序
SORT_END
; 排序完成,程序在此处停止
B SORT_END
AREA MyData, DATA, READWRITE
MyArray DCD 5, 2, 8, 1, 9 ; 定义待排序的数组
ArrayLen DCD 5 ; 定义数组长度
END ; 程序结束