什么是寄存器

在点亮 LED 的时候,我们都是用操作寄存器的方法来实现的,那大家是否想过,这个

寄存器到底是什么?为什么我们可以直接操作 P0 口?

解答上面的问题之前,我们先简单介绍下 51 单片机的主要组成部分,这对我们学习其

他单片机也有好处。

我们以国内的 STC89C51 为例,该单片机主要由 51 内核、外设 IP、和总线这三大部分

组成。内核是由 Intel 公司生产的,外设 IP 就是 STC 公司在内核的基础上添加的诸如定时

器、串口、IO 口等这些东西,总线就是用来连接内核和外设的接口单元。Intel 在这里属于

IP 核设计公司,STC 属于 IC 设计公司。世界上能设计 IP 核的公司屈指可数。我们非常熟

悉的 ARM 公司就属于 IP 核设计公司,ARM 给其他公司授权,其他 IC 公司就在 ARM 内

核上设计出各具特色的 MCU,我们后面要学习的 STM32 就是属于一中基于 ARM 内核的

MCU。

寄存器则是内置于各个 IP 外设中,是一种用于配置外设功能的存储器,就是一种内

存,并且有想对应的地址。学过 C 语言我们就知道,要操作这些内存就可以使用 C 语言中

的指针,通过寻址的方式来操作这些具有特殊功能的内存—寄存器。比如 P0 口对应的地址

是 0X80,那么我们要修改 0X80 这个地址对应的内存的内容的话,按照常理可以这样操

作:

1 *(*0X80)= 0XFE; // 点亮 LED

可当我们编译的时候,编译器会报错,在 51 里面只能通过 SFR 和 SBIT 这两个关键字

来实现寄存器映像,不能直接操作寄存器对应的地址,这是 51 相较于 STM32 不同的地

方。

51 单片机的这些寄存器位于地址 80H~FFH 中,对应着 128 个地址,但不是每个地址

都是有效的,51 系列的单片机有 21 个,52 系列的则有 26 个,其他的都是保留区。

   寄存器映射

实际上我们在编程的时候并不是通过指针来操作寄存器的,而是直接给 P0、P1 这些

端口寄存器赋值。那么这些外设资源是如何与地址建立一一对应的关系(寄存器映射定

义),这得益与 51 特有的两个关键字:SFR 和 sbit,其他单片机没有,只能用其他的方式

来实现寄存器映射。这两个关键字帮我们实现了所有寄存器的定义,所以我们才可以像操

作普通变量一个来操作寄存器。其实我们一开始提到的点亮 LED 的代码,全貌应该是这样

的:

1 sfr P0 = 0x80; // 寄存器定义

2 P0 = 0XFE; // 总线操作点亮 LED

为了方便起见,我们可以把寄存器映射全部写好封装在一个头文件里面,不用每用一

个寄存器就定义一次。其实这方面的工作不用我们做,我们在编程的时候都会在开始的地

方添加一个头文件:

1 #include <reg51.h>《零死角玩转 STM32》— F1 系列

第 10 页 共 53 页

这个头文件已经实现了全部寄存器的定义,该文件是 keil 自带,在安装目录:

Keil\C51\INC 下可以找到。这个文件实现了字节寄存器和位寄存器的定义。

   启动文件—STARTUP.A51

还有一个就是启动代码,这个也是很多初学者容易忽略的地方,对于这部分我们主要

总结下它的功能,不详解讲解里面的代码。

单片机在上电复位后,首先执行的是启动文件—STARTUP.A51,而不是我们通常看到

的 main 函数。我们新建 51 工程的时候会有一个提示:是否拷贝启动代码到当前的工程,

我们一般选择是。

启动代码用汇编语言编写,主要实现了以下功能:清除内部数据存储器、清除外部数

据存储器、清除外部页储存器、初始化 small 模式下的可重入栈和指针、初始化 large 模式

下可重入栈和指针、初始化 compact 模式下的可重入栈和指针、初始化 8051 硬件栈指针、《零死角玩转 STM32》— F1 系列

第 12 页 共 53 页

传递初始化全局变量的控制命令或者在没有初始化全局变量时给 main 函数传递命令。然后

程序就跳转到 main 函数,来到我们熟知的 C 世界。

  总结

在讲解用 51 点亮 LED 的时候,我们补充了什么是寄存器、寄存器映射、启动代码这

三部分的内容,这三部分内容本来是放到 STM32 里面讲解的,但考虑到大家已经有 51 的

基础,并且对 51 比较熟悉,那我再添加点内容,大家自然没有那么抗拒,并且可以根据上

面讲的内容亲自实践,学习得也会更深入。那当我再在 STM32 讲解这几个内容的时候,大

家就会对比着学习,对 STM32 也就没有那么忌惮。