【程序状态寄存器读写指令】
1.指令码以及格式
mrs:读取CPSR寄存器的值
mrs 目标寄存器 CPSR:读取CPSR的数值保存到目标寄存器中
msr:修改CPSR寄存器的数值
msr CPSR,第一操作数:将第一操作数的数值保存到CPSR寄存器中
//修改CPSR寄存器,也就表示程序的状态发生了变化
10000
2.实例代码
mrs r1,cpsr @从目标寄存器中读
@切换到user模式,只修改模式位,其他位不变
bic r1,#0x1f @低5位清0
orr r1,#0x10 @低5位置位
@将修改后的CPSR数值写回
msr cpsr,r1
注意:在user模式下不可以手动修改CPSR的数值
USER模式是 唯一的非特权模式,如果这个模式下随便修改CPSR的数值会对整个系统造成一些不好的影响。
USER模式也不可以手动切换到其他模式,需要发生对应的异常才可以进入对应的异常模式
【软中断指令】
1.概念
软中断是在软件层次上模拟出的一个中断,和硬件中断一样,软中断触发后也会执行对应的中断处理程序。当执行了软中断之后,处理器的工作模式由USER模式切换为SVC模式
2.软中断指令码以及格式
swi 中断号
注意:
中断号是一个由24位二进制数组成的一个立即数。不同的中断号用于区分不同的中断。
3.异常处理过程分析
3.1 异常模式和异常源的对应关系
5种异常模式对应7种异常源
|-------|----------------|---------------------------|
| 异常模式 | 异常源 | 解释 |
| FIQ | FIQ类型异常源 | 一些硬件发生了FIQ异常事件进入FIQ模型 |
| IRQ | IRQ类型异常源 | 一些硬件发生了IRQ异常事件进入IRQ模型 |
| SVC | 复位信号 | 按键复位/上电复位时产生 |
| | swi软中断指令 | 执行swi指令 |
| undef | 未定义异常源 | 译码器在翻译指令时,遇到无法翻译的指令,指令未定义 |
| abort | data abort | 取数据发生异常时 |
| | prefetch abort | 取指令发生异常时 |
5种异常模式对应7种异常源
当发生异常时处理器就会进入对应的异常模式工作
执行异常处理程序,完成特定的功能
5种异常模式对应7种异常源,异常源的优先级中复位信号的优先级最高
3.2 异常的处理过程分析
**********异常处理过程(CPU自动完成)****************
分为4大步3小步,主要为了保存现场以及程序的跳转和模式的切换
1. 保存发生异常之前的CPSR的值存放在对应异常的SPSR寄存器中
2.修改CPSR的值
1>`修改状态位(T位 第5位),切换为ARM状态
2>根据实际情况禁止IRQ和FIQ中断 ([7:6])
3>修改模式位为对应的异常模式
3.将返回地址保存在对应异常模式下的LR寄存器中
4.修改PC的值,指向对应的异常向量表位置
***********恢复现场(手动完成)***********
1.恢复CPSR的值为未发生异常之前的状态
2.修改PC寄存器的值,PC=LR
3.3 异常向量表
1.异常向量表是内存空间中的一段特殊的内存。这段内存有32字节大小。这个内存被平分为8等份。每一份4字节
2.异常向量表存放的是7种异常源对应的异常处理程序的跳转指令,有一份保留
3.7种异常源在异常向量表中的位置是固定不可变的
4.只要指定异常向量表的基地址,既可以根据不同异常源在异常向量表中的偏移量找到对应异常的跳转指令,进入不同的异常处理程序
4.软中断异常处理实例代码
.text
.global _start
_start:
@初始化异常向量表
b main
b .
b do_swi
b .
b .
b .
b .
b .
main:@主程序
@初始化栈
mov sp,#0X40000020
@切换到USER模型
msr cpsr,#0X10
mov r1,#1
mov r2,#2
@产生软中断
swi 1
add r3,r1,r2
b main
do_swi:@异常处理程序
@保护现场
stmfd sp!,{r1,r2,lr}
mov r1,#4
mov r2,#5
mul r4,r1,r2
@出栈恢复现场 pc=lr cpsr=spsr
ldmfd sp!,{r1,r2,pc}^ @^表示修改PC的值同时将CPSR的值修改
wh:
b wh
.end
【C和汇编的混合编程】
1.混合编程的意义
所谓的混合编程就是c语言资源和汇编资源的相互调用
- 一般工程会有汇编启动程序,启动程序完成堆栈的相关初始化,完毕之后才跳转到c语言的main函数
- c语言中几乎不可以直接操作寄存器,但是有些特定场景下需要c中操作寄存器,这时候就需要c语言中嵌套汇编的语法
2.概述
要想实现C和汇编的混合编程必须遵循ATPCS规范。
ATPCS : ARM-Thumb Procedure Call Standard
int add(int i,int j)
{
return i+j;
}
函数参数的传递采用R0-R3进行传递,如果参数的个数大于4个通过压栈的方式进行传递
函数的返回值通过R0返回,如果函数的返回值大于4个字节通过r0-r1返回。
ATPCS规范中规定ARM采用满减栈。
3.汇编中调用c语言的函数
汇编调用C语言的函数,需要将c语言的函数当作汇编的标签使用,函数传递的参数保存在R0-R3寄存器中,函数的返回值最终保存在R0寄存器中
*****汇编文件**********
.text
.global _start
_start:
@ 1. 初始化栈指针,C代码运行必须有栈
ldr sp, =0x40000820
@ 2. 汇编调用c函数
@ 2.1 给C的函数传递实参值
mov r0, #3 @ a = 3
mov r1, #4 @ b = 4
mov r2, #5 @ c = 5
mov r3, #6 @ d = 6
@ 2.2 汇编调用c的函数
bl add_func
@ 2.3 函数的返回通过r0返回,查看r0寄存器中的值
loop:
b loop
.end
**********c文件********************
// c代码的函数是一个全局的函数
int add_func(int a, int b, int c, int d)
{
return (a+b+c+d);
}
4.c语言调用汇编的标签
c语言中想要调用汇编中的标签,只需要在c语言文件中将标签声明为函数的形式即可
********起始汇编文件**********
.text
.globl _start
_start:
@ 1. 初始化栈指针,C代码运行必须有栈
ldr sp, =0x40000820
@ 2. 汇编调用c,跳转到main函数
b main
.end
********c文件************
// 使用extern对函数进行声明
extern int add_func(int a, int b, int c, int d);
int sum = 0;
int main()
{
// 在c代码中调用汇编代码
sum = add_func(1,2,3,4);
while(1);
return 0;
}
********汇编文件**********
.text
.global add_func @ 将add_func函数声明为全局
add_func:
add r0, r0, r1
add r0, r0, r2
add r0, r0, r3
mov pc, lr
.end
5.c语言内联汇编
在某一些特定的场景下需要在c语言中直接使用汇编的语法,此时需要内联汇编。内联汇编的实现需要通过asm关键字进行修饰
5.1 格式
asm volatile(
"汇编指令模板\n\t" //"\n\t"表示一条指令的结束
.....
:输出列表 //指令结果的输出值
:输入列表 //指令的数据输入
:破坏列表 //破坏列表指定我们当前可用的寄存器
);
5.2 实例
********汇编启动文件*******
.text
.globl _start
_start:
@ 1. 初始化栈指针,C代码运行必须有栈
ldr sp, =0x40000820
@ 2. 汇编调用c,跳转到main函数
b main
.end
**********c语言文件***********
// 内联汇编
int add_func2(int a, int b, int c, int d)
{
int sum = 0;
// 使用汇编实现求和
asm volatile( "add r0, r0, r1\n\t" "add r0, r0, r2\n\t" "add r0, r0, r3\n\t" :"=r"(sum) :"r"(a),"r"(b),"r"(c),"r"(d) :"memory" );
return sum;
}
//"=r"(sum)表示输出从寄存器中放到变量sum中
// "r"(a) 指定输入从变量a中获取放到通用寄存器
//"memory"声明使用内存
// 使用extern对函数进行声明
extern int add_func(int a, int b, int c, int d);
int sum = 0;
int main()
{
// 调用内联汇编的函数
sum = add_func2(5,6,7,8);
// 在c代码中调用汇编代码
sum = add_func(1,2,3,4);
while(1);
return 0;
}
*********汇编文件*************
.text
.global add_func @ 将add_func函数声明为全局
add_func:
add r0, r0, r1
add r0, r0, r2
add r0, r0, r3
mov pc, lr
.end
【开发板介绍】
1.核心板介绍
2.拓展板
【相关硬件基础内容介绍】
1.PCB
PCB( Printed Circuit Board),中文名称为印制电路板,又称印刷线路板,是重要的电子部件,是电子元器件的支撑体,是电子元器件电气相互连接的载体。由于它是采用电子印刷术制作的,故被称为"印刷"电路板。
2.电路板丝印
可以通过不同元器件的丝印标号在电路原理图中对应的硬件原理图
电路板丝印是用丝网bai印刷技术来制作印刷电路板。丝印值得是丝印层,画pcb的时候是分层的,其中包含文字的那一层,用来标注元件或者添加其他信息,这一层叫丝印层。
通过丝网印刷方式将元件外形、序号以及其他说明性文字印制在元件面或焊锡面上,以方便电路板生产过程的插件(包括表面封装元件的贴片)以及日后产品的维修操作。
不同的电路元件的丝印图:
Ux:常作为开发板上芯片的标号
Rx:电阻
Cx:电容
Dx:二极管
Qx:三极管
标准器件的丝印的编号:
U? --> 芯片 C? --> 电容 R? --> 电阻 L? --> 电感
D? --> 二极管 Q? --> 三极管 J? --> 接插件 CON? --> 接插件
非标准器件的丝印编号:器件的编号的名字可以自定义
FAN1 --> 风扇
LD1 --> LED1灯
KEY1 --> 按键1
4. 网络标号
在原理图上,器件引脚上边红色的字,就是网络标号,
网络标号相同的两个引脚说明具有相同的电器连接属性,
即在PCB板上两个引脚通过导线进行连接。
3.网络标号
网络标号(net label)是一个电气连接点,一般由字母或数字组成,具有相同网络标号的电气连接线、管脚、及网络是连接在一起的