宏汇编器及相关应用程序
宏汇编器,连接/定位器,
库管理器,用于8051、扩展型
8051和251微控制器的库管理器
用户手册
2001年2月
编译说明
这是罗亩在学习A51的过程中,为了使用方便而翻译整理的,由于没有多少时间检查较对,而且其中好多译法也没有深入研究,所以错误的地方可能比较多,还请各位同好斧正。
非常感谢21IC为我提供了一个可以记录我的学习、工作历程的空间,欢迎大家加入21IC,欢迎大家访问我的笔记:
https://www.wendangku.net/doc/4c13532625.html,
本手册的原文版权归Keil公司所有,中文版权归罗亩所有,请各位同好只用来学习参考,不要用作其它用途。
罗亩
2006年8月
序
本手册讲述如何使用 A51、AX51 和 A251 宏汇编器(罗亩按:此处将Assembler译作汇编器,以便与汇编程序(Assembly Program)区分),以及相关的应用程序,这些程序的作用是把汇编源代码翻译为可执行程序,以在8051或其变型,如Philips 80C51MX和Intel / Atmel WM 251器件上运行。本手册假定你熟悉Windows操作系统,并且知道如何将可执行程序装入微处理器中。
“第1章. 简介”,大体浏览一下不同的汇编器版本,讲解一些基本的汇编语言编程知识。
“第2章、架构”,大致讲解一下8051,扩展型8051,Philips 80C51MX和Intel / Atmel WM 251器件。
“第3章、编写汇编程序”,讲解汇编语句和算术、逻辑表达式的规则。
“第4章、汇编程序的伪指令”,讲解如何定义段和符号,以及所有伪指令的使用方法。
“第5章、汇编程序的宏”,讲解标准宏的功能,以及应用标准宏的一些知识。
“第6章、宏处理语言”,定义和讲解英特尔宏处理语言的应用。
“第7章、调用和控制”,讲解如何调用汇编器,如何控制汇编器的运行。
“第8章、错误信息”,列出了所有的汇编器错误信息,并说明导致出错的原因,以及怎样避免。
“第9章、连接/定位器”,包括所有连接/定位器伪指令的参考部分,还有例子和详细的说明。
“第10章、库管理器”,讲解如何制作和管理自己的库文件。
“第11章、目标文件-16制文件(Object-Hex)转换器”,说明如何生成英特尔16进制文件。
附录中包含程序举例,不同版本汇编器之间的区别,以及其他一些大家感兴趣的项目。
行文惯例(略)
第1章简介
本手册讲述的是用于传统的8051、扩展型8051和251微处理器家族的宏汇编器和相关软件,以及使用汇编语言为这些微处理器开发软件的过程。
传统的8051、扩展型8051和251的架构将在“第2章架构概览”中作一下简短的讲解。其中,对传统的8051处理器、扩展型8051不同版本的处理器和251处理器之间的区别作了讲解。对于微处理器架构最完整的信息,请参照你所用的微处理器的硬件参考手册。
为了实现对不同的8051和251变型产品的最优化支持,Keil提供了以下开发工具:
开发工具支持的微处理器,说明
A51宏汇编器
BL51连接/定位器LIB51库管理器用于传统型8051的开发工具包含对32×64KB代码堆的支持
AX51宏汇编器
LX51扩展型连接/定位器LIBX51库管理器用于传统型和扩展型8051(菲利浦80C51MX,达拉斯390,等等)的开发工具
最多支持16MB代码和XDATA存储空间。
A251宏汇编器
L251连接/定位器
LIB251库管理器
用于Intel / Atmel 251的开发工具。
AX51和A251汇编器是A51汇编器的扩展集。该用户向导覆盖了所有的开发工具版本。每当有一个特点或选项是某种工具专有的时,都已经清楚地标注出来。
下表列出了所有工具的版本和微处理器架构:
项目所指
Ax51宏汇编器A51,AX51和A251宏汇编器
Cx51编译器C51,CX51,C251 ANSI C编译器
Lx51连接/定位器BL51,LX51和L251连接/定位器
LIBx51库管理器LIB51,LIBX51和LIB251库管理器
OHx51目标-16进制转换器OH51,OHX51和OH251目标-16进制转换器
x51架构或x51器件所有的传统8051,扩展8051和251器件类型
如何开发一个程序
该部分大致讲解一下Ax51宏汇编器,Lx51连接/定位器及其应用。
什么是汇编器?
汇编器是一种软件工具,作用是简化编写计算机程序的任务。它可以将符号代码翻译为可执行的目标代码。该目标代码可以被编写进微处理器中,并被执行。汇编语言程序可直接被翻译为CPU指令,控制处理器完成运算。所以,要想有效地编写汇编程序,你应该既熟悉微处理器的架构,又熟悉汇编语言。
汇编语言的操作代码(助记符)很容易记忆(如MOV代表转移指令,ADD代表加法指令,等等)。对于指令操作数中的地址和数值,我们也可以把它们符号化。当我们为它们命名时,应尽量使它们的名称像指令助记符一样具有意义。例如,如果我们的程序必须处理一个日期数据,我们可以把它命名为DATE。如果我们的程序包含一组指令,它们完成一个定时循环(一组指令被重复执行,直到过去指定长度的时间为止),那么我们可以把这一程序组命名为TIMER_LOOP。
一个汇编程序由三部分组成:
?机器指令
?汇编器伪指令
?汇编器控制指令
一条机器指令就是一条机器代码,它可以被机器执行。关于机器指令的详细论述,请参考8051或其派生微处理器的硬件手册。附录A对机器指令作了一下概述。
汇编器伪指令是用来定义程序结构和符号的,并生成不可执行的代码(数据、信息,等)。参见“第4章汇编器伪指令”对所有汇编器伪指令的详细讨论。
汇编器控制指令设定汇编模式,并控制汇编流向。“第7章调用和控制指令”对所有的汇编器伪指令作了详细论述。
模块化编程
许多程序太长或太复杂,很难写在单一单元中。如果把代码分为较小的功能单元,将大大简化编程过程。模块化程序一般比单块程序容易编写、调试和修改。
模块化编程方法类似于包含大量电路的硬件设计。器件或程序在逻辑上被分为多个“黑箱子”,这些黑箱子都有指定的输入和输出。只要把各个单元之间的接口定义好,各个单元的详细设计就可以独立进行了。
模块化编程的优点如下:
更有效的程序开发:使用模块化方法可以更快地开发程序,因为较小的子程序比大程序更容易理解、设计和测试。定义好模块的输入和输出之后,程序员可以给模块提供需要的输入,通过检测输出来判断模块的正确性。然后由连接器把分立的模块连接、定位,生成一个单一的绝对地址的可执行的程序模块。最后,测试整个模块。
子程序可以重复利用:为一个程序编写的代码经常可以用于其它的程序中。在模块化编程中,可以把这些部分保存起来,以备将来使用。因为代码可以被重定位,所以保存的模块可以连接到满足其输入和输出要求的任意程序中。而在单块程序编程中,这样的部分深埋在整个程序中,不易被其它的程序使用。
便于调试和修改:模块化程序一般比单块程序易于调试。因为精心定义了程序的模块接口,很容易把问题定位到特定的模块。一旦找到了有问题的模块,改正问题就相当容易了。模块化编程可以简化程序修改的工作。我们可以很有信心地把新的或调试过的模块连接到一个已有的程序,而不用更改程序的其余部分。
下图是为x51开发程序的总体步骤。
模块化程序开发过程
这一部分简要讨论一下可重定位的Ax51汇编器,Lx51连接/定位器,以及OHx51编码转换器。
段、模块和程序
在初始设计阶段,首先定义程序要完成的任务,然后分为各个子程序。下面简要介绍一下使用Ax51汇编器和Lx51连接/定位器的子程序的种类。
一个段是一个程序块或数据块。一个段既可以是可重定位的,也可以是绝对的。一个可重定位的段有一个名字,类型,和其它的特性。名称相同、来自不同模块的段被认为是同一个段的一部分,它们叫做部分段。几个名称相同的部分段由Lx51连接/定位器结合为一个段。一个绝对段不能与其它段相结合。
一个模块包含一个或多个段或部分段。模块是一个源代码单元,可以被单独编译。它包含模块中使用的所有符号的定义。一个模块可以是单个由标准文本编辑器制作的ASCII文本文件。但是,你可以用include汇编伪指令把几个文本文件合并在一起。Ax51编译器把一个源文件编译为一个目标文件(object file)。每个目标文件就是一个模块。
当程序的所有模块都汇编完毕后,就由Lx51处理目标模块文件。Lx51连接/定位器给所有的可重定位的段分配绝对地址,把名称和类型相同的部分段合并起来。Lx51也分解模块间的所有引用。Lx51输出整个程序的一个绝对目标模块文件,和一个地图文件(map file),列出连接/定位过程的结果。
翻译和连接过程
一般地,我们会在μVersion2集成开发环境(IDE)中使用Ax51汇编器和其它工具。参见μVersion2用户手册:8051入门,以获取使用μVersion2集成开发环境的更多信息。
当然,我们也可以在命令行(罗亩按:在Windows中仿DOS的窗口,如果您没有学过DOS,可以略过这一部分)中调用Ax51汇编器。在Windows命令行中输入你想使用的汇编器版本的名称,例如A51。在这一命令行中,我们必须输入要被翻译的汇编源文件的名称,以及其它一些需要用来控制源文件翻译过程的控制指令。例如:
A51 DEMO.A51
回车后,汇编器输出如下:
A51 MACRO ASSEMBLER V6.00
ASSEMBLY COMPLETE. 0 WARNING(S), 0 ERROR(S)
所有的程序模块汇编完毕后,将由Lx51把目标模块连接起来,所有的变量和地址都被解析并定位到一个可执行程序中。下例所示为使用连接器的一条简单命令:
BL51 DEMO.OBJ, PRINT.OBJ
连接器生成一个绝对地址的目标文件和一个地图文件,地图文件中包含详细的静态信息和屏幕信息。连接器的输出如下:
BL51 LINKER/LOCATER V4.00
LINK/LOCATE RUN COMPLETE. 0 WARNING(S), 0 ERROR(S)
然后我们可以把可执行程序转换为Intel HEX文件,以编入PROM。这要用到OHx51十六进制转换程序,调用命令如下:
OH51 DEMO
转换程序的输出如下:
OBJECT TO HEX FILE CONVERTER OH51 V2.40
GENERATING INTEL HEX FILE: DEMO.HEX
OBJECT TO HEX CONVERSION COMPLETED.
由汇编器生成的一个列表文件例子。
A51 MACRO ASSEMBLER ASSEMBLER DEMO PROGRAM 07/07/2000 18:32:30 PAGE 1
MACRO ASSEMBLER A51 V6.01
OBJECT MODULE PLACED IN demo.OBJ
ASSEMBLER INVOKED BY: C:\KEIL\C51\BIN\A51.EXE DEMO.A51 DEBUG
LOC OBJ LINE SOURCE
1 $title (ASSEMBLER DEMO PROGRAM)
2 ; 一个简单的示例汇编模块
3
4 ; 符号定义
000D 5 CR EQU 13 ; Carriage?Return 进位?返回
000A 6 LF EQU 10 ; Line?Feed
7
8 ; 定义段
9 ?PR?DEMO SEGMENT CODE ; 程序部分
10 ?CO?DEMO SEGMENT CODE ; 常数部分
11
12 ; Extern Definition 外部定义
13 EXTRN CODE (PRINTS, DEMO)
14
15 ; 程序部分开始
_ _ _ _ 16 CSEG AT 0 ; Reset Vector 复位失量0000 020000 F 17 JMP Start
18
_ _ _ _ 19 RSEG ?PR?DEMO ; 程序部分
0000 900000 F 20 START: MOV DPTR, #Txt ; 示例文本
0003 120000 F 21 CALL PRINTS ; 打印字符串
22
0006 020000 F 23 JMP DEMO ; 示例程序
24
25 ; 文本常量
_ _ _ _ 26 RSEG ?CO?DEMO ; 常量部分
27 Txt: DB ‘Hello World’, CR, LF, 0
0000 48656C6C
0004 6F20576F
0008 726C640D
000C 0A00
28
29 END ; 模块结束SYMBOL TABLE LISTING
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _
N A M E T Y P E V A L U E ATTRIBUTES
?CO?DEMO . . . . . C SEG 000EH REL=UNIT
?PR?DEMO . . . . . C SEG 0009H REL=UNIT
CR . . . . . . . . N NUMB 000DH A
DEMO . . . . . . . C ADDR _ _ _ _ _ EXT
LF . . . . . . . . N NUMB 000AH A
PRINTS . . . . . . C ADDR _ _ _ _ _ EXT
START. . . . . . . C ADDR 0000H R SEG=?PR?DEMO TXT. . . . . . . . C ADDR 0000H R SEG=?CO?DEMO
REGISTER BANK(S) USED: 0
ASSEMBLY COMPLETE. 0 WARNING(S), 0 ERROR(S)
文件的扩展名
一般地,文件扩展名是用来标志文件内容的。下表列出8051工具链中用到的文件扩展名。
扩展名内容描述
.A51
.ASM
.SRC
源代码文件:包含ASCII文本,是Ax51编译器的输入文件。
.C
.C51
C源代码文件:包含ASCII文本,是Cx51 ANSI C编译器的输入文件。
.INC .H 包含文件:包含ASCII文本,将由include伪指令合并入一个源代码文件中。它们也是Ax51或Cx51的输入文件。
.OBJ 可重定位目标文件:是Ax51或Cx51的输出文件,包含程序代码和控制信息。
几个可重定位的目标文件是Lx51连接/定位器的典型输入文件。
.LST 列表目标文件:由Ax51或Cx51生成,是用来记录编译过程的。一个典型的列表文件包含ASCII程序文本和有关源模块的诊断信息。
. (无后缀).ABS 绝对目标文件:是Lx51的输出文件。典型地,它是一个完整的程序,可以在x51 CPU上执行。
.M51 .MAP 连接器地图文件:是由Lx51生成的列表文件。一个地图文件包含内存使用的信息和其它静态信息。
.HEX .H86 Hex文件:是OHx51目标文件-16进制转换器的输出文件,文件格式为Intel HEX。HEX是PROM编程器或其它应用程序的输入文件。
程序模板文件
下面的模板文件包含了编写汇编程序模块的指导原则和提示。该模板文件位于文件夹\C51\ASM或\C251\ASM中。罗亩对其中的英文说明作了一下汉化。
;------------------------------------------------------------------------------
; Source code template for A251/A51 assembler modules.
; A251/A51汇编模块的源代码模板。
; Copyright (c) 1995-2000 KEIL Software, Inc.
;------------------------------------------------------------------------------
$NOMOD51 ; disable predefined 8051 registers
; 禁能预定义的 8051 寄存器
#include
// 包含 CPU 定义文件(例如,8052)
;------------------------------------------------------------------------------
; Change names in lowercase to suit your needs.
; 把名称改为小写来适合你的要求。
;
; This assembly template gives you an idea of how to use the A251/A51
; Assembler. You are not required to build each module this way-this is only
; an example.
; 该汇编模板给你一个如何使用 A251/A51汇编器的概念。你不需要按这种方式建立
; 每个模块——这只是一个例子。
;
; All entries except the END statement at the End Of File are optional.
; 除了文件末尾的 END 语句外,所有语句都是可选的。
;
; If you use this template, make sure you remove any unused segment declarations,
; as well as unused variable space and assembly instructions.
; 如果您使用该模板,一定要把不用的段声明、以及不用的变量空间和汇编指令
; 全部去掉。
;
; This file cannot provide for every possible use of the A251/A51 Assembler.
; 该文件并未包含 A251/A51 汇编器的所有应用。
; Refer to the A51/A251 User's Guide for more information.
; 参见 A51/A251 用户手册以获取更多信息。
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; Module name (optional)
; 模块名称(可选)
;------------------------------------------------------------------------------
NAME module_name
;------------------------------------------------------------------------------
; Here, you may import symbols from other modules.
; 你可以从其它模块把符号导入到此处。
;------------------------------------------------------------------------------
EXTRN CODE (code_symbol) ; May be a subroutine entry declared in
; CODE segments or with CODE directive.
; 可以是在 CODE 段中或用伪指令CODE
; 声明的子程序入口
EXTRN DATA (data_symbol) ; May be any symbol declared in DATA segments
; segments or with DATA directive.
; 可以是在 DATA 段中或用伪指令 DATA
; 声明的的任意符号。
EXTRN BIT (bit_symbol) ; May be any symbol declared in BIT segments
; or with BIT directive.
; 可以是在 BIT 段中或用伪指令 BIT
; 声明的任意符号。
EXTRN XDATA (xdata_symbol) ; May be any symbol declared in XDATA segments
; or with XDATA directive.
; 可以是在 XDATA 段中或用伪指令 XDATA
; 定义的任意符号。
EXTRN NUMBER (typeless_symbol); May be any symbol declared with EQU or SET
; directive
; 可以是用伪指令 EQU 或 SET 声明的任意符号
;------------------------------------------------------------------------------
; You may include more than one symbol in an EXTRN statement.
; 在一条 EXTRN 语句中,你可以包含多个符号。
;------------------------------------------------------------------------------
EXTRN CODE (sub_routine1, sub_routine2), DATA (variable_1)
;------------------------------------------------------------------------------
; Force a page break in the listing file.
; 在列表文件中强制换页。
;------------------------------------------------------------------------------
$EJECT
;------------------------------------------------------------------------------
; Here, you may export symbols to other modules.
; 此处,你可以把符号输出到其它模块。
;------------------------------------------------------------------------------
PUBLIC data_variable
PUBLIC code_entry
PUBLIC typeless_number
PUBLIC xdata_variable
PUBLIC bit_variable
;------------------------------------------------------------------------------
; You may include more than one symbol in a PUBLIC statement.
在一条 PUBLIC 语句中,你可以包含多个符号。
;------------------------------------------------------------------------------
PUBLIC data_variable1, code_table, typeless_num1, xdata_variable1
;------------------------------------------------------------------------------
; Put the STACK segment in the main module.
; 把堆栈 (STACK) 段置于主模块中。
;------------------------------------------------------------------------------
?STACK SEGMENT IDATA ; ?STACK goes into IDATA RAM.
; 把 ?STACK 定义在IDATA RAM 中。
RSEG ?STACK ; switch to ?STACK segment.
; 切换到 ?STACK 段。
DS 5 ; reserve your stack space
; 5 bytes in this example.
; 在本例中保留 5 个字节的堆栈空间$EJECT
;------------------------------------------------------------------------------
; Put segment and variable declarations here.
; 把段和变量声明放在此处。
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; DATA SEGMENT--Reserves space in DATA RAM--Delete this segment if not used.
; DATA SEGMENT—在 DATA RAM中预留空间—如果不用的话就删掉。
;------------------------------------------------------------------------------
data_seg_name SEGMENT DATA ; segment for DATA RAM.
; 声明一个 DATA RAM 段
RSEG data_seg_name ; switch to this data segment
; 切换到该数据段
data_variable: DS 1 ; reserve 1 Bytes for data_variable
; 为data_variable 预留1个字节
data_variable1: DS 2 ; reserve 2 Bytes for data_variable1
; 为data_variable1 预留2个字节
;------------------------------------------------------------------------------
; XDATA SEGMENT--Reserves space in XDATA RAM--Delete this segment if not used. ; XDATA SEGMENT--在XDATA RAM 中预留空间—如果不用的话就删掉。
;------------------------------------------------------------------------------
xdata_seg_name SEGMENT XDATA ; segment for XDATA RAM
; 声明一个 XDATA RAM 段
RSEG xdata_seg_name ; switch to this xdata segment
; 切换到该数据段
xdata_variable: DS 1 ; reserve 1 Bytes for xdata_variable
; 为xdata_variable 预留1个字节xdata_array: DS 500 ; reserve 500 Bytes for xdata_array
; 为xdata_array 预留500个字节
;------------------------------------------------------------------------------
; INPAGE XDATA SEGMENT--Reserves space in XDATA RAM page (page size: 256 Bytes)
; INPAGE XDATA SEGMENT—在 XDATA RAM 页中预留空间(页大小: 256 Bytes)
; INPAGE segments are useful for @R0 addressing methodes.
; 对于 @R0 寻址模式 INPAGE 非常有用。
; Delete this segment if not used.
; 如果不用的话就删掉该段。
;------------------------------------------------------------------------------
page_xdata_seg SEGMENT XDATA INPAGE ; INPAGE segment for XDATA RAM
; 声明一个 XDATA RAM 的INPAGE段 RSEG xdata_seg_name ; switch to this xdata segment
; 切换到该xdata 段
xdata_variable1:DS 1 ; reserve 1 Byte for xdata_variable1
; 为变量 xdata_variable1 预留1个字节
;------------------------------------------------------------------------------
; ABSOLUTE XDATA SEGMENT--Reserves space in XDATA RAM at absolute addresses.
; ABSOLUTE XDATA SEGMENT—在XDATA RAM 中预留绝对地址的空间。
; ABSOLUTE segments are useful for memory mapped I/O.
; 绝对段对于内存映射 I/O 非常有用。
; Delete this segment if not used.
; 如果不用的话就删掉该段。
;------------------------------------------------------------------------------
XSEG AT 8000H ; switch absolute XDATA segment @ 8000H
; 切换到绝对地址 XDATA 段到8000H XIO: DS 1 ; reserve 1 Byte for XIO port
; 为XIO 口预留一个字节。XCONFIG: DS 1 ; reserve 1 Byte for XCONFIG port
; 为XCONFIG 口预留一个字节。
;------------------------------------------------------------------------------
; BIT SEGMENT--Reserves space in BIT RAM--Delete segment if not used.
; BIT SEGMENT—在BIT RAM 中预留空间—如果不用的话就删掉。
;------------------------------------------------------------------------------
bit_seg_name SEGMENT BIT ; segment for BIT RAM.
; 声明一个位于 BIT RAM 中的段
RSEG bit_seg_name ; switch to this bit segment
; 切换到该 bit 段。
bit_variable: DBIT 1 ; reserve 1 Bit for bit_variable
bit_variable1: DBIT 4 ; reserve 4 Bits for bit_variable1
; 为bit_variable1 预留4位
;------------------------------------------------------------------------------
; Add constant (typeless) numbers here.
; 把常量(无符号)数值加在此处。
;------------------------------------------------------------------------------
typeless_number EQU 0DH ; assign 0D hex
; 赋给 16 进制数 0D typeless_num1 EQU typeless_number-8 ; evaluate typeless_num1
; 计算typeless_num1 $EJECT
;------------------------------------------------------------------------------
; Provide an LJMP to start at the reset address (address 0) in the main module.
; 提供一个 LJMP 到主模块中位于复位地址(地址0)处的 start 。
; You may use this style for interrupt service routines.
; 你可以把这种方法用于中断服务程序。
;------------------------------------------------------------------------------
CSEG AT 0 ; absolute Segment at Address 0
; 位于地址 0 的绝对段。
LJMP start ; reset location (jump to start)
; 复位地址(跳转到 start)
;------------------------------------------------------------------------------
; CODE SEGMENT--Reserves space in CODE ROM for assembler instructions.
; CODE SEGMENT—为汇编器指令在 CODE ROM 中预留空间。
;------------------------------------------------------------------------------
code_seg_name SEGMENT CODE
RSEG code_seg_name ; switch to this code segment
; 切换到该代码段
USING 0 ; state register_bank used
; for the following program code.
; 用来跟踪程序代码的状态寄存器堆。
start: MOV SP,#?STACK-1 ; assign stack at beginning
; 在程序开始前分配堆栈
;------------------------------------------------------------------------------
; Insert your assembly program here. Note, the code below is non-functional.
; 把你的汇编程序插在此处。注意,下面的代码没有任何实际功能。
;------------------------------------------------------------------------------
ORL IE,#82H ; enable interrupt system (timer 0)
; 使能中断系统(定时器0)
SETB TR0 ; enable timer 0
; 使能定时器0
repeat_label: MOV A,data_symbol
ADD A,#typeless_symbol
CALL code_symbol
MOV DPTR,#xdata_symbol
MOVX A,@DPTR
MOV R1,A
PUSH AR1
CALL sub_routine1
POP AR1
ADD A,R1
JMP repeat_label
code_entry: CALL code_symbol
RET
code_table: DW repeat_label
DW code_entry
DB typeless_number
DB 0
$EJECT
;------------------------------------------------------------------------------
; To include an interrupt service routins, provide an LJMP to the ISR at the
; interrupt vector address.
; 要包含一个中断服务程序,在中断向量地址处加一条跳转到中断服务程序 (ISR) 的语句。;------------------------------------------------------------------------------
CSEG AT 0BH ; 0BH is address for Timer 0 interrupt
LJMP timer0int ; 0BH 是定时器0的中断入口地址。
;------------------------------------------------------------------------------
; Give each interrupt function its own code segment.
; 给出每个中断函数自己的代码段。
;------------------------------------------------------------------------------
int0_code_seg SEGMENT CODE ; segment for interrupt function
; 中断函数段
RSEG int0_code_seg ; switch to this code segment
; 切换到该代码段
USING 1 ; register bank for interrupt routine
; 为中断程序设置寄存器堆
timer0int: PUSH PSW
MOV PSW,#08H ; register bank 1
; 寄存器堆1
PUSH ACC
MOV R1,data_variable
MOV DPTR,#xdata_variable
MOVX A,@DPTR
ADD A,R1
MOV data_variable1,A
CLR A
ADD A,#0
MOV data_variable1+1,A
POP ACC
POP PSW
RETI