我要成为嵌入式高手之4月10日51单片机第五天!!
————————————————————————————
单片机最小系统板:
单片机内部的CPU:
CPU定义的变量都在ram中、编写的程序代码都在rom中
CPU在次细化:kernal内核和外设
如GPIO、串口通信都是操作外设,而程序其实是在运行在kernal里,51单片机的内核称为8051,arm的内核称为arm。
因此先学习arm内核编程,使用芯片为S3c2440
ARM内核
ALU:算数逻辑单元
(以下寄存器c语言访问不到,故应该用汇编)
r0 ~ r12:通用寄存器,不可被寻址(当做变量,用来存放操作数)
pc(program counter)程序计数器:本质是个指针,指向当前执行指令的下一条指令
①pc取指令
②将取到的指令翻译成CPU能够运行的指令:译码
③执行
好处:容易实现函数的跳转
lr(link register)链接寄存器:存储函数跳变前指令的地址,以供返回(相当于保护现场)
sp:栈指针寄存器
目的:在c语言运行之前把sp指针指出来
Cache高速缓存寄存器:比一般寄存器读写速度快
ICache:指令
DCache:数据
MMU内存管理单元:有MMU可以运行操作系统
AHB:先进的高速外设总线(ram,usb等高速设备)
APB:低速总线设备(uart,gpio,timer等低速设备)
s3c2440(32位处理器) 使用的架构是ARM920t架构,使用的指令集为ARMV5TE
ARM最小系统
半导体器件
TTL:输入高电平>2.4V,输出低电平<0.4V
CMOS:1逻辑电平电压接近于电源电压,0逻辑电平接近于0,而且具有很宽的噪声容限
二极管:半导体二极管是在一个PN结的两侧,各引出一根金属电极,并用外壳封装起来而构成的。由P区引出的电极称为阳极,由N区引出的电极称为阴极。
三极管:半导体三极管也成为晶体三极管,最主要的作用是电流放大和开关作用。基极(b),集电极(c),发射极(e)
MOS管(场效应管):场效应晶体管FET(Field Effect Transistor),由多数载流子参与导电,也称为单极型晶体管。
存储器的分类
存储器是指保存数组的硬件单元。广义的分类可简单的分为易失性存储器和非易失性存储器两类:
易失性存储器是指掉电后数据就丢失了的存储器,最常见 的就是ram;
非易失性存储器是指掉电后数组不会丢失的存储器,最常见 的就是rom。
ram种类:
rom种类:
nor flash(或非)可以被寻址 nand flash(与非)不可被寻址
ARM指令集
1、ARM采用的是32位架构
2、ARM约定:
Byte:8位
Halfword:16位(2字节)
Word:32位(4字节)
Doubleword:64位(8字节)(Cortex-A处理器)
3、大部分ARM core提供:
ARM指令集(32位)
Thumb指令集(16位)
字节顺序
默认小端存储
ARM寄存器
一、ARM有37个32位长的寄存器
1个用作PC
1个用作CPSR
5个用作SPSR
30个通用寄存器
二、Cortex体系下有40个32位长寄存器
ARM的七种工作模式
User:非特权模式,大部分任务执行在这种模式
FIQ:当一个高优先级(fast)中断产生时将会进入这种模式
IRQ:当一个低优先级(normal)中断产生时将会进入这种模式
Supervistor:当复位或软中断执行指令时将会进入这种模式
Abort:当存取异常时将会进入这种模式
Undef:当执行未定义指令时会进入这种模式
System:使用和User模式相同寄存器集的特权模式
下面的cpsr 和 spsr 寄存器:
一个cpsr、五个spsr
psr寄存器:
程序状态寄存器
cpsr:当前程序状态寄存器
spsr:备份被打断那一瞬间的cpsr(保护现场)
下面为如何设置arm的工作模式:
N Z C V位会根据之前运算结果来回发生变化
异常处理
由于异常向量表中元素地址都是固定的,故在c程序执行之前需要进行异常向量表初始化
ARM汇编指令
ARM汇编主要目的是为了编写ARM启动代码,启动代码启动后,引导程序到c语言环境下运行。
1、初始化异常向量表
2、初始化各工作模式的栈指针寄存器
3、开启arm内核中断允许
4、将工作模式设置为user模式
5、完成上述工作后,引导程序进入c语言主函数执行
如何判断立即数
- 如果某个数的数值范围是0~255之间,那么这个数一定是立即数;
- 把某个数展开成2进制,这个数的最高位1至最低位1之间的二进制数序列的位数不能超过8位;
- 这个数的二进制序列的右边必须为偶数个连续的 0
mov指令:
加载12位立即数到寄存器或转移一个寄存器的值到另外一个寄存器
mov r0, #2 :加载立即数2到寄存器r0,MOV{S}<c> <Rd>, #<const>
mov r1, r0 :将r0寄存器的值加载到r1,MOV{S}<c> <Rd>, <Rm>
大多数指令的格式为opcode rd, rn ,其中,rd是目标寄存器,rn是第一操作数寄存器。
移位指令
ASR:算数右移
LSL:逻辑左移
ROR:循环右移
sub指令:
SUB{S}<c> <Rd>, <Rn>, #<const>:将寄存器Rn的值减const之后存储到寄存器Rd
SUB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}:寄存器Rn减寄存器Rm的值,减完存储到寄存器Rd
orr指令:
orr指定位置1:ORR{S}<c> <Rd>, <Rn>, #<const>:按位或,Rn与常量const或,或的结果保存到Rd里
bic指令:
bic指定位清零:BIC{S}<c> <Rd>, <Rn>, #<const>:将Rn中的字数据const为1的比特清零,把结果放入rd
mvn指令:
若一个数取反是立即数,就可以用mvn存储到寄存器中
ldr指令:
ldr寄存器加载指令:
LDR{<c>}{<q>} <Rt>, <label> ;如ldr r0, =0x2FAB45
ldr指令多用于从ram中将一个32位的字数据传送到目的寄存器中
LDR<c> <Rt>, [<Rn>{, #+/-<imm12>}] 如:
LDR R0,[R1,#8];
将内存地址为R1+8的字数据读入寄存器R0,这里的#8作为12位立即数是可以省略的
LDR<c> <Rt>, [<Rn>], #+/-<imm12> 如:
ldr r0, [r1], #8 ;
将内存地址R1的字数据读入r0,之后r1+8
LDR<c> <Rt>, [<Rn>, #+/-<imm12>]! 如:
LDR R0,[R1,#8] !;
将存储器地址为R1+8的字数据读入寄存器R0,并将新地址R1+8写入R1。
汇编指令的s后缀
几乎所有的汇编指令都可以在指令后面加上s后缀,s后缀的含义是在指令执行过程中会更新cpsr寄存器的N,V,C,Z位(类似于一种标记,表明上一次计算的结果有何特点)
N:在结果是有符号的二进制补码情况下,如果结果为负数,则N=1;如果结果为非负数,则N=0
Z:如果结果为0,则Z=1;如果结果为非零,则Z=0
C:是针对无符号数最高有效位向更高位进位时C=1;减法中运算结果的最高有效位从更高位借位时C=0
V:该位是针对有符号数的操作,会在下面两种情形变为1,两个最高有效位均为0的数相加,得到的结果最高有效位为1;两个最高有效位均为1的数相加,得到的结果最高有效位为0;除了这两种情况以外V位为0(例如有符号数整型溢出)
汇编指令的c后缀
cmp指令:
cmp r0, r1:第一操作数(r0)与第二操作数(r1)进行减法运算,该运算会产生NZCV标志改变,运算之后可以加c后缀进行下一步运算
相当于运算条件
练习:假设有三个变量R0=10,R1=20,R2=15,找出最大值装入R3寄存器