Embedded Systems 简明教程
Embedded Systems - Overview
System
系统是一组按照规则一起工作的单元的排列。也可以被定义为按照固定计划工作、组织或做一项或多项任务的方式。例如,手表是一个显示时间的系统。它的组件遵循一套规则来显示时间。如果其中一个部件发生故障,手表将停止工作。因此,我们可以说,在一个系统中,它的所有子组件相互依赖。
Embedded System
如其名称所示,嵌入式是指附加到另一事物上的东西。可以将嵌入式系统视为具有嵌入式软件的计算机硬件系统。嵌入式系统可以是一个独立的系统,也可以是大型系统的一部分。嵌入式系统是基于微控制器或微处理器的系统,旨在执行特定任务。例如,火灾报警器是一个嵌入式系统;它只感知烟雾。
嵌入式系统有三个组件:
-
It has hardware.
-
It has application software.
-
它有实时操作系统(RTOS),负责监督应用程序软件并通过按照计划控制等待时间来提供机制,让处理器运行一个进程。RTOS 定义了系统工作方式。它在执行应用程序期间设置规则。小型嵌入式系统可能没有 RTOS。
因此,我们可以将嵌入式系统定义为基于微控制器、软件驱动、可靠、实时的控制系统。
Characteristics of an Embedded System
-
Single-functioned − 嵌入式系统通常执行一项专门操作并且重复执行相同的操作。例如:寻呼机始终用作寻呼机。
-
Tightly constrained − 所有计算系统在设计度量方面都有限制,但嵌入式系统的度量尤其严格。设计度量是其实现的特性(如其成本、尺寸、功率和性能)的度量标准。它必须足够小以适合单个芯片,必须执行得足够快以实时处理数据,并且必须消耗最少的电力以延长电池寿命。
-
Reactive and Real time − 许多嵌入式系统必须持续对系统环境的变化做出反应,并且必须在没有任何延迟的情况下实时计算某些结果。考虑汽车巡航控制器的示例;它会持续监控速度和制动传感器并对它们做出反应。它必须在有限的时间内重复计算加速或减速;延迟计算会导致无法控制汽车。
-
Microprocessors based − 它必须基于微处理器或微控制器。
-
Memory − 它必须具有存储器,因为它的软件通常嵌入在 ROM 中。它不需要计算机中的任何辅助存储器。
-
Connected − 它必须具有连接的外围设备以连接输入和输出设备。
-
HW-SW systems − 软件用于获得更多功能和灵活性。硬件用于性能和安全性。
Basic Structure of an Embedded System
下图显示了嵌入式系统的基本结构:
-
Sensor − 它测量物理量并将其转换为电信号,该信号可由观察者或任何电子仪器(如数模转换器)读取。传感器将测得的数量存储到存储器中。
-
A-D Converter − 模数转换器将传感器发送的模拟信号转换为数字信号。
-
Processor & ASICs − 处理器处理数据以测量输出并将其存储到存储器中。
-
D-A Converter − 数模转换器将处理器馈送的数字数据转换为模拟数据
-
Actuator − 执行器将 D-A 转换器给出的输出与存储在其中的实际(预期)输出进行比较,并将批准的输出存储起来。
Embedded Systems - Processors
处理器是一个嵌入式系统的核心。它是接收输入并处理数据后产生输出的基本单元。对于嵌入式系统设计人员而言,有必要了解微处理器和微控制器。
Processors in a System
一个处理器有两个基本单元:
-
程序流控制单元 (CU)
-
Execution Unit (EU)
CU 包含一个从内存中获取指令的获取单元。EU 有用于实现与数据传输操作和数据从一种形式转换到另一种形式有关的指令的电路。
EU 包含算术和逻辑单元 (ALU),还包含执行程序控制任务的指令的电路,例如中断,或跳至另一组指令。
一个处理器按从内存中获取的相同顺序运行获取循环并执行指令。
Types of Processors
处理器可以划分为以下类别:
-
通用处理器 (GPP) 微处理器 微控制器 嵌入式处理器 数字信号处理器 媒体处理器
-
特定用途系统处理器 (ASSP)
-
特定用途指令处理器 (ASIP)
-
特定用途集成电路 (ASIC) 或超大规模集成 (VLSI) 电路上的 GPP 核或 ASIP 核。
Microprocessor
微处理器是具有 CPU 的单个 VLSI 芯片。此外,它还可能具有其他单元,例如缓存、浮点处理算术单元和流水线单元,这些单元有助于更快地处理指令。
早期的微处理器取指执行周期由大约 1 MHz 的时钟频率控制。现在的处理器以 2GHz 的时钟频率工作
Microcontroller
微控制器是个单芯片 VLSI 单元(也称为 microcomputer ),虽然计算能力有限,但具备增强的输入/输出能力和许多片上功能单元。
CPU |
RAM |
ROM |
I/O Port |
Timer |
Serial COM Port |
微控制器尤其用于实时控制应用的嵌入式系统,具有片上程序内存和设备。
Microprocessor vs Microcontroller
下面我们来看一看微处理器和微控制器之间最显著的区别。
Microprocessor |
Microcontroller |
微处理器本质上是多任务的。可以一次执行多个任务。例如,在电脑上我们可以在文本编辑器中写文字时播放音乐。 |
单任务方向。例如,洗衣机仅设计用来洗衣服。 |
RAM、ROM、I/O 端口和计时器可以外部添加,数量可以变化。 |
RAM、ROM、I/O 端口和计时器不能外部添加。这些组件必须一起嵌入到芯片上,数量是固定的。 |
设计者可以决定所需的内存或 I/O 端口的数量。 |
固定数量的内存或 I/O 使得微控制器非常适合有限但具体的任务。 |
外部存储器和 I/O 端口的外部支持让基于微处理器的系统更笨重且更昂贵。 |
微控制器比微处理器更轻便且更便宜。 |
外部设备需要更多空间,并且功耗更高。 |
基于微控制器的系统耗电量低,占用空间小。 |
Embedded Systems - Architecture Types
8051 微控制器使用 8 位数据总线工作。所以它们最多能支持 64K 外部数据内存和 64k 外部程序内存。总的来说,8051 微控制器可寻址 128k 外部内存。
当数据和代码位于不同的存储器块中时,那么架构被称为 Harvard architecture 。当数据和代码位于同一个存储器块中时,那么架构被称为 Von Neumann architecture 。
Von Neumann Architecture
冯·诺伊曼架构最早由计算机科学家约翰·冯·诺依曼提出。在该架构中,一条数据路径或总线既负责指令又负责数据。结果,CPU 一次只能执行一项操作。它要么从内存中获取一条指令,要么对数据执行读/写操作。因此,指令获取和数据操作不能同时进行,同时共享一条公共总线。
冯·诺伊曼架构支持简单的硬件。它允许使用一个单一顺序存储器。当今的处理速度远远超过内存访问时间,并且我们采用了一种非常快速但容量较小的存储器(高速缓存),它位于处理器的本地。
Harvard Architecture
哈佛架构为指令和数据提供单独的存储和信号总线。该架构的数据存储完全包含在 CPU 中,并且无法将指令存储作为数据进行访问。使用内部数据总线,计算机为程序指令和数据分别设置存储器区域,从而允许同时访问指令和数据。
程序需要由操作员加载;处理器无法自行启动。在哈佛架构中,无需让这两个存储器共享属性。
Von-Neumann Architecture vs Harvard Architecture
以下几点将冯·诺伊曼架构与哈佛架构区分开来。
Von-Neumann Architecture |
Harvard Architecture |
单个内存由代码和数据共享。 |
代码和数据有独立的存储器。 |
处理器需要在不同的时钟周期中获取代码并在另一个时钟周期中获取数据。所以它需要两个时钟周期。 |
单个时钟周期足够了,因为单独的总线用于访问代码和数据。 |
速度更快,因此更省时。 |
速度较慢,因此更耗时。 |
Simple in design. |
Complex in design. |
CISC and RISC
CISC 是一种复杂指令集计算机。它是一台可以寻址大量指令的计算机。
在 20 世纪 80 年代初,计算机设计师建议计算机应该使用更少指令和简单的结构,以便它们可以在 CPU 内更快地执行而无需使用内存。此类计算机被归类为精简指令集计算机或 RISC。
CISC vs RISC
以下几点将 CISC 与 RISC 区分开来 −
CISC |
RISC |
更大的指令集。易于编程。 |
更小的指令集。难以编程。 |
编译器的设计更简单,考虑了更大的指令集。 |
Complex design of compiler. |
许多寻址模式导致复杂的指令格式。 |
很少有寻址模式,修复指令格式。 |
Instruction length is variable. |
Instruction length varies. |
每秒时钟周期高。 |
每秒时钟周期低。 |
Emphasis is on hardware. |
Emphasis is on software. |
控制单元使用微程序单元实现大型指令集。 |
每个指令都由硬件执行。 |
执行速度较慢,因为指令需要从内存中读取并由解码器单元解码。 |
执行速度较快,因为每个指令都由硬件执行。 |
Pipelining is not possible. |
可以将指令流水线化,考虑单时钟周期。 |
Embedded Systems - Tools & Peripherals
Compilers and Assemblers
Compiler
编译器是一个计算机程序(或一组程序),它将用编程语言(源语言)编写的源代码转换为另一种计算机语言(通常是二进制格式)。转换的最常见原因是创建可执行程序。“编译器”一词主要用于将源代码从高级程序语言翻译成低级语言(例如汇编语言或机器代码)的程序。
Debugging Tools in an Embedded System
调试是一个有条理的过程,用于查找和减少计算机程序或电子硬件块中的错误数量,以便其按预期工作。当子系统紧密耦合时,调试很困难,因为一个子系统中的一个小改动可能会在另一个子系统中产生错误。嵌入式系统中使用的调试工具在开发时间和调试功能方面差异很大。我们将在下面讨论以下调试工具:
-
Simulators
-
Microcontroller starter kits
-
Emulator
Microcontroller Starter Kit
微控制器入门套件包括:
-
Hardware board (Evaluation board)
-
In-system programmer
-
一些软件工具,如编译器、汇编器、链接器等。
-
有时,一个 IDE 和一个代码大小受限的编译器评估版本。
与模拟器相比,这些套件的一大优点是它们可在实时环境中工作,从而便于验证输入/输出功能。但是,入门套件完全足够,并且是最节省成本的开发简单微控制器项目的选项。
Emulators
仿真器是一个硬件套件或软件程序,或二者兼有,它在另一个与第一个不同的计算机系统(主机)中模拟一个计算机系统(来宾)的功能,从而模拟行为与真实系统(来宾)的行为非常相似。
模拟是指电子设备中的计算机程序模拟(仿效)另一个程序或设备的能力。模拟专注于重新创建一个原始计算机环境。仿真器有能力保持与数字对象真实性的更紧密连接。仿真器帮助用户在一个平台上的任何类型的应用程序或操作系统中工作,类似于软件在其原始环境中运行的方式。
Peripheral Devices in Embedded Systems
嵌入式系统通过其外围设备与外部世界通信,如下所示:
-
串行通信接口(SCI),如 RS-232、RS-422、RS-485 等。
-
同步串行通信接口,如 I2C、SPI、SSC 和 ESSI
-
Universal Serial Bus (USB)
-
多媒体卡(SD 卡、紧凑型闪存卡等)
-
网络,如以太网、LonWorks 等。
-
诸如 CAN-Bus、LIN-Bus、PROFIBUS 等现场总线。
-
诸如 PLL、捕获/比较和时间处理单元的集成器。
-
离散 I/O,也称为通用输入/输出 (GPIO)
-
模数/数模转换器 (ADC/DAC)
-
诸如 JTAG、ISP、ICSP、BDM 端口、BITP 和 DP9 端口的调试
Criteria for Choosing Microcontroller
在选择微处理器时,请确保它满足手头任务并具有成本效益。我们必须判断 8 位、16 位或 32 位微处理器能否最佳地处理任务的计算需求。此外,在选择微处理器时应牢记以下几点:
-
Speed − 微处理器可支持的最高速度是多少?
-
Packaging − 是 40 针 DIP(双列直插式封装)还是 QFP(四方扁平封装)?这一点在最终产品的空间、组装和样机试制方面很重要。
-
Power Consumption − 对于电池供电产品而言,这是一项重要的标准。
-
Amount of RAM and ROM 芯片上。
-
Count of I/O pins and Timers 芯片上。
-
Cost per Unit − 这一点对于使用该微处理器的产品的最终成本而言很重要。
此外,请确保您准备好该微处理器随附的工具,例如编译器、调试器和汇编器。最重要的是,您应从可靠的来源购买微处理器。
Embedded Systems - 8051 Microcontroller
Brief History of 8051
第一款微处理器 4004 是由英特尔公司发明的。 8085 和 8086 微处理器也是由英特尔发明的。1981 年,英特尔推出了一个称为 8051 的 8 位微控制器。它被称为 system on a chip 是因为它有 128 字节的 RAM、4K 字节的片上 ROM、两个定时器、一个串行端口和 4 个端口(8 位宽),所有这些都集成在一个芯片中。当它变得广受欢迎时,英特尔允许其他制造商制造和销售与 8051 代码兼容的不同版本的 8051。这意味着如果您针对一种版本的 8051 编写程序,它将无论制造商如何也在其他版本上运行。这导致了几个具有不同速度和片上 RAM 大小的版本。
8051 Flavors / Members
-
8052 microcontroller −8052 拥有 8051 微控制器的所有标准功能,以及额外的 128 字节 RAM 和一个额外的定时器。它还有 8K 字节的片上程序 ROM,而不是 4K 字节。
-
8031 microcontroller −这是 8051 系列的另一款成员。由于这款芯片具有 0K 字节的片上 ROM,因此通常被称为无 ROM 的 8051。您必须向其中添加外部 ROM 才能使用它,其中包含要提取和执行的程序。此程序可能高达 64K 字节。但在向 8031 添加外部 ROM 的过程中,它失去了 4 个端口中的 2 个端口。为了解决这个问题,我们可以向 8031 添加外部 I/O
Comparison between 8051 Family Members
下表比较了 8051、8052 和 8031 中可用的功能。
Feature |
8051 |
8052 |
8031 |
ROM(bytes) |
4K |
8K |
0K |
RAM(bytes) |
128 |
256 |
128 |
Timers |
2 |
3 |
2 |
I/O pins |
32 |
32 |
32 |
Serial port |
1 |
1 |
1 |
Interrupt sources |
6 |
8 |
6 |
Features of 8051 Microcontroller
8051 微控制器随以下功能捆绑提供 −
-
4KB 字节片内程序存储器 (ROM)
-
128 字节片内数据存储器 (RAM)
-
Four register banks
-
128 个用户定义软件标志
-
8-bit bidirectional data bus
-
16-bit unidirectional address bus
-
32 个通用寄存器,每个 8 位
-
16 位定时器(通常为 2 个,但这可能更多或更少)
-
三个内部和两个外部中断
-
四个 8 位端口(精简模型有两个 8 位端口)
-
16 位程序计数器和数据指针
-
8031 可能还有许多特殊功能,如 UART、ADC、运算放大器等。
Embedded System - I/O Programming
在 8051 中,I/O 操作使用四个端口和 40 个引脚完成。以下引脚图显示了 40 个引脚的详细信息。I/O 操作端口预留 32 个引脚,每个端口有 8 个引脚。其他 8 个引脚指定为 Vcc、GND、XTAL1、XTAL2、RST、EA(条形)、ALE/PROG(条形)和 PSEN(条形)。
它是 40 针 PDIP(塑料双列直插式封装)
Note - 在 DIP 封装中,你可以通过 IC 中间的切口识别第一个引脚和最后一个引脚。第一个引脚位于此切口标记的左侧,最后一个引脚(即本例中的第 40 个引脚)位于切口标记的右侧。
I/O Ports and their Functions
四个端口 P0、P1、P2 和 P3 各使用 8 个引脚,使其成为 8 位端口。复位后,所有端口都配置为输入,可立即用作输入端口。当第一个 0 写入端口时,它将变为输出。要重新配置它为输入,必须向端口发送 1。
Port 0 (Pin No 32 – Pin No 39)
它有 8 个引脚(32 到 39)。它可以用于输入或输出。与 P1、P2 和 P3 端口不同,我们通常将 P0 连接到 10K-ohm 上拉电阻,以便用作输入或输出端口,因为它是一个开漏输出。
它还指定为 AD0-AD7,允许它同时用作地址和数据。对于 8031(即无 ROM 芯片),当我们需要访问外部 ROM 时,P0 将同时用于地址和数据总线。ALE(引脚号 31)指示 P0 具有地址或数据。当 ALE = 0 时,它提供数据 D0-D7,但当 ALE = 1 时,它具有地址 A0-A7。如果没有外部存储器连接,则必须将 P0 外部连接到 10K-ohm 上拉电阻。
MOV A,#0FFH ;(comments: A=FFH(Hexadecimal i.e. A=1111 1111)
MOV P0,A ;(Port0 have 1's on every pin so that it works as Input)
Port 1 (Pin 1 through 8)
它是一个 8 位端口(第 1 至 8 个引脚),可以作为输入或输出使用。它不需要上拉电阻,因为它们已经内部连接。复位后,端口 1 配置为输入端口。以下代码可用于向端口 1 发送 55H 和 AAH 的交替值。
;Toggle all bits of continuously
MOV A,#55
BACK:
MOV P2,A
ACALL DELAY
CPL A ;complement(invert) reg. A
SJMP BACK
如果端口 1 配置为用作输出端口,那么要再次用作输入端口,请对它进行编程,方法是像以下代码一样向它的所有位写入 1。
;Toggle all bits of continuously
MOV A ,#0FFH ;A = FF hex
MOV P1,A ;Make P1 an input port
MOV A,P1 ;get data from P1
MOV R7,A ;save it in Reg R7
ACALL DELAY ;wait
MOV A,P1 ;get another data from P1
MOV R6,A ;save it in R6
ACALL DELAY ;wait
MOV A,P1 ;get another data from P1
MOV R5,A ;save it in R5
Port 2 (Pins 21 through 28)
端口 2 共占用 8 个引脚(第 21 至 28 个引脚),可用于输入和输出操作。就像 P1(端口 1)一样,P2 也不需要外部上拉电阻,因为它们已经内部连接。它必须与 P0 一起使用,以便为外部存储器提供 16 位地址。因此,它也指定为 (A0–A7),如引脚图所示。当 8051 连接到外部存储器时,它为 16 位地址的高 8 位提供路径,并且不能用作 I/O。复位后,端口 2 配置为输入端口。以下代码可用于向端口 2 发送 55H 和 AAH 的交替值。
;Toggle all bits of continuously
MOV A,#55
BACK:
MOV P2,A
ACALL DELAY
CPL A ; complement(invert) reg. A
SJMP BACK
如果端口 2 配置为用作输出端口,那么要再次用作输入端口,请对它进行编程,方法是像以下代码一样向它的所有位写入 1。
;Get a byte from P2 and send it to P1
MOV A,#0FFH ;A = FF hex
MOV P2,A ;make P2 an input port
BACK:
MOV A,P2 ;get data from P2
MOV P1,A ;send it to Port 1
SJMP BACK ;keep doing that
Port 3 (Pins 10 through 17)
它也是 8 位的,可以用作输入/输出。此端口提供一些非常重要的信号。P3.0 和 P3.1 分别是 RxD(接收器)和 TxD(发送器),并共同用于串行通信。P3.2 和 P3.3 引脚用于外部中断。P3.4 和 P3.5 分别用于计时器 T0 和 T1。P3.6 和 P3.7 是写(WR)和读(RD)引脚。这些是低电平有效引脚,这意味着当向它们提供 0 时它们将变为活动状态,并且它们用于向基于 8031 的系统中的外部 ROM 提供读写操作。
P3 Bit |
Function |
Pin |
P3.0 |
RxD |
10 |
P3.1 |
TxD |
11 |
P3.2 |
Complement of INT0 |
12 |
P3.3 |
INT1 |
13 |
P3.4 |
T0 |
14 |
P3.5 |
T1 |
15 |
P3.6 |
WR |
16 |
P3.7 |
Complement of RD |
17 |
Dual Role of Port 0 and Port 2
-
Dual role of Port 0 - 端口 0 也指定为 AD0–AD7,因为它可以同时用于数据和地址处理。在将 8051 连接到外部存储器时,端口 0 可以同时提供地址和数据。然后,8051 微控制器将输入复用为地址或数据,以节省引脚。
-
Dual role of Port 2 - 除了用作 I/O,端口 P2 还可用于与端口 0 一起为外部存储器提供 16 位地址总线。端口 P2 也指定为 (A8– A15),而端口 0 通过 A0–A7 提供低 8 位。换句话说,我们可以说当 8051 连接到外部存储器(ROM)时,最大可达 64 KB,这是通过 16 位地址总线实现的,因为我们知道 216 = 64 KB。Port2 用于 16 位地址的高 8 位,不能用于 I/O,这是寻址任何外部 ROM 程序代码的方式。
Hardware Connection of Pins
-
Vcc - 引脚 40 为芯片提供电源,其电压为 +5 V。
-
Gnd - 引脚 20 为参考接地。
-
XTAL1, XTAL2 (Pin no 18 & Pin no 19) - 8051 具有片内振荡器,但需要外部时钟才能运行。石英晶体连接在芯片的 XTAL1 和 XTAL2 引脚之间。此晶体还需要两个 30pF 的电容器来生成所需频率的信号。每个电容的一侧连接到接地。8051 IC 有多种速度,而这全都取决于石英晶体,例如,20 MHz 微控制器需要一个不超过 20 MHz 的频率的晶体。
-
RST (Pin No. 9) - 它是一个输入引脚和活动高引脚。在此引脚上施加高脉冲后,即 1,微控制器将重置并终止所有活动。此过程称为 Power-On Reset 。激活上电复位将导致寄存器中的所有值丢失。它将程序计数器设置为全 0。为了确保复位的有效输入,高脉冲必须在变低之前至少保持两个机器周期,这取决于电容值和它充电的速度。( Machine Cycle 是单个指令在执行中所需的最小频率量)。
-
EA or External Access (Pin No. 31) - 它是一个输入引脚。此引脚是一个活动低引脚;施加低脉冲后,它被激活。对于具有片内 ROM 的微控制器 (8051/52),EA (bar) 引脚连接到 Vcc。但在没有片内 ROM 的 8031 微控制器中,代码存储在外部 ROM 中,然后由微控制器提取。在这种情况下,我们必须将(引脚号 31)EA 连接到 Gnd 以表明程序代码存储在外部。
-
PSEN or Program store Enable (Pin No 29) - 这也是一个活动低引脚,即在施加低脉冲后它被激活。它是一个输出引脚,与 8031 基于(即 ROMLESS)系统中的 EA 引脚一起使用,以允许将程序代码存储在外部 ROM 中。
-
ALE or (Address Latch Enable) - 这是一个输出引脚,为活动高。它专门用于 8031 IC 以将其连接到外部存储器。它可以在决定 P0 引脚将用作地址总线还是数据总线时使用。当 ALE = 1 时,P0 引脚作为数据总线工作,而当 ALE = 0 时,P0 引脚作为地址总线工作。
I/O Ports and Bit Addressability
这是在编写 8051 代码时对 8051 使用最广泛的功能。有时我们只需要访问端口的 1 或 2 位,而不是整个 8 位。8051 提供了访问端口的各个位的能力。
在以单比特方式访问端口时,我们使用语法“SETB X. Y”,其中 X 是端口号 (0 到 3),Y 是数据位 D0-D7 的位号 (0 到 7),其中 D0 是 LSB,而 D7 是 MSB。例如,“SETB P1.5”设置端口 1 的高电平位 5。
以下代码展示了我们如何连续切换位 P1.2。
AGAIN:
SETB P1.2
ACALL DELAY
CLR P1.2
ACALL DELAY
SJMP AGAIN
Embedded Systems - Terms
Program Counter
程序计数器是一个 16 位或 32 位寄存器,其中包含要执行的下一条指令的地址。每次获取指令时,PC 会自动递增到下一个顺序内存位置。分支、跳转和中断操作会使用其他于下一个顺序位置的地址加载程序计数器。
激活上电复位将导致寄存器中的所有值丢失。这意味着上电复位后 PC(程序计数器)的值为 0,迫使 CPU 从 ROM 存储器位置 0000 获取第一个操作码。这意味着我们必须将第一个字节的上行码放在 ROM 位置 0000,因为这是 CPU 希望找到第一条指令的位置
Reset Vector
复位向量的意义在于它指向处理器包含固件的第一条指令的内存地址。没有复位向量,处理器将不知道从何处开始执行。上电复位后,处理器使用预定义的内存位置中的复位向量值为程序计数器 (PC) 加载。在 CPU08 架构中,它位于位置 $FFFE:$FFFF。
当复位向量不必要时,开发人员通常会认为理所当然,并且不会对其编程以生成最终映像。结果,处理器不会在最终产品上启动。这是在调试阶段发生的常见错误。
Stack Pointer
栈在RAM中实现,一个CPU寄存器用于访问它,称为SP(堆栈指针)寄存器。SP寄存器是8位寄存器,可以寻址范围为00h到FFh的存储器地址。最初,SP寄存器包含值07,指向位置08,作为8051为堆栈使用的第一个位置。
当CPU寄存器的内容存储在堆栈中时,称为PUSH操作。当堆栈的内容存储在CPU寄存器中时,称为POP操作。换句话说,将寄存器推送到堆栈中以保存它,并将其弹出堆栈以检索它。
Infinite Loop
无限循环或无穷循环可以标识为计算机程序中的一系列指令,由于以下原因,它们在循环中无限地执行−
-
没有终止条件的循环。
-
带有无法满足的终止条件的循环。
-
带有终止条件的循环导致循环重新开始。
此类无限循环通常会导致较旧的操作系统无响应,因为无限循环会消耗所有可用的处理器时间。等待用户输入的I/O操作也称为“无限循环”。计算机“冻结”的一个可能是无限循环;其他原因包括 deadlock 和 access violations 。
与PC不同,嵌入式系统从不“退出”应用程序。它们通过无限循环空闲,等待事件以中断的形式发生,或 pre-scheduled task 。为了节省电能,一些处理器进入特殊的 sleep 或 wait modes ,而不是通过无限循环空闲,但它们将在计时器或外部中断时退出此模式。
Embedded Systems - Assembly Language
汇编语言被开发用于为机器级代码指令提供 mnemonics 或符号。汇编语言程序由助记符组成,因此它们应该被翻译成机器代码。负责此转换的程序称为 assembler 。汇编语言通常被称为低级语言,因为它直接与CPU的内部结构一起工作。为了用汇编语言进行编程,程序员必须了解CPU的所有寄存器。
不同的编程语言,如C、C++、Java和各种其他语言,被称为高级语言,因为它们不处理CPU的内部细节。相反,汇编器用于将汇编语言程序翻译成机器代码(有时也称为 object code 或 opcode )。类似地,编译器将高级语言翻译成机器代码。例如,要编写C语言程序,必须使用C编译器将程序翻译成机器语言。
Structure of Assembly Language
汇编语言程序是一系列语句,它们要么是诸如ADD和MOV的汇编语言指令,要么是称为 directives 的语句。
instruction 告诉CPU要做什么,而 directive (也称为 pseudo-instructions )则向汇编器发出指令。例如,ADD和MOV指令是CPU运行的命令,而ORG和END是汇编器指令。当使用ORG指令时,汇编器将操作码放在存储器位置0,而END则指示源代码的末尾。程序语言指令包含以下四个字段−
[ label: ] mnemonics [ operands ] [;comment ]
方括号([ ])表示该字段是可选的。
-
label field 允许程序通过名称引用一行代码。标签字段不能超过一定数量的字符。
-
mnemonics 和 operands fields 一起执行程序的实际工作并完成任务。诸如ADD A, C和MOV C, #68之类的语句,其中ADD和MOV是助记符,它们生成操作码;“A, C”和“C, #68”是操作数。这两个字段可能包含指令。指令不会生成机器代码,并且仅供汇编器使用,而指令则被翻译成机器代码以供CPU执行。
1.0000 ORG 0H ;start (origin) at location 0
2 0000 7D25 MOV R5,#25H ;load 25H into R5
3.0002 7F34 MOV R7,#34H ;load 34H into R7
4.0004 7400 MOV A,#0 ;load 0 into A
5.0006 2D ADD A,R5 ;add contents of R5 to A
6.0007 2F ADD A,R7 ;add contents of R7 to A
7.0008 2412 ADD A,#12H ;add to A value 12 H
8.000A 80FE HERE: SJMP HERE ;stay in this loop
9.000C END ;end of asm source file
-
comment field 以分号开头,分号是注释指示符。
-
注意程序中的“HERE”标签。任何引用指令的标签后面都应跟冒号。
Assembling and Running an 8051 Program
在此,我们将讨论汇编语言的基本形式。创建、汇编和运行汇编语言程序的步骤如下:
-
首先,我们使用编辑器键入与上述程序类似的程序。诸如全 Microsoft 操作系统附带的 MS-DOS EDIT 程序的编辑器可以用来创建或编辑程序。编辑器必须能够生成 ASCII 文件。汇编器在下一步使用源文件的“asm”扩展名。
-
“asm”源文件包含步骤 1 中创建的程序代码。它被送入 8051 汇编器。然后,汇编器将汇编语言指令转换为机器代码指令,并生成一个 .obj file (对象文件)和一个 .lst file (列表文件)。它也称为 source file ,这就是某些汇编器需要此文件拥有“src”扩展名的原因。“lst”文件是可选的。它对程序非常有用,因为它会列出所有操作码和地址,以及汇编器检测到的错误。
-
汇编器需要名为 linking 的第三步。链接程序采用一个或多个对象文件,并生成带有“abs”扩展名的绝对对象文件。
-
接下来,“abs”文件被送入名为“OH”(对象到十六进制转换器)的程序,该程序创建带有“hex”扩展名的文件,此文件可以刻录到 ROM 中。
Data Type
8051 微控制器包含一个 8 位的单数据类型,每个寄存器的大小也都是 8 位。程序员必须将大于 8 位的数据(00 到 FFH,或十进制的 255)分解,以便 CPU 能够处理它。
DB (Define Byte)
DB 指令是汇编器中最广泛使用的数据指令。它用于定义 8 位数据。它还可用于定义十进制、二进制、十六进制或 ASCII 格式的数据。对于十进制,“D”位于十进制数字后是可选的,但对于“B”(二进制)和“Hl”(十六进制)来说,它则是必需的。
要指示 ASCII,只需将字符放在引号中(“这样”)。汇编器会自动为数字/字符生成 ASCII 代码。DB 指令是唯一可用于定义大于两个字符的 ASCII 字符串的指令;因此,它应用于所有 ASCII 数据定义。下面给出了一些 DB 示例:
ORG 500H
DATA1: DB 28 ;DECIMAL (1C in hex)
DATA2: DB 00110101B ;BINARY (35 in hex)
DATA3: DB 39H ;HEX
ORG 510H
DATA4: DB "2591" ;ASCII NUMBERS
ORG 520H
DATA6: DA "MY NAME IS Michael" ;ASCII CHARACTERS
可以在 ASCII 字符串周围使用单引号或双引号。DB 还用于在字节大小块中分配内存。
Assembler Directives
8051 的一些指令如下:
-
ORG (origin) − 原点指令用于指示地址的开头。它以十六进制或十进制格式获取数字。如果数字后提供了 H,则该数字将被视为十六进制,否则为十进制。汇编器将十进制数字转换为十六进制。
-
EQU (equate) − 它用于在不占据内存位置的情况下定义常量。EQU 将常量值与数据标签相关联,以便标签出现在程序中,其常量值将被替换为该标签。在执行指令“MOV R3, #COUNT”时,寄存器 R3 将加载值 25(注意 # 号)。使用 EQU 的优点是,程序员可以更改它一次,汇编器会更改它的所有出现;程序员不必搜索整个程序。
-
END directive − 它表示源 (asm) 文件的结尾。END 指令是程序的最后一行;汇编器会忽略 END 指令后的任何内容。
Embedded Systems - Registers
寄存器用在 CPU 中,以临时存储信息,这些信息可能是要处理的数据,或指向要获取的数据的地址。在 8051 中,有一种数据类型为 8 位,从 MSB(最高有效位)D7 到 LSB(最低有效位)D0。对于 8 位数据类型,任何大于 8 位的数据类型都必须在处理之前分解为 8 位块。
8051 中使用最广泛的寄存器有 A(累加器)、B、R0-R7、DPTR(数据指针)和 PC(程序计数器)。除 DPTR 和 PC 之外,所有这些寄存器都是 8 位的。
Storage Registers in 8051
我们将在此处讨论以下类型的存储寄存器 −
-
Accumulator
-
R register
-
B register
-
Data Pointer (DPTR)
-
Program Counter (PC)
-
Stack Pointer (SP)
Accumulator
累加器,寄存器 A,用于所有算术和逻辑运算。如果不存在累加器,则每次计算的结果(加法、乘法、移位等)都将存储到主存储器中。与累加器等寄存器相比,访问主存储器比访问寄存器更慢,这是因为用于大型主存储器的技术比用于寄存器的技术慢(但便宜)。
The "R" Registers
“R”寄存器是一组八个寄存器,即 R0、R1 至 R7。这些寄存器在许多操作中用作辅助或临时存储寄存器。考虑将 10 和 20 相加的示例。将变量 10 存储在累加器中,并将另一个变量 20 存储在(例如)寄存器 R4 中。要处理加法运算,请执行以下命令 −
ADD A,R4
执行此指令后,累加器将包含值 30。因此,“R”寄存器是非常重要的辅助或 helper registers 。如果没有这些“R”寄存器,累加器本身将不会非常有用。“R”寄存器用于临时存储值。
我们再举一个例子。我们将把 R1 和 R2 中的值相加,然后从结果中减去 R3 和 R4 的值。
MOV A,R3 ;Move the value of R3 into the accumulator
ADD A,R4 ;Add the value of R4
MOV R5,A ;Store the resulting value temporarily in R5
MOV A,R1 ;Move the value of R1 into the accumulator
ADD A,R2 ;Add the value of R2
SUBB A,R5 ;Subtract the value of R5 (which now contains R3 + R4)
如你所见,我们使用 R5 来临时保存 R3 和 R4 的总和。当然,这不是计算 (R1 + R2) – (R3 + R4) 最有效的方法,但它确实说明了使用“R”寄存器作为临时存储值的途径。
The "B" Register
“B”寄存器与累加器非常相似,因为它可以保存 8 位(1 字节)的值。“B”寄存器仅由两个 8051 指令使用: MUL AB 和 DIV AB 。为了快速轻松地将 A 乘以或除以另一个数字,你可以将另一个数字存储在“B”中并使用这两个指令。除了使用 MUL 和 DIV 指令之外,“B”寄存器通常用作另一个临时存储寄存器,很像第九个 R 寄存器。
The Data Pointer
数据指针 (DPTR) 是 8051 唯一可由用户访问的 16 位(2 字节)寄存器。累加器、R0–R7 寄存器和 B 寄存器是 1 字节值寄存器。DPTR 用于指向数据。它由 8051 使用,并使用 DPTR 指示的地址访问外部存储器。DPTR 是唯一可用的 16 位寄存器,通常用于存储 2 字节值。
The Program Counter
程序计数器 (PC) 是一个 2 字节地址,用于告诉 8051 在存储器中可以找到要执行的下一条指令。在 8051 初始化时,PC 从 0000h 开始,并在每次执行指令后递增。PC 并不总是递增 1。有些指令可能需要 2 或 3 个字节;在这种情况下,PC 将递增 2 或 3。
Branch, jump 和 interrupt 操作使用除下一个顺序位置之外的地址加载程序计数器。激活上电复位将导致寄存器中的所有值丢失。这意味着 PC 的值在复位时为 0,强制 CPU 从 ROM 位置 0000 获取第一个操作码。这意味着我们必须将第一个字节的命令放在 ROM 位置 0000,因为这是 CPU 期望找到第一条指令的位置。
The Stack Pointer (SP)
堆栈指针与除 DPTR 和 PC 之外的所有寄存器一样,都可以保存 8 位(1 字节)的值。堆栈指针指示从该位置移走堆栈中下一个值的位置。当一个值被压入堆栈时,SP 的值会递增,然后该值会存储在生成的存储器位置。当一个值从堆栈中弹出时,该值将从 SP 指示的存储器位置返回,然后递减 SP 的值。
此操作顺序很重要。当 8051 初始化时,SP 将初始化为 07h。如果同时将值压入堆栈,则该值将存储在内部 RAM 地址 08h,因为 8051 会首先递增 SP 的值(从 07h 到 08h),然后将压入的值存储在该存储器地址(08h)。SP 由 8051 通过六条指令直接修改:PUSH、POP、ACALL、LCALL、RET 和 RETI。
ROM Space in 8051
8051 的某些系列成员仅有 4K 字节的片上 ROM(例如 8751、AT8951);有些有 8K ROM,例如 AT89C52,还有一些系列成员有 32K 字节和 64K 字节的片上 ROM,例如 Dallas Semiconductor。需要记住的一点是,8051 系列的任何成员都无法访问超过 64K 字节的操作码,因为 8051 中的程序计数器是一个 16 位寄存器(0000 到 FFFF 地址)。
8051 内部程序 ROM 的第一个位置的地址为 0000H,而最后一个位置可能根据芯片上 ROM 的大小而不同。在 8051 系列成员中,AT8951 具有 $k 字节的片上 ROM,其存储器地址为 0000(第一个位置)到 0FFFH(最后一个位置)。
8051 Flag Bits and PSW Register
程序状态字 (PSW) 寄存器是一个 8 位寄存器,也称为 flag register 。它有 8 位宽,但只使用了 6 位。两个未使用的位是 user-defined flags 。四个标志被称为 conditional flags ,这意味着它们表示执行指令后产生的条件。这四种标志是 CY *(Carry), *AC (辅助进位)、 P (奇偶校验)和 OV (溢出)。位 RS0 和 RS1 用于更改寄存器组。下图显示了程序状态字寄存器。
PSW 寄存器包含反映 CPU 当前状态的状态位。
CY |
CA |
F0 |
RS1 |
RS0 |
OV |
- |
P |
CY |
PSW.7 |
Carry Flag |
AC |
PSW.6 |
Auxiliary Carry Flag |
F0 |
PSW.5 |
用户可用于一般用途的标志 0。 |
RS1 |
PSW.4 |
寄存器组选择器位 1 |
RS0 |
PSW.3 |
寄存器组选择器位 0 |
OV |
PSW.2 |
Overflow Flag |
- |
PSW.1 |
User definable FLAG |
P |
PSW.0 |
奇偶标志。由硬件在指令周期中设置/清除,以指明累加器中奇/偶数位的数量。 |
我们可以使用 RS0 和 RS1 位选择相应的寄存器组位。
RS1 |
RS2 |
Register Bank |
Address |
0 |
0 |
0 |
00H-07H |
0 |
1 |
1 |
08H-0FH |
1 |
0 |
2 |
10H-17H |
1 |
1 |
3 |
18H-1FH |
-
CY, the carry flag − 当 D7 位有进位时,此进位标志被设置(1)。它会在 8 位加法或减法运算后受到影响。它还可以通过指令直接重置为 1 或 0,例如“SETB C”和“CLR C”,其中“SETB”代表设置位进位,“CLR”代表清除进位。
-
AC, auxiliary carry flag − 如果在 ADD 或 SUB 运算期间从 D3 和 D4 进位,则设置 AC 位;否则,将清除该位。它用于执行二进制编码十进制算术的指令。
-
P, the parity flag − 奇偶标志仅表示累加器寄存器中的 1 的数量。如果 A 寄存器包含奇数个 1,则 P = 1;如果包含偶数个 1,则 P = 0。
-
OV, the overflow flag − 每当有符号数运算的结果太大,导致高位溢出到符号位时,就会设置此标志。它仅用于检测有符号算术运算中的错误。
Embedded Systems - Registers Bank/Stack
8051 微控制器总共拥有 128 字节的 RAM。我们将讨论如何分配这 128 字节的 RAM,并研究其作为堆栈和寄存器的用途。
RAM Memory Space Allocation in 8051
8051 中的 128 字节的 RAM 被分配了地址 00 至 7FH。它们可以直接作为内存位置进行访问,并被划分为三个不同的组,如下所示 −
-
从 00H 到 1FH 位置的 32 字节被预留给寄存器组和堆栈。
-
从 20H 到 2FH 位置的 16 字节被预留给按位寻址的读/写内存。
-
从 30H 到 7FH 位置的 80 字节用于读写存储;它被称为 scratch pad 。8051 程序员广泛使用这 80 个位置的 RAM 来存储数据和参数。
Register Banks in 8051
总共 32 字节的 RAM 被预留给寄存器组和堆栈。这 32 个字节被划分为四个寄存器组,其中每个组有 8 个寄存器,R0-R7。RAM 位置 0 到 7 被预留给 R0-R7 的组 0,其中 R0 是 RAM 位置 0,R1 是 RAM 位置 1,R2 是位置 2,依此类推,直到内存位置 7,属于组 0 的 R7。
第二个 R0-R7 寄存器组从 RAM 位置 08 开始,到位置 OFH。第三个 R0-R7 组从内存位置 10H 开始,到位置 17H。最后,RAM 位置 18H 到 1FH 被预留给第四个 R0-R7 组。
Default Register Bank
如果将 RAM 位置 00-1F 预留给四个寄存器组,那么在 8051 上电时,我们可以访问哪个寄存器组的 R0-R7?答案是寄存器组 0;即在对 8051 进行编程时,可以用名称 R0 到 R7 访问 RAM 位置 0 到 7。因为用名称(例如 R0 到 R7)引用这些 RAM 位置比用它们的内存位置容易得多。
How to Switch Register Banks
当 8051 上电时,寄存器组 0 是默认值。我们可以使用 PSW 寄存器切换到其他组。PSW 的 D4 和 D3 位用于选择所需的寄存器组,因为可以通过按位寻址指令 SETB 和 CLR 访问它们。例如,“SETB PSW.3”将设置 PSW.3 = 1 并选择组寄存器 1。
RS1 |
RS2 |
Bank Selected |
0 |
0 |
Bank0 |
0 |
1 |
Bank1 |
1 |
0 |
Bank2 |
1 |
1 |
Bank3 |
Stack and its Operations
How Stacks are Accessed
由于堆栈是一段 RAM,因此 CPU 内部有寄存器可以指向它。用于访问堆栈的寄存器称为堆栈指针寄存器。8051 中的堆栈指针是 8 位宽,它可以取 00 到 FFH 的值。当 8051 初始化时,SP 寄存器包含值 07H。这意味着 RAM 位置 08 是用于堆栈的第一个位置。将 CPU 寄存器存储在堆栈中的操作称为 PUSH ,将内容从堆栈获取回 CPU 寄存器称为 POP 。
Embedded Systems - Instructions
程序流程按顺序进行,从一条指令到下一条指令,除非执行了控制传递指令。汇编语言中的各种类型的控制传递指令包括条件或无条件跳转和调用指令。
Loop and Jump Instructions
Looping in the 8051
重复执行一系列指令的特定次数称为 loop 。指令 DJNZ reg, label 用于执行循环操作。在此指令中,寄存器减 1;如果不为零,则 8051 跳到由标签所引用的目标地址。
在循环开始前,用重复次数的计数器加载寄存器。在此指令中,寄存器减量和跳跃决策合并为一条指令。寄存器可以是 R0-R7 中的任何一个。计数器也可以是 RAM 位置。
Example
Multiply 25 by 10 using the technique of repeated addition.
Solution − 乘法可以通过多次相加乘数来实现,次数与乘数相同。例如,
25 * 10 = 250(FAH)
25 + 25 + 25 + 25 + 25 + 25 + 25 + 25 + 25 + 25 = 250
MOV A,#0 ;A = 0,clean ACC
MOV R2,#10 ; the multiplier is replaced in R2
Add A,#25 ;add the multiplicand to the ACC
AGAIN:DJNZ R2,
AGAIN:repeat until R2 = 0 (10 times)
MOV R5 , A ;save A in R5 ;R5 (FAH)
Drawback in 8051 − 使用指令 DJNZ Reg label 的循环操作仅限于 256 次迭代。如果未执行条件跳转,则执行跳转后的指令。
Looping inside a Loop
当我们在另一个循环内使用循环时,它被称为 nested loop 。当最大计数限制为 256 时,使用两个寄存器来保存计数。因此,我们使用这种方法来重复执行操作超过 256 次。
Example
编写一个程序 −
-
使用值 55H 加载累加器。
-
对 ACC 补码 700 次。
Solution − 由于 700 大于 255(任何寄存器的最大容量),因此使用两个寄存器来保存计数。以下代码展示如何对 R2 和 R3 这两个寄存器进行计数。
MOV A,#55H ;A = 55H
NEXT: MOV R3,#10 ;R3 the outer loop counter
AGAIN:MOV R2,#70 ;R2 the inner loop counter
CPL A ;complement
Other Conditional Jumps
下表列出了 8051 中使用的条件跳转 −
Instruction |
Action |
JZ |
如果 A = 0 则跳转 |
JNZ |
如果 A ≠ 0 则跳转 |
DJNZ |
减量并如果寄存器 ≠ 0 则跳转 |
CJNE A, data |
如果 A ≠ 数据则跳转 |
CJNE reg, #data |
如果字节 ≠ 数据则跳转 |
JC |
如果 CY = 1 则跳转 |
JNC |
如果 CY ≠ 1,则跳转 |
JB |
如果位 = 1,则跳转 |
JNB |
如果位 = 0,则跳转 |
JBC |
如果位 = 1,则跳转并清除位 |
-
JZ (jump if A = 0) − 在此指令中,检查累加器的内容。如果为零,则 8051 跳转到目标地址。JZ 指令仅可用于累加器,不适用于任何其他寄存器。
-
JNZ (jump if A is not equal to 0) − 在此指令中,检查累加器的内容是否不为零。如果不为零,则 8051 跳转到目标地址。
-
JNC (Jump if no carry, jumps if CY = 0) − 标志(或 PSW)寄存器中的进位标志位用于做出是否跳转的决定“JNC 标志”。CPU 查看进位标志以了解它是否被置位 (CY = 1)。如果未置位,则 CPU 开始从标签的地址获取和执行指令。如果 CY = 1,则它不会跳转,而是会执行 JNC 下面的下一条指令。
-
JC (Jump if carry, jumps if CY = 1) − 如果 CY = 1,则它跳转到目标地址。
-
JB (jump if bit is high)
-
JNB (jump if bit is low)
Note − 必须注意,所有条件跳转都是短跳转,即目标地址必须在程序计数器内容的 -128 到 +127 字节内。
Unconditional Jump Instructions
8051 中有两个无条件跳转 −
-
LJMP (long jump) − LJMP 是 3 字节指令,其中第一个字节表示操作码,第二个和第三个字节表示目标位置的 16 位地址。2 字节目标地址是为了允许跳转到从 0000 到 FFFFH 的任何内存位置。
-
SJMP (short jump) − 这是一条 2 字节指令,其中第一个字节是操作码,第二个字节是目标位置的相对地址。相对地址范围从 00H 到 FFH,分为正向和反向跳转;也就是说,相对于当前 PC(程序计数器)地址的 -128 到 +127 字节内存内。对于正向跳转,目标地址可以从当前 PC 的 127 字节空间内。对于反向跳转,目标地址可以从当前 PC 的 -128 字节内。
Calculating the Short Jump Address
所有条件跳转(JNC、JZ 和 DJNZ)都是短跳转,因为它们是 2 字节指令。在这些指令中,第一个字节表示操作码,第二个字节表示相对地址。目标地址始终相对于程序计数器的值。要计算目标地址,将第二个字节添加到紧跟在跳转之下的指令的 PC。看看下面给出的程序 −
Line PC Op-code Mnemonic Operand
1 0000 ORG 0000
2 0000 7800 MOV R0,#003
3 0002 7455 MOV A,#55H0
4 0004 6003 JZ NEXT
5 0006 08 INC R0
6 0007 04 AGAIN: INC A
7 0008 04 INC A
8 0009 2477 NEXT: ADD A, #77h
9 000B 5005 JNC OVER
10 000D E4 CLR A
11 000E F8 MOV R0, A
12 000F F9 MOV R1, A
13 0010 FA MOV R2, A
14 0011 FB MOV R3, A
15 0012 2B OVER: ADD A, R3
16 0013 50F2 JNC AGAIN
17 0015 80FE HERE: SJMP HERE
18 0017 END
CALL Instructions
CALL 用于调用子例程或方法。子例程用于执行需要频繁执行的操作或任务。这使程序更具结构性并节省了内存空间。有两个指令 − LCALL 和 ACALL。
Embedded Systems - Addressing Modes
addressing mode 表示如何寻址给定的存储器位置。有五种不同的方式或五种寻址模式可用于执行此指令,如下所示 −
-
Immediate addressing mode
-
Direct addressing mode
-
Register direct addressing mode
-
Register indirect addressing mode
-
Indexed addressing mode
Immediate Addressing Mode
让我们从一个示例开始。
MOV A, #6AH
一般而言,我们可以编写,
MOV A, #data
它被称为 immediate ,因为 8 位数据即刻传输到累加器(目标操作数)。
以下插图描述了上述指令及其执行。操作码 74H 保存于 0202 地址。数据 6AH 保存于程序存储器中的 0203 地址。在读取操作码 74H 后,下一个程序存储器地址中的数据将传输到累加器 A(E0H 是累加器的地址)。由于该指令为 2 字节并且在一个周期内执行,程序计数器将递增 2,并将指向程序存储器的 0204。
Note − ' symbol before 6AH indicates that the operand is a data (8 bit). In the absence of ' ,十六进制数字将作为地址。
Direct Addressing Mode
这是另一种寻址操作数的方式。在此,数据地址(源数据)提供为操作数。让我们举个例子。
MOV A, 04H
寄存器库#0(第 4 个寄存器)的地址为 04H。当执行 MOV 指令时,存储于寄存器 04H 中的数据将移动到累加器。由于寄存器 04H 保存数据 1FH,因此 1FH 移动到累加器。
Note − 我们未使用 ' in direct addressing mode, unlike immediate mode. If we had used ' ,数据值 04H 会传输到累加器,而不是 1FH。
现在,看一看以下插图。它显示了指令如何执行。
如上图所示,这是一条 2 字节指令,需要 1 个周期才能完成。PC 将递增 2,并将指向 0204。指令 MOV A, address 的操作码为 E5H。当执行 0202 处的指令(E5H)时,累加器激活并准备接收数据。然后 PC 转到下一个地址 0203 并查找位置 04H 的地址,即源数据(传送到累加器)所在的位置。在 04H 处,控制找到数据 1F 并将其传输到累加器,因此完成执行。
Register Direct Addressing Mode
在此寻址模式中,我们直接使用寄存器名称(作为源操作数)。让我们尝试在示例中进行理解。
MOV A, R4
一次,寄存器可以获取从 R0 到 R7 的值。有 32 个这样的寄存器。为了使用 32 个寄存器仅使用 8 个变量来寻址寄存器,使用寄存器库。有 4 个寄存器库从 0 到 3 命名。每个库包含 8 个寄存器从 R0 到 R7 命名。
一次,可以选取单个寄存器库。通过名为 Special Function Register (SFR)的 Processor Status Word (PSW)可以选取寄存器库。PSW 是一个 8 位 SFR,其中每位可以根据需要进行编程。位从 PSW.0 指定到 PSW.7。PSW.3 和 PSW.4 用于选取寄存器库。
现在,看一看以下插图,从而清晰了解它是如何工作的。
操作码 EC 用于 MOV A,R4。操作码存储于地址 0202 处,当执行它时,控制直接转到所选 PSW 中的寄存器库的 R4(即 PSW 中选择的)。如果选取寄存器库#0,则寄存器库#0 的 R4 中的数据将移动到累加器。此处 2F 存储于 04H。04H 表示寄存器库#0 的 R4 的地址。
数据(2F)移动以粗体突出显示。2F 从数据存储器位置 0CH 传输到累加器,并显示为虚线。0CH 是寄存器库#1 的寄存器 4(R4)的地址位置。上述指令为 1 字节,需要 1 个周期才能完全执行。这意味着,你可以使用寄存器直接寻址模式来保存程序存储器。
Register Indirect Addressing Mode
在此寻址模式中,数据地址存储于操作数中的寄存器内。
MOV A, @R0
此处 R0 中的值被视为地址,其中包含要传输到累加器的值。 Example : 如果 R0 的值为 20H,并且数据 2FH 存储在地址 20H 中,那么在执行此指令后,值 2FH 将传输到累加器中。请参见以下说明:
因此 MOV A, @R0 的操作码为 E6H。假设选择了寄存器组 #0,则寄存器组 #0 的 R0 保存数据 20H。程序控制移动到 20H,它在其中找到数据 2FH 并将其传输到 2FH,累加器。这是一条 1 字节指令,程序计数器递增 1 并且移动到程序存储器的 0203。
Note - 仅允许 R0 和 R1 形成寄存器间接寻址指令。换句话说,程序员可以使用 @R0 或 @R1 创建指令。所有寄存器组均被允许。
Indexed Addressing Mode
我们将举两个示例以理解索引寻址模式的概念。请看以下说明:
MOVC A, @A+DPTR
和
MOVC A, @A+PC
其中 DPTR 是数据指针,PC 是程序计数器(两者都是 16 位寄存器)。考虑第一个示例。
MOVC A, @A+DPTR
源操作数为 @A+DPTR。它包含此位置的源数据。在这里,我们正在将 DPTR 的内容与累加器的当前内容相加。此加法将给出一个新地址,该地址是源数据的地址。然后将此地址指出的数据传输到累加器。
操作码为 93H。DPTR 的值为 01FE,其中 01 位于 DPH(高 8 位)中,FE 位于 DPL(低 8 位)中。累加器的值为 02H。然后执行 16 位加法,01FE H+02H 得到 0200 H。位于位置 0200H 的数据将传输到累加器。累加器中的前一个值(02H)将被 0200H 中的新值替换。说明中的累加器中的新数据将突出显示。
这是一条 1 字节指令,执行需要 2 个周期,与之前的指令(每个都是 1 个周期)相比,此指令所需的执行时间较长。
另一个示例 MOVC A, @A+PC 的工作方式与上述示例相同。在这里,不是将 DPTR 与累加器相加,而是将程序计数器(PC)中的数据与累加器相加以获得目标地址。
Embedded Systems - SFR Registers
专用功能寄存器(或特殊目的寄存器,或简称特殊寄存器)是微处理器内部的一个寄存器,用于控制或监视微处理器的各种功能。由于特殊寄存器与处理器的某些特殊功能或状态密切相关,因此可能无法通过普通指令(如加、移动等)直接写入它们。相反,某些处理器架构中的一些特殊寄存器需要特殊指令才能对其进行修改。
在 8051 中,寄存器 A、B、DPTR 和 PSW 是通常称为 SFR(特殊功能寄存器)的寄存器组的一部分。可以通过 SFR 的名称或其地址来访问 SFR。
下表显示了 SFR 及其地址的列表。
Byte Address |
Bit Address |
|
FF |
||
F0 |
F7 |
F6 |
F5 |
F4 |
F3 |
F2 |
F1 |
F0 |
B |
||
E0 |
E7 |
|
E6 |
E5 |
E4 |
E3 |
E2 |
E1 |
E0 |
ACC |
|
D0 |
||
D7 |
D6 |
D5 |
D4 |
D3 |
D2 |
- |
D0 |
PSW |
B8 |
- |
- |
- |
BC |
BB |
BA |
B9 |
B8 |
IP |
B0 |
B7 |
B6 |
B5 |
B4 |
B3 |
B2 |
B1 |
B0 |
P3 |
|
A2 |
||
AF |
- |
- |
AC |
AB |
AA |
A9 |
A8 |
IE |
A0 |
A7 |
A6 |
A5 |
A4 |
A3 |
A2 |
A1 |
A0 |
P2 |
||
99 |
Not bit Addressable |
|
SBUF |
98 |
9F |
9E |
9D |
9C |
9B |
9A |
99 |
98 |
SCON |
|
90 |
||
97 |
96 |
95 |
94 |
93 |
92 |
91 |
90 |
P1 |
8D |
Not bit Addressable |
TH1 |
8C |
Not bit Addressable |
TH0 |
8B |
Not bit Addressable |
TL1 |
8A |
Not bit Addressable |
TL0 |
89 |
Not bit Addressable |
TMOD |
88 |
8F |
8E |
8D |
8C |
8B |
8A |
89 |
88 |
TCON |
87 |
Not bit Addressable |
PCON |
||
83 |
Not bit Addressable |
|
DPH |
82 |
Not bit Addressable |
DPL |
81 |
Not bit Addressable |
SP |
80 |
87 |
87 |
85 |
84 |
83 |
82 |
81 |
关于 SFR 地址,请考虑到以下两点。
-
特殊功能寄存器可以具有 80H 到 FFH 之间的地址。这些地址高于 80H,因为从 00 到 7FH 的地址是 8051 内部的 RAM 内存地址。
-
并非 80 到 FF 的所有地址空间都由 SFR 使用。未使用的地址空间 80H 到 FFH 被保留,8051 程序员不得使用。
CY |
PSW.7 |
Carry Flag |
AC |
PSW.6 |
Auxiliary Carry Flag |
F0 |
PSW.5 |
用户可用于一般用途的标志 0。 |
RS1 |
PSW.4 |
寄存器组选择器位 1 |
RS0 |
PSW.3 |
寄存器组选择器位 0 |
OV |
PSW.2 |
Overflow Flag |
- |
PSW.1 |
User definable FLAG |
P |
PSW.0 |
奇偶标志。由硬件在指令周期中设置/清除,以指明累加器中奇/偶数位的数量。 |
在以下示例中,SFR 寄存器的名称用其地址替换。
CY |
AC |
F0 |
RS1 |
RS0 |
OV |
- |
P |
我们可以使用 RS0 和 RS1 位选择相应的寄存器组位。
RS1 |
RS2 |
Register Bank |
Address |
0 |
0 |
0 |
00H-07H |
0 |
1 |
1 |
08H-0FH |
1 |
0 |
2 |
10H-17H |
1 |
1 |
3 |
18H-1FH |
程序状态字 (PSW) 包含状态位以反映 CPU 的当前状态。8051 变体提供一个特殊功能寄存器 PSW,其中包含此状态信息。8251 提供两个附加状态标志,Z 和 N,可在称为 PSW1 的第二个特殊功能寄存器中使用。
Embedded Systems - Timer/Counter
timer 是一种用于测量时间间隔的特殊时钟类型。经常被称为用于测量经过时间从零向上计数的计时器 stopwatch 。它是一种根据指定时间间隔倒数并用于产生时间延迟的设备,例如,沙漏是一种计时器。
counter 是一种存储(有时显示)特定事件或过程相对于时钟信号发生次数的设备。它用于计算微控制器外部发生的事件。在电子领域,可以使用寄存器类型电路(例如触发器)轻松实现计数器。
Difference between a Timer and a Counter
将计时器与计数器区分开来的点如下:
Timer |
Counter |
寄存器在每个机器周期中递增。 |
寄存器在考虑其对应于外部输入引脚 (T0, T1) 的 1 到 0 的转换时递增。 |
最大计数率为振荡器频率的 1/12。 |
最大计数率为振荡器频率的 1/24。 |
计时器使用内部时钟的频率,并产生延迟。 |
计数器使用外部信号来计算脉冲。 |
Timers of 8051 and their Associated Registers
8051 有两个定时器,Timer 0 和 Timer 1。它们可用作定时器或事件计数器。Timer 0 和 Timer 1 均为 16 位宽。由于 8051 遵循 8 位架构,因此每个 16 位可作为低字节和高字节的两个独立寄存器访问。
Timer 0 Register
Timer 0 的 16 位寄存器以低字节和高字节的形式访问。低字节寄存器称为 TL0(Timer 0 低字节),高字节寄存器称为 TH0(Timer 0 高字节)。这些寄存器可像任何其他寄存器一样访问。例如,指令 MOV TL0, #4H 将值移入 Timer #0 的低字节。
Timer 1 Register
Timer 1 的 16 位寄存器以低字节和高字节的形式访问。低字节寄存器称为 TL1(Timer 1 低字节),高字节寄存器称为 TH1(Timer 1 高字节)。这些寄存器可像任何其他寄存器一样访问。例如,指令 MOV TL1, #4H 将值移入 Timer 1 的低字节。
TMOD (Timer Mode) Register
Timer 0 和 Timer 1 都使用相同的寄存器来设置各种定时器操作模式。这是一个 8 位寄存器,其中低 4 位留给 Timer 0,高 4 位留给定时器。在每种情况下,低 2 位用于预先设置定时器模式,而高 2 位用于指定位置。
Gate − 设置后,定时器仅在 INT(0,1) 为高电平时运行。
C/T − 计数器/定时器选择位。
M1 − 模式位 1。
M0 − 模式位 0。
GATE
每个定时器都有启动和停止的方法。一些定时器通过软件执行此操作,一些通过硬件执行,还有一些同时具有软件和硬件控制。8051 定时器具有软件和硬件控制。定时器的启动和停止由软件使用指令 SETB TR1 和 CLR TR1 (对于定时器 1)以及 SETB TR0 和 CLR TR0 (对于定时器 0)控制。
SETB 指令用于启动它,而 CLR 指令用于停止它。只要 TMOD 寄存器中的 GATE = 0,这些指令就会启动和停止定时器。通过使 TMOD 寄存器中的 GATE = 1,定时器可以由外部源启动和停止。
C/T (CLOCK / TIMER)
TMOD 寄存器中的此位用于决定是否使用定时器作为 delay generator 或 event manager 。如果 C/T = 0,则将其用作定时器延迟生成。用于创建时延的时钟源是 8051 的晶体频率。如果 C/T = 0,则附加到 8051 的晶体频率也决定了 8051 定时器以规则间隔发出的滴答声的速度。
定时器频率总是附加到 8051 的晶体频率的 1/12。尽管基于 8051 的各种系统具有 10 MHz 到 40 MHz 的 XTAL 频率,但我们通常使用 11.0592 MHz 的 XTAL 频率。这是因为 8051 的串行通信波特率。XTAL = 11.0592 允许 8051 系统与 PC 通信且无错误。
Different Modes of Timers
Mode 0 (13-Bit Timer Mode)
在模式 0 下的 Timer 1 和 Timer 0 均作为 8 位计数器运行(带 32 位预分频器)。定时器寄存器配置为一个 13 位寄存器,由 TH1 的所有 8 位和 TL1 的低 5 位组成。TL1 的高 3 位是不确定的,应该忽略。设置运行标志 (TR1) 不会清除寄存器。当计数从所有 1 到所有 0 时,将设置定时器中断标志 TF1。对于 Timer 0,模式 0 操作与 Timer 1 相同。
Mode 1 (16-Bit Timer Mode)
定时器模式 "1" 是一个 16 位定时器,是一种常用的模式。它的工作方式与 13 位模式相同,只是使用了所有 16 位。TLx 从 0 开始递增,最大为 255。达到值 255 后,TLx 重置为 0,然后 THx 递增 1。作为一个完整的 16 位定时器,该定时器最多可以包含 65536 个不同的值,并且在 65536 个机器周期后会溢出回 0。
Mode 2 (8 Bit Auto Reload)
两个定时器寄存器均配置为具有自动重新加载的 8 位计数器(TL1 和 TL0)。TL1(TL0)溢出将设置 TF1(TF0),并使用软件预设的 Th1(TH0)的内容重新加载 TL1(TL0)。重新加载不会改变 TH1(TH0)。
自动重新加载模式的好处在于,你可以让定时器始终包含 200 到 255 的值。如果你使用模式 0 或 1,你必须在代码中检查溢出,然后在这种情况下,将定时器重置为 200。在这种情况下,宝贵的指令会检查值和/或重新加载。在模式 2 中,微控制器会处理这一切。一旦你在模式 2 中配置了一个定时器,你不必担心检查定时器是否溢出,也不必担心重置值,因为微控制器硬件会为你完成这一切。自动重新加载模式用于建立一个通用的波特率。
Mode 3 (Split Timer Mode)
定时器模式 "3" 称为 split-timer mode 。将 Timer 0 设置为模式 3 时,它将变为两个独立的 8 位定时器。Timer 0 是 TL0,Timer 1 是 TH0。这两个定时器从 0 计数到 255,并在溢出的情况下重置回 0。Timer 1 的所有位现在都将链接到 TH0。
当 Timer 0 处于分解模式时,真正的 Timer 1(即 TH1 和 TL1)可以设置为模式 0、1 或 2,但它不能启动/停止,因为执行此操作的位现在链接到 TH0。真正的定时器 1 将在每个机器周期内递增。
Initializing a Timer
决定定时器模式。考虑运行持续且独立于任何外部管脚的 16 位定时器。
初始化 TMOD SFR。使用 TMOD 的最低 4 位,并考虑定时器 0。将两个位,GATE 0 和 C/T 0,保持为 0,因为我们想要定时器独立于外部管脚。由于 16 位模式是定时器模式 1,因此清除 T0M1,并设置 T0M0。实际上,唯一要开启的是 TMOD 的第 0 位。现在执行以下指令 −
MOV TMOD,#01h
现在,定时器 0 处于 16 位定时器模式,但定时器未运行。要以运行模式启动定时器,通过执行以下指令设置 TR0 位 −
SETB TR0
现在,定时器 0 将立即开始计数,每隔一个机器周期递增一次。
Embedded Systems - Interrupt
中断是由硬件或软件发出的信号,指示需要立即注意的事件。每当中断发生时,控制器都会完成执行当前指令,并开始执行一个 Interrupt Service Routine (ISR) 或 Interrupt Handler 。ISR 会告诉处理器或控制器在中断发生时做什么。中断可以是硬件中断或软件中断。
Hardware Interrupt
硬件中断是从外部设备(如磁盘控制器或外部外围设备)发送到处理器的电子警报信号。例如,当我们在键盘上按一个键或移动鼠标时,它们会触发硬件中断,导致处理器读取击键或鼠标位置。
Software Interrupt
软件中断是由特殊情况或指令集中的特殊指令引起的,当它们被处理器执行时会引起中断。例如,如果处理器的算术逻辑单元运行一个将数字除以零的命令,从而导致除以零异常,从而导致计算机放弃计算或显示错误消息。软件中断指令的工作方式类似于子例程调用。
What is Polling?
持续监视的状态被称为 polling 。微控制器持续检查其他设备的状态;在执行此操作时,它不执行任何其他操作,并消耗所有处理时间来进行监视。可以通过使用中断来解决此问题。
在中断方法中,控制器仅在发生中断时响应。因此,不需要控制器定期监视接口和内置设备的状态(标志、信号等)。
Interrupt Service Routine
对于每个中断,都必须有一个中断服务例程 (ISR) 或 interrupt handler 。当发生中断时,微控制器会运行中断服务例程。对于每个中断,内存中都有一个固定位置,用于保存其中断服务例程 ISR 的地址。为保存 ISR 地址而留出的内存位置表称为中断向量表。
Interrupt Vector Table
在 8051 中,包括 RESET 在内有六个中断。
Interrupts |
ROM Location (Hex) |
Pin |
Interrupts |
ROM Location (HEX) |
|
串行 COM(RI 和 TI) |
0023 |
|
Timer 1 interrupts(TF1) |
001B |
|
外部硬件中断 1(INT1) |
0013 |
P3.3 (13) |
外部硬件中断 0(INT0) |
0003 |
P3.2 (12) |
Timer 0 (TF0) |
000B |
|
Reset |
0000 |
9 |
-
当复位引脚被激活时,8051 跳转到地址位置 0000。这是上电复位。
-
为定时器设置了两个中断:一个用于定时器 0,另一个用于定时器 1。在中断向量表中,内存位置分别为 000BH 和 001BH。
-
为硬件外部中断设置了两个中断。端口 3 中的引脚编号 12 和引脚编号 13 分别用于外部硬件中断 INT0 和 INT1。在中断向量表中,内存位置分别为 0003H 和 0013H。
-
串行通信有一个中断,它属于接收和发送。内存位置 0023H 属于此中断。
Steps to Execute an Interrupt
当一个中断变得活跃时,微控制器将经历以下步骤 −
-
微控制器关闭当前执行的指令,并将下一条指令(PC)的地址保存在堆栈中。
-
它还内部保存了所有中断的当前状态(即,不在堆叠中)。
-
它跳转到中断向量表中的内存位置,其中保存了中断服务例程的地址。
-
微控制器从中断向量表获取 ISR 的地址并跳转到它。它开始执行中断服务子例程,该子例程是 RETI(从中断返回)。
-
在执行 RETI 指令后,微控制器返回到被中断的位置。首先,它通过将堆栈的顶部字节弹出到 PC 中,从堆栈中获取程序计数器(PC)地址。然后,它开始从该地址执行。
Edge Triggering vs. Level Triggering
中断模块有两种类型——电平触发或边沿触发。
Level Triggered |
Edge Triggered |
无论何时断源电平被声明,则电平触发中断模块总会产生中断。 |
仅当边沿触发中断模块检测到中断源的声明边沿时,它才会产生中断。当中断源电平实际改变时,会检测到边沿。它还可以通过周期性采样来检测,并在前一个样本被取消声明时检测到声明的电平。 |
如果在固件中断处理程序处理中断时中断源仍被声明,则中断模块将重新生成中断,从而导致再次调用中断处理程序。 |
无论中断源如何工作,都可以立即操作边沿触发中断模块。 |
电平触发中断对于固件来说很麻烦。 |
边沿触发中断保持固件的代码复杂性低,减少固件的条件数量,并在处理中断时提供更大的灵活性。 |
Enabling and Disabling an Interrupt
复位后,即使所有中断都被激活,所有中断也会被禁用。必须使用软件启用中断,以便微控制器响应这些中断。
IE(中断使能)寄存器负责启用和禁用中断。IE 是一个可寻址寄存器。
Interrupt Enable Register
EA |
- |
ET2 |
ES |
ET1 |
EX1 |
ET0 |
EX0 |
-
EA − Global enable/disable.
-
- − Undefined.
-
ET2 − 启用定时器 2 中断。
-
ES − 启用串口中断。
-
ET1 − 启用定时器 1 中断。
-
EX1 − 启用外部 1 中断。
-
ET0 − 启用定时器 0 中断。
-
EX0 − 启用外部 0 中断。
要启用中断,我们会执行以下步骤 −
-
IE 寄存器 (EA) 的 D7 位必须为高电平,才能让寄存器的其余部分生效。
-
如果 EA = 1,中断将启用,且如果 IE 中它们对应的位为高电平,则会对其做出响应。如果 EA = 0,则不会响应任何中断,即使 IE 寄存器中它们对应的引脚为高电平。
Interrupt Priority in 8051
我们可以通过向任何一个中断分配更高优先级来更改中断优先级。这由对名为 IP (中断优先级) 的寄存器进行编程来完成。
下图显示了 IP 寄存器的位。在复位后,IP 寄存器包含所有 0。要向任何一个中断提供更高的优先级,我们会让 IP 寄存器中对应的位变为高电平。
- |
- |
- |
- |
PT1 |
PX1 |
PT0 |
PX0 |
- |
IP.7 |
Not Implemented. |
- |
IP.6 |
Not Implemented. |
- |
IP.5 |
Not Implemented. |
- |
IP.4 |
Not Implemented. |
PT1 |
IP.3 |
定义定时器 1 中断优先级。 |
PX1 |
IP.2 |
定义外部中断 1 优先级。 |
PT0 |
IP.1 |
定义定时器 0 中断优先级。 |
PX0 |
IP.0 |
定义外部中断 0 优先级。 |