从计算机基础、寄存器知识、汇编指令、中断以及各外设驱动的开发,单片机底层经过这段时间的学习做一个总结。
计算机组成
计算机由输入设备、输出设备、控制器、运算器、存储器组成,存储器分为外部存储器、内部存储器、高速缓存、寄存器,在单片机底层开发中,主要使用寄存器对某一地址进行读写操作,来实现对硬件的驱动。
寄存器
当前使用的STM32U575单片机是ARMv7的架构,32位处理器支持32位指令集,每一条指令都是32位。该单片机的寄存器大小都是4字节(32位)。
寄存器R0~R12
用来保存基本的操作数据和运算的数据。对于ARM32架构,函数调用时前4个参数用通用寄存器(R0~R3),剩余的用栈。对于ARM64架构,函数调用时前8个参数用通用寄存器(R0~R7),剩余的通过栈;
R13寄存器(SP)
栈指针寄存器-专门保存栈内存的栈顶地址,用于进行内存读写;
R14寄存器(LR)
链接寄存器-用于特定程序跳转场景下保存程序返回的地址;
R15寄存器(PC)
程序计数器-用于保存马上要被取指的指令地址,当PC寄存器保存的地址被发送给内存后,PC的数值会自动向下加一条指令的大小,这是程序顺序运行的原因;
CPSR寄存器
当前程序状态寄存器-用于保存当前程序的状态;
SPSR寄存器
被保存的程序状态继寄存器-保存当前程序之前的状态,一般用于异常处理结束后将SPSR的值赋值给CPSR,返回之前状态。
汇编指令
汇编文件一般从.s文件开始,在.s文件内以.end结束,在.end之前要加上循环语句,防止程序越界。汇编指令分为-数据搬移、
立即数-能够经过编码后保存到指令空间中直接当作指令一部分去执行的数据。一个32位指令空间中预留了12位空间保存当前操作数,可以通过某一个规则对操作数进行处理,将处理后的数值存放在这个12位空间中。
立即数规则-将操作数循环右移偶数位,如果能够得到一个0-255内的数据,这个数就是立即数。反过来,得到的数循环右移偶数位,也可能得到操作数。指令中操作数的12位空间分为低8位和高4位,低8位保存循环右移后得到的0-255内的数值,高4位保存0-255内的数值循环右移的偶数位/2的数值。按照这个规则判断这个数或者这个数的取反值,只要一个能确定是立即数,那么这个数和它的取反值都是立即数。(了解即可,一般使用keil编译汇编指令,如果不是立即数,编译直接报错)
数据处理指令
对存放在寄存器中的数据进行操作的指令。
mov {条件码} 目标寄存器, 操作数 功能:将操作数搬移到目标寄存器中 ex:mov r0,#0xFFFFFFFE 表示将0xFFFFFFFE赋值给r0寄存器 |
mvn {条件码} 目标寄存器, 操作数 功能:将操作数取反后的结果搬移到目标寄存器中 |
lsl {条件码} 目标寄存器,第一操作寄存器,第二操作数 功能:将第一操作寄存器的数值逻辑左移第二操作数的位数,最高位移除,低位补零。 |
lsr {条件码} 目标寄存器,第一操作寄存器,第二操作数 功能:将第一操作寄存器的数值逻辑右移第二操作数的位数,最低位移除,高位补零。 |
ror {条件码} 目标寄存器,第一操作寄存器,第二操作数 功能:将第一操作寄存器的数值循环右移第二操作数的位数,最低位移动到最高位。 |
add {条件码} 目标寄存器,第一操作寄存器,第二操作数 功能:第一操作寄存器的数值+第二操作数的结果赋值给目标寄存器,结果不影响CPSR的c位 |
adds {条件码} 目标寄存器,第一操作寄存器,第二操作数 功能:第一操作寄存器的数值+第二操作数的结果赋值给目标寄存器,结果影响CPSR的c位 |
adc {条件码} 目标寄存器,第一操作寄存器,第二操作数 功能:第一操作寄存器的数值+第二操作数+CPSR的c位的值的结果赋值给目标寄存器 |
sub {条件码} 目标寄存器,第一操作寄存器,第二操作数 功能:第一操作寄存器的数据减第二操作数的结果赋值给目标寄存器,结果不影响CPSR的c位 |
subs {条件码} 目标寄存器,第一操作寄存器,第二操作数 功能:第一操作寄存器的数据减第二操作数的结果赋值给目标寄存器,结果影响CPSR的c位 |
sbc {条件码} 目标寄存器,第一操作寄存器,第二操作数 功能:第一操作寄存器的数据减第二操作数再减去CPSR的c位的值的取反值,得到的结果赋值给目标寄存器 |
mul {条件码} 目标寄存器,第一操作寄存器,第二操作数 功能:第一操作寄存器的数值*第二操作数的结果赋值给目标寄存器,结果不影响CPSR |
muls {条件码} 目标寄存器,第一操作寄存器,第二操作数 功能:第一操作寄存器的数值*第二操作数的结果赋值给目标寄存器,结果影响CPSR的N位和Z位 |
and {条件码} 目标寄存器,第一操作寄存器,第二操作数 功能:第一操作寄存器的值&第二操作数的结果赋值给目标寄存器 |
orr {条件码} 目标寄存器,第一操作寄存器,第二操作数 功能:第一操作寄存器|第二操作数的结果赋值给目标寄存器 |
eor {条件码} 目标寄存器,第一操作寄存器,第二操作数 功能:第一操作寄存器异或第二操作数的结果赋值给目标寄存器 |
bic {条件码} 目标寄存器,第一操作寄存器,第二操作数 功能:将第一操作寄存器中的第二操作数中值是1的对应位置零 |
cmp {条件码} 第一操作寄存器,第二操作数 功能:比较第一操作寄存器的数值和第二操作数,并更新相关的标志位,本质是两个数进行减法运算,运算结果控制CPSR的NZCV位,N置一时计算产生符数,Z置一时结果时0,V置一时加法进位/减法不借位。 |
tst {条件码} 第一操作寄存器,第二操作数 功能:判断第一操作寄存器中的第二操作数对应的位是否为0 |
teq {条件码} 第一操作寄存器,第二操作数 功能:比较第一操作寄存器的数值和第二操作数是否相等,指令不影响CPSR的V位和C位 |
跳转指令
用于实现程序的跳转,实现跳转的两种方式:1、使用跳转指令,2、直接修改PC寄存器的值
b {条件码} table_address 功能:跳转到table_address对应的指令,不返回 |
bl {条件码} table_address 功能:跳转到table_address对应的指令,执行结束使用MOV PC,LR返回 |
内存访问指令
可以在arm寄存器和存储器之间进行数据传递的指令。
单寄存器内存访问指令
str {条件码} 第一操作寄存器, [addr] 功能:将第一操作寄存器中的4字节存储到addr指向的地址中,零偏移 |
str {条件码} 第一操作寄存器, [addr, 操作数] 功能:将第一操作寄存器中的4字节存储到addr+操作数指向的地址中,addr的地址值不变 |
str {条件码} 第一操作寄存器, [addr], 操作数 功能:将第一操作寄存器中的4字节存储到addr指向的地址中,传送完成后addr的地址值+操作数 |
str {条件码} 第一操作寄存器, [addr, 操作数]! 功能:将第一操作寄存器中的4字节存储到addr+操作数指向的地址中,传送完成后addr的地址值+操作数 |
strh:在str后加上“h”表示将第一操作寄存器中的2字节数据存储到addr指向的地址中 strb:在str后加上“b”表示将第一操作寄存器中的1字节数据存储到addr指向的地址中 |
ldr {条件码} 第一操作寄存器, [addr] 功能:将addr指向的地址处的数据读出,保存到第一操作寄存器中,addr地址值不变,零偏移 |
ldr {条件码} 第一操作寄存器, [addr, 操作数] 功能:将addr+操作数指向的地址处的数据读出,保存到第一操作寄存器中,addr地址值不变,零偏移 |
ldr {条件码} 第一操作寄存器, [addr], 操作数 功能:将addr指向的地址处的数据读出,保存到第一操作寄存器中,addr地址值+操作数 |
ldr {条件码} 第一操作寄存器, [addr, 操作数]! 功能:将addr+操作数指向的地址处的数据读出,保存到第一操作寄存器中,addr地址值+操作数 |
ldrh:在ldr后加上“h”表示将从addr指向的地址中读出2字节数据保存到第一操作寄存器中 ldrb:在ldr后加上“h”表示将从addr指向的地址中读出1字节数据保存到第一操作寄存器中 |
多寄存器内存访问指令
压栈以及出栈,用于栈内存读写,后缀名有4种,ia后缀、ib后缀、da后缀、db后缀
stm {后缀} addr!,{寄存器list} 功能:将寄存器list中的数据写入到addr对应的地址中 |
ldm {后缀} addr!,{寄存器list} 功能:从寄存器list中读数据,保存到addr对应的地址中 |
栈的操作种类:空栈、满栈、增栈、减栈
组合成四种栈的操作方式:满减栈FD、空减栈ED、满增栈FA、空增栈EA
状态寄存器传送指令
mrs {条件码} 目标寄存器,cpsr 功能:读取CPSR的数值,保存到目标寄存器 |
msr {条件码} cpsr,操作数 功能:修改CPSR的值 |
异常产生指令
swi 操作数 功能:操作数就是产生中断的中断号 |
协处理器指令(略)
异常/中断处理
汇编指令中的异常向量表/中断向量表用于在触发中断后,跳转到中断函数中执行对应的指令。
PS:需要注意的是,interrupt中断函数没有返回值,也没有传参,对于ARM32架构,函数调用时前4个参数用通用寄存器(R0~R3),剩余的用栈。对于ARM64架构,函数调用时前8个参数用通用寄存器(R0~R7),剩余的通过栈;
当异常产生时,拷贝CPSR到SPSR,设置新的CPSR的数值,改变CPU状态进入相应的异常模式,保存返回地址到LR寄存器,设置PC寄存器的值位相应的异常向量表对应的异常向量,异常处理函数处理结束后,将SPSR的值赋给CPSR,将LR的值赋给PC,即可返回正常模式继续执行。
外设驱动
通过寄存器对芯片外部设备进行配置,使能外部设备进行相应的操作。
具体操作就是-通过各类寄存器配置相关外设的时钟RCC使能,配置外设的专属寄存器(通过芯片手册查看),对外设进行控制或通过寄存器对外设的相关数据进行读写操作,完成驱动和通信等功能。
GPIO(通用输入输出)
通过寄存器配置GPIO的时钟RCC使能、输入或输出模式、是否复用、高低电平,等寄存器控制GPIO的驱动,输出高低电平或通过检测GPIO的电平值来达成某些操作。
SPI1
串行全双工同步通信-SCL、MOSI、MISO、CSN
SPI由两个属性来决定通信模式-时钟极性、时钟相位
时钟极性CPOL的值决定了SPI的初始电平,时钟极性为0时,SPI默认低电平;时钟极性为1时,SPI默认高电平;时钟相位CPHA的值为1时,SPI的数据线在SCL时钟线的前沿(不管是上升沿还是下降沿)进行采样,后沿进行输出;时钟相位为0时,SPI的数据线在SCL时钟线的后沿进行采样,前沿进行输出。
USART(通用异步接收/发送器)
串行全双工异步通信-TXD(发送端)、RXD(接收端)、GND(接地)
除了配置USART的RCC时钟和USART对应的GPIO的RCC时钟,再配置对应GPIO的复用功能,使能和设置USART的相关寄存器,实现串口的通信功能。
串口通信有TTL、RS232、RS422、RS485等通信方式。
基本配置起始位、波特率、停止位、校验位、过采样
IIC-I2C
串行半双工同步通信-SCL(时钟线)、SDA(数据线)
通过SCL时钟线和SDA数据线的电平状态决定当前IIC的状态,主机通过从机地址及从机功能码对从机进行访问,实现与从机的通信。由于存在ack应答,通信的准确性较高。
PWM(脉冲宽度调制)
通过TIM定时器输出指定宽度的方波,用于驱动外设进行工作。
PWM方波的指标:PWM周期、PWM频率、PWM占空比
ADC(模拟-数字转换器)
根据算法将接受到的电压或电流信号转换为数字信号,转换后的数据可以输出为人所认知的数据。
DMA(直接内存访问)
减少了CPU参与数据传输的时间,可以实现从外设到内存、内存到外设、外设到外设、内存到内存这四种方式的数据传输。
这次总结还是存在很多不足,朋友们要是发现什么问题提醒我,还需共勉.
标签:总结,操作数,addr,第一,STM32,单片机,指令,寄存器,操作 From: https://blog.csdn.net/weixin_72755055/article/details/145153997