学习单片机,不管怎么学都是要走一些弯路的,有的人弯路走得多,有多人弯路走得少,有些人中途就放弃了,也有不少人成功上岸,掌握了各式各样的单片机、处理器。用51单片机来学习是最合适不过的,因为它的结构不复杂,该有的东西也都有,学会了它,再学习其他的单片机就简单多了。很多人会使用单片机来点亮LED、数码管,能使用单片机进行串口通讯,能用单片机进行各种传感器和驱动器,就觉得已经精通了。其实这还远远不够,换个单片机又要学习很久,换个处理器更是两眼一黑,真正学会单片机是要搞清楚单片机的内部构架和原理,这样你就可以一招鲜吃遍天了,因为不管是51构架的单片机、还是Cortex-M系列的单片机、或者手机上使用Cortex-A系列的处理器、以及PC上使用的处理器,基本原理没有太大差异。就像房子,有摩天大厦、也有厂房、有公寓、有仓库、有商品房、有安置房、有别墅、有厕所,他们都是钢筋,水泥构成,有门,有窗,有房间,有大房间,小房间,有精装修,有毛坯装修,基本的东西是一样的,只是使用的差异不同而已。
单片机的英文全称Single-Chip Microcomputer,也叫单片微电脑,想想电脑的主要构成(CPU、内存、硬盘、主板),那单片机就是把CPU、内存、硬盘、主板集成在一个芯片上,CPU还是CPU、内存就是RAM、硬盘就是ROM(单片机的ROM也叫Flash)、主板就是单片机上各种总线连接。电脑还可以提供一些外部的接口,比如鼠标、键盘、显示器、各种USB接口,单片机也可以提供各种外部接口,就是那些GPIO,有些GPIO有特殊的功能,比如UART、SPI、IIC等。
所以单片机的结构可以是下面这样子。CPU通过总线与ROM、RAM、GPIO进行信息交互。
CPU:是单片机运行的核心部分,负责执行程序指令,数据处理,控制各个外设。
解码指令和执行指令:CPU从程序存储器(Flash)中读取指令,对指令进行解码,并执行;
控制数据流:CPU负责控制数据在内部总线上的流动,以及将数据传递给内部寄存器和外设
管理中断:CPU能够检测到外部中断信号,并根据优先级处理中断请求;
控制时序和时钟:CPU需要根据时钟信号来同步各个部件的操作,来确保系统的正常运行
处理输入输出操作:CPU可以通过输入输出端口与外部设备进行通信,实现对外设的控制和数据交换。
ROM:51单片机的ROM是用来存储代码和常量数据,包括程序指令、常量、变量的初值、固定的数据表等。在51单片机中ROM是不可写的,只能烧录。单片机上电后,程序代码和常量数据会ROM中被加载到RAM中运行。
RAM:51单片机的RAM是用来存储程序和数据的临时存储器,RAM分内部RAM和外部RAM,内部RAM位于芯片内部,主要用于存储程序运行时所需的变量和数据、堆、栈等,内部RAM一般比较小,128字节、256字节等。外部RAM则需要通过外部接口连接到芯片上,可以扩展单片机的存储空间,外部RAM的大小一般在几K字节到几十K字节之间
GPIO:51单片机的GPIO(通用输入输出口),是最基本的IO口,可以通过编程实现对外部设备的控制和数据的输入输出。常见的应用包括LED灯的控制、蜂鸣器控制、按键检测、数码管显示、LCD显示等。
51单片机的CPU主要由这几部分组成:ALU、特殊功能寄存器、指令寄存器、指令译码器、程序计数器(PC)、时钟电路。
ALU(算术逻辑单元):ALU是处理CPU中所有算术和逻辑运算的核心部件,它包括加法器、逻辑门、移位器等。
特殊功能寄存器:
程序计数器(PC):程序计数器是一个16位的寄存器,用于存储下一条指令的地址。当51单片机执行一条指令时,PC寄存器会根据指令的长度自动+1或者+2,以便指向下一条指令的地址当遇到跳转指令的时候PC寄存器的值会被直接修改为要跳转的地址。
指令寄存器(IR):指令寄存器是专门用来存储当前执行的指令的寄存器,当51单片机执行指令时,指令从程序存储器读取到指令缓冲区,在被传送到指令寄存器中。在指令寄存器中,指令被分解成操作码和操作数,然后被送到指令译码器中进行译码,最终执行相应的操作。
指令译码器(ID):用于将指令寄存器中的指令解码成相应的操作,并控制相应的执行大暖完成指令的执行。在51单片机中,指令译码器通常由微指令控制器和微程序存储器组成,主要工作时将操作码和操作数等信息解码成微指令,并将微指令送到执行单元,从而实现指令的执行。
时钟电路:给CPU提供时钟信号
51单片机的ROM分位3个区域:代码区、数据区、扩展区
代码区:也称为程序区,用于存放代码,是程序的主要部分。代码区的大小由ROM的容量决定,一般有4KB、8KB、16KB;
数据区:用于存放常量
扩展区:用于存放可以被访问的区域
STC89C52系列单片机的RAM分两部分,一部分是内部RAM(256字节),一部分是内部扩展RAM,大小要看手册。
内部的256字节RAM,地址范围是0x00--0xFF,
256字节的RAM又分低128字节内部RAM(0x00--0x7F)和高128字节内部RAM(0x80--0xFF);
这个低128字节的RAM既可以直接寻址,也可间接寻址;
高128字节RAM与特殊功能寄存器的地址范围是一样的,都是0x80--0xFF,看起来是一样的,实际上不一样,因为他们的寻址方式不一样高128字节的RAM只能间接寻址,特殊功能寄存器只能直接寻址,怎么理解,就拿高考来比喻吧,就像河南的高考成绩和北京的高考成绩,同样都是500分,北京的可以上985,河南的只能去上专科,因为他们的录取系统不一样,也就是寻址方式不一样。
低128字节RAM也称通用RAM区,是使用的最频繁的RAM区。
RAM区又可分为:
工作寄存器组区:地址从00H--1FH,工32个字节,分位4组,每组包含8个8位的工作寄存器,编号都是R0--R7,提供4个寄存器组是因为1个寄存器组可能还不够用,可通过程序状态字寄存器PSW中的RS1和RS0组合决定使用那个工作寄存器组
可位寻址区:地址20H--2FH,共16个字节,所谓可位寻址指的是可以一个BIT一个BIT的读写
用户RAM区和堆栈区:地址30--FF,一个8位的堆栈指针(SP),用于指向堆栈区,单片机复位后,堆栈指针SP为07H,指向了工作寄存器组0中的R7,因此用户初始化程序都应对SP设置初值,一般都是在在80H以后得单元,也就是设置在低128字节的RAM区,
51单片机的特殊功能寄存器包括以下几个,地址空间分布在0x80--0xFF:
1、P0、P1、P2、P3:端口寄存器,用于控制芯片的输入输出状态;
2、ACC:累加器寄存器,用于存储运算结果、或者数据传输;
3、B:B寄存器,用于存储运算的第二个操作数;
4、PSW:程序状态字寄存器,用于存储程序执行的状态信息,包括标志位、进位等;
5、SP:堆栈指针寄存器,用于存储堆栈的地址;
6、DPL、DPH:数据指针寄存器,用于存储数据的地址;
7、IE、IP中断使能和中断优先级寄存器,用于控制中断的使能和优先级;
8、TMOD、TCON、TH0、TL0、TH1、TL1:定时器/计数器模式寄存器,计数器寄存器,用于定时器和计数器的控制;
9、SCON、SBUF:串口控制寄存器和数据缓冲寄存器,用于串口通信的控制和数据传输;
10、其他系列的单片机也会根据功能扩展对应的寄存器,如ADC、 PCA
常规51单片机特殊功能寄存器的地址分配如下所示
STC89C52RC的特殊功能寄存器和地址分布可以从提供的头文件中查找
sfr XICON = 0xc0;
sfr WDT_CONTR = 0xe1;
sfr ISP_DATA = 0xe2;
sfr ISP_ADDRH = 0xe3;
sfr ISP_ADDRL = 0xe4;
sfr ISP_CMD = 0xe5;
sfr ISP_TRIG = 0xe6;
sfr ISP_CONTR = 0xe7;
sfr P0 = 0x80;
sfr P1 = 0x90;
sfr P2 = 0xA0;
sfr P3 = 0xB0;
sfr P4 = 0xe8; //STC自己扩展了P4端口,标准的51单片机是只有P0,P1, P2, P3端口
sfr PSW = 0xD0;
sfr ACC = 0xE0;
sfr B = 0xF0;
sfr SP = 0x81;
sfr DPL = 0x82;
sfr DPH = 0x83;
sfr PCON = 0x87;
sfr TCON = 0x88;
sfr TMOD = 0x89;
sfr TL0 = 0x8A;
sfr TL1 = 0x8B;
sfr TH0 = 0x8C;
sfr TH1 = 0x8D;
sfr IE = 0xA8;
sfr IP = 0xB8;
sfr SCON = 0x98;
sfr SBUF = 0x99;
/* STC自己扩展的寄存器 */
sfr AUXR = 0x8E;
sfr AUXR1 = 0xA2;
sfr SADDR = 0xA9;
sfr IPH = 0xB7;
sfr SADEN = 0xB9;
sfr T2CON = 0xC8;
sfr T2MOD = 0xC9;
sfr RCAP2L = 0xCA;
sfr RCAP2H = 0xCB;
sfr TL2 = 0xCC;
sfr TH2 = 0xCD;
下面的图是从STC的官方手册中截下来的STC89C51架构,该包含的模块都包含进去了
TMP寄存器和ACC寄存器都是累加器寄存器,但是他们的用途不一样。
TMP寄存器是一个临时寄存器,用于存储计算过程中的临时结果,比如计算的中间结果、或者一些运算的临时存储。TMP寄存器不是一个通用的寄存器,所以它不能直接访问。
ACC寄存器是累加器寄存器,就不一样了,它是一个通用的寄存器,可以被程序直接访问,ACC是可以存储加减乘除,移位等运算的结果,也可以用于存储数据和地址。
地址生成器指的是内部存储器地址的生成电路,这个电路由几个寄存器和逻辑门构成。地址生成电路通过以下几个步骤来生成内部存储器的地址:
1、程序计数器(PC)指向下一条要执行的指令的地址;
2、指令寄存器(IR)读取PC指向的指令;
3、根据指令的操作码,去顶指令的长度;
4、PC的值加上指令的长度,得到下一条指令的地址;
对于数据存储器,可以使用数据寄存器(DPTR)来生成地址,这个数据寄存器就是双数据指针。
51单片机的取指令步骤:
1、将程序计数器(PC)的值送到地址总线,使得程序计数器中存储的地址作为地址总线的地址;
2、将程序计数器中存储的地址送入程序存储器的地址端口,从而选中相应的存储单元;
3、从程序存储器中读取指令,并将指令送入数据总线;
4、将指令从数据总线送到指令寄存器;
5、将程序计数器+1,指向下一条指令;
6、重复上面的过程,直到程序执行结束
51单片机的程序经过编译器编译成单片机可执行的文件,比如hex格式的文件或者bin格式的文件;
使用烧录器将可执行文件烧录(下载)到单片机的Flash中,也就是ROM中;
上电后,51单片机CPU从Flash的地址0开始读取指令;
根据指令对寄存器、内存进行读写操作;
51单片机在main函数之前的操作
其实单片机上电之后并不是直接进行main函数里面的各种操作指令,在进入main函数之前还有一些初始化的操作,包括:
1、清除所有的RAM变量,初始化所有的寄存器,设置所有的IO口为默认状态;
2、使能中断,初始化中断向量表,设置中断优先级;
3、配置系统的时钟;
4、初始化各种外设;
5、初始化堆栈指针;
这些初始化的操作一般是由编译器或者开发环境提供的启动代码完成的。
在特殊功能寄存器中有一个堆栈指针寄存器(SP),它用于指向堆栈顶部的地址。当程序执行中遇到CALL指令、中断时,会将程序计数器(PC)的值压入堆栈中,并将SP寄存器的值-1,指向堆栈的下一个可用地址。返回时,会从堆栈中取出压入的PC值,并将SP寄存器的值+1,指向堆栈的顶部。
堆栈,英文stack,一般翻译成栈,因为堆和栈还是有一定区别的,在计算机中,堆和栈都是内存的一部分,栈一般是CPU自己分配,而堆需要程序员自己去申请,自己去释放。
在51单片机中,堆栈(stack)用来保存上下文。当中断发生时,会将当前的程序计数器(PC)、状态寄存器(PSW)、以及其他通用寄存器中的值都保存在堆栈中。当中断服务程序结束之后,又把堆栈中的内容读出来。
使用堆栈保存上下文,需要注意以下几点:
1、确保堆栈的大小足够保存所有的需要保存的寄存器的值;
2、在进入中断前,需要禁止其他中断的发生,以防止在中断服务程序执行的过程中发生其他的中断,从而破坏堆栈中保存的值;
3、在退出中断服务程序后,需要重新开启中断,以便能够响应其他的中断请求;
4、当使用多重嵌套中断时,需要使用多个堆栈来保存不同中断的上下文。
51单片机的中断向量就是一组地址,这个地址就是单片机中存储程序指令的地址,
程序存储器就是Flash,他的地址从0x0000开始,按照代码量地址也逐渐增加,但是有一些特殊的地址位置,一般的程序指令是不能占用的,这些特殊的位置就是中断向量,一旦中断发生,程序计数器(PC)直接就跳转到对应的中断向量地址,开始执行中断服务。
常规的51单片机有以下几个中断向量
STC单片机自己扩充了几个其他的中断,用到的时候自己可以去查一下手册。一般中断向量的地址是位于程序存储器的0x0000--0x003F这段地址范围内。
在程序开发过程中,我们可以通过特定的指令将中断服务子程序的入口地址写入中断向量地址中,当发生对应的中断事件时,CPU会根据中断向量中存储的入口地址跳转到对应的中断服务子程序。