1.03k likes | 1.22k Views
单片机原理接口及其应用. (Principle and Application of Single Chip Microcomputer). 第 1 章 概述 第 2 章 MCS-51 单片机硬件结构 第 3 章 MCS-51 寻址方式和指令系统 第 4 章 MCS-51 汇编程序设计 第 5 章 中断系统 第 6 章 定时器 / 计数器及串行口 第 7 章 存储器扩展 第 8 章 接口电路扩展 第 9 章 应用举例. 4.1 汇编语言基本概念 4.2 汇编语言程序设计. 第 4 章 MCS-51 汇编程序设计 . 4.1.1 程序设计语言
E N D
单片机原理接口及其应用 (Principle and Application of Single Chip Microcomputer)
第1章 概述 第2章 MCS-51单片机硬件结构 第3章 MCS-51寻址方式和指令系统 第4章MCS-51汇编程序设计 第5章 中断系统 第6章 定时器/计数器及串行口 第7章 存储器扩展 第8章 接口电路扩展 第9章 应用举例
4.1 汇编语言基本概念 4.2 汇编语言程序设计 第4章 MCS-51汇编程序设计
4.1.1 程序设计语言 4.1.2 汇编语言的语句结构 4.1.3 伪指令 4.1 汇编语言基本概念
程序设计语言的结构及其功能可以分为三种: 1.机器语言:机器语言是用二进制代码0和1表示指令和数据的最原始的程序设计语言。 机器语言编程困难,一般不再用其编程。 2.汇编语言:在汇编语言中,指令用助记符表示,地址、操作数可用标号、符号地址及字符等形式来描述。 比机器语言编程方便,但要熟悉机器硬件结构、指令系统才能用好它。 汇编语言与机器语言一样是面向机器的,无通用性。 4.1.1 程序设计语言
3.高级语言:高级语言是接近于人的自然语言,面向过程而独立于机器的通用语言。3.高级语言:高级语言是接近于人的自然语言,面向过程而独立于机器的通用语言。 近年来单片机也流行采用高级语言编程。 如C51
1.汇编语言的指令类型 MCS-51单片机汇编语言,包含两类不同性质的指令。 (1)基本指令:即指令系统中的指令。它们都是机器能够执行的指令,每一条指令都有对应的机器代码。 (2)伪指令:汇编时用于控制汇编的指令。它们都不是机器的指令,无机器码产生。 4.1.2 汇编语言的语句结构
2.汇编语言的语句格式 汇编语言源程序是由汇编语句(即指令) 组成的。汇编语言一般由四部分组成。 其典型的汇编语句格式如下: 标号: 操作码 操作数 ;注释 START: MOV A,30H ;A←(30H)
START: MOV A, #0 ; 赋初值 (4-1) (p.69) MOV R1, #10 ;计数器赋初值 MOV R2, #00000011B LOOP: ADD A, R2 ;累加 DJNZ R1, LOOP HERE: SJMP HERE 标号:即符号地址,需要时加上。标号后加冒号;标号由字母开头(1-8字符),标号不能与指令助记符、预定义符号相同。 操作数:数值操作数,根据需要可用16进制 (后缀H)、10进制、二进制 (后缀B) 表示。16进制数以A~F开头时,前面要加’0’。 $符号的使用:程序最后一句可用 SJMP $ 代替。 注释:以分号开头,根据需要对于指令的作用加以解释。
用汇编语言编写的程序必须经汇编(翻译)成机用汇编语言编写的程序必须经汇编(翻译)成机 器代码,单片机才可运行它。为了控制汇编程序如何 完成源程序的汇编过程并产生目标程序,需要在源程 序中加入汇编控制命令,即伪指令。 1.ORG :汇编起始地址命令 用来说明ORG指令以下程序段在存储器中存放的起始地址。 例如 ORG 1000H START: MOV A,#20H MOV B,#30H ┇ 一个程序中可多次使用ORG指令,地址要由小到大 排列。 4.1.3 伪指令
2.EQU :赋值命令 给标号赋予一个确定的数值。其它语句可以引用这 个标号 TTY EQU 1080H 3.DB :定义数据字节命令 把数据以字节的形式存放在连续存储单元中。 ORG 1500H HERE: DB 56H,0A7H,35,‘A’ (1500h 56H A7H 23H 41H) 4.DW :定义数据字命令 按字的形式把数据存放在连续存储单元中。
ORG 1600H ABC: DW 1234H, 4567H (1600h 12H 34H 45H 67H) 5.DS :定义存储区命令 从指定的地址单元开始,保留一定数量存储单元。 ORG 1000H BASE: DS 50H 6.BIT:位定义命令 赋字符名为某个位地址值。 EA: BIT 0AFH 7.END:汇编结束命令 告知汇编程序源程序结束
4.2.1 汇编语言程序设计步骤 4.2.2 汇编语言程序的汇编 4.2.3 顺序程序 4.2.4 分支程序 4.2.5 循环程序 4.2.6 子程序 4.2.7 查找程序 4.2.8 码制转换程序 4.2.9 程序举例 4.2 汇编语言程序设计
1.分析问题 完成什么任务,解决什么问题;已知的数据,运算精度和速度; 2.确定算法 用何种方法解决问题;多个算法的比较;怎样组织数据; 3.设计程序流程图 把算法和解决问题的步骤具体化;通过流程图掌握程序的总体结构; 4.2.1 汇编语言程序设计步骤
4.分配内存单元和I/O端口地址 片内RAM划分:工作寄存器组;堆栈区;其它暂存区和缓冲区等;片外RAM; 确定各I/O端口的地址 5.编写汇编语言源程序 按流程图编写源程序;程序通常由主程序、子程序、中断服务程序等构成。 6.调试程序 对程序的各个部分分别调试;有些还要与硬件系统连接后调试; 切记:编程不易,调试更难。 只有掌握了程序的调试、测试才算会编程。
汇编语言源程序翻译成机器代码的过程称为“汇编”汇编语言源程序翻译成机器代码的过程称为“汇编” 1. 手工汇编 通过查指令代码将指令逐条翻译成机器代码并输入到 单片机中。这种方法要求自行按绝对地址定位指令,并计 算偏移量。工作量大、繁琐、易错,修改不易,已被机器 汇编取代。 2. 机器汇编 在系统机上用相应的汇编程序对源程序文件(*.asm) 自动翻译。由于使用不同种类的计算机进行汇编工作,称 为交叉汇编 (汇编后的机器代码不能直接在系统机上运行)。 机器汇编三步骤:(1)编辑输入源程序;(2)机器汇编; (3)下载机器代码并运行调试。 4.2.2 汇编语言程序的汇编
例4-2 (p.75) 地址 机器码 行号 源程序 LOC OBJ LINE SOURCE 0000 1 ORG 0H 0000 020020 2 LJMP 20H 0020 3 ORG 20H 0020 7408 4 START: MOV A, #8 0022 75F076 5 MOV B, #76H 0025 25E0 6 ADD A, Acc 0027 25F0 7 ADD A, B 0029 80FE 8 SJMP $ 9 END 2000-(2009+2)=FFF5
顺序程序是一种最简单,最基本的程序。 特点:程序按编写的顺序依次往下执行每一 条指令,直到最后一条。 【例4.1】 将30H单元内的两位BCD码拆开并 转换成ASCII码,存入RAM两个单元中(低位 在31H,高位在32H)。 程序流程如图4-1所示。 4.2.3 顺序程序
开始 取数据低4位 转换成ASCII码 存ASCII码 取数据高4位 转换成ASCII码 存ASCII码 结束 图4-1 拆字程序流程图
参考程序如下: ORG 2000H MOV A,30H ;取数 ANL A,#0FH ;取低4位 ADD A,#30H ;转换成ASCII码 MOV 31H,A ;保存结果 MOV A,30H ;取数 SWAP A ;高4位与低4位互换 ANL A,#0FH ;取低4位(原来的高4位) ADD A,#30H ;转换成ASCII码 MOV 32H,A ;保存结果 SJMP $ END
【例4.2】 设X、Y两个小于10的整数分别存于片内30H、31H单元,试求两数的平方和并将结果存于32H单元。 解:两数均小于10,故两数的平方和可存放于一个字节,可利用乘法指令求平方。 程序流程如图4-2所示。
开始 取数据X 求X2 暂存X2 取数据Y 求Y2 求X2+Y2 保存平方和 结束 图4-2 例4.2程序流程图
参考程序如下: ORG 2000H MOV A,30H ;取30H单元的数据X MOV B,A ;将X送入B寄存器 MUL AB ;求X2,结果在累加器中 MOV R1,A ;将结果暂存于R1寄存器中 MOV A,31H ;取31H单元数据Y MOV B,A ;将Y送入B寄存器 MUL AB ;求Y2,结果在累加器中 ADD A,R1 ;求X2+ Y2 MOV 32H,A ;保存结果 SJMP $ ;暂停 END
1.分支程序的基本形式 分支程序有三种基本形式,如图4-3所示。 N N 条件满足? 条件满足? Y Y B A A (b) (a) K=? K=0 K=1 … K=n …… A0 A1 An (c) 4.2.4 分支程序 图4-3 分支程序结构流程图
分支程序的设计要点如下: (1)先建立可供条件转移指令测试的条件。 (2)选用合适的条件转移指令。 (3)在转移的目的地址处设定标号。 2.双向分支程序设计举例 【例4.3】(4-12) 求符号函数的值 (p.88) 1 X > 0 Y = 0 X = 0 -1 X < 0 解:X为有符号数,存在40H单元。Y存在41H单元。 程序流程如图4-4所示。
参考程序如下: ORG 1000H MOV A, 40H ; 取数 CJNE A, #0, NZEAR ; 非零,转 AJMP NEGT ;(A)=0,转存结果 NZEAR: JNB ACC.7,POSI ; (A)>0,转 MOV A, #81H(原码); A ← -1 AJMP NEGT POSI: MOV A, #1H ; A ← 1 NEGT: MOV 41H, A ; 存结果 SJMP $ ; 暂停 END
3.多向分支程序设计举例 【例4.4】(4-13) 根据R2的值转向n个分支程序。(p.90) (R2)=0,转向PRG0; (LJMP PRG0) (R2)=1,转向PRG1; (LJMP PRG1) ┇ (R2)=n,转向PRGN; (LJMP PRGN) 解:利用JMP @A+DPTR 指令直接给PC赋值,使程序实现转移。
参考程序如下: JMP6: MOV DPTR,#TAB5 ; 转移指令表首地址 MOV A,R2 ; 取分支转移参量送A MOV B,#3 ; 乘数3送B (3字节指令) MUL AB ; 形成转移偏移量 MOV R6, A ; 暂存偏移量低8位 MOV A, B ; A←偏移量高8位 ADD A, DPH MOV DPH, A ; 加到DPH中 MOV A, R6 ; 取回偏移量低8位 JMP @A+DPTR ; 分支跳转[PC ← (A)+(DPTR)] ┇ TAB5: LJMP PRG0 ; 转移指令表 LJMP PRG1 ┇ LJMP PRGn
【例4.5】(4-14)根据(31H 30H)的内容决定程序流向 (31H)<80 (p.90) JMP6: MOV DPTR,#TAB6 ; 转移指令表首地址 MOV A,30H ; 取低字节分支转移参量送A MOV B,#3 ; 乘数3送B (3字节指令) MUL AB ; 形成低字节转移偏移量 MOV R3, A ; 暂存 MOV A, B ; A←低字节偏移量高8位 ADD A, DPH MOV DPH, A ; 加到DPH中 MOV A, 31H ; 取高字节分支转移参量送A MOV B,#3 ; 乘数3送B (3字节指令) MUL AB ; 形成高字节转移偏移量 ADD A, DPH ; 加入DPH MOV DPH, A
MOV A , R3 ; 取回低字节偏移量低8位 JMP @A+DPTR ; 分支跳转[PC ← (A)+(DPTR)] ┇ TAB6: LJMP PRG0 ; 转移指令表 LJMP PRG1 ┇ LJMP PRGn
1.循环程序的结构 初始化 初始化 循环控制 (某种条件) 修改循环参数 循环体 Y 循环结束? 修改循环参数 N 循环结束? 循环体 N 循环控制 (计数器) Y 结束部分 结束部分 结束 (b)直到型循环结构 (a)当型循环结构 开始 结束 开始 4.2.5 循环程序 图4-6 循环结构程序流程图
☆循环程序一般包括如下四个部分: (1)初始化 (2)循环体 (3)循环控制 (4)结束 ☆循环程序按结构形式,有单重循环与多重循环。 ☆在多重循环中,只允许外重循环嵌套内重循环。 ☆不允许循环相互交叉,也不允许从循环程序的外部跳入循环程序的内部(如图4-7所示)。
外循环 外循环 外循环 中循环 内循环 内循环 内循环 内循环 (c)交叉不正确 (b)嵌套正确 (a)嵌套正确 图4-7 多重循环示意图
2.循环程序设计举例 【例4.6】(4-15)有一单字节数据块从片内RAM的50H单元开始存放,共20个单元,求其累加和(存放在R3R4中)。(p.93) 解:此题设置一个计数器R2控制循环次数,每处理完一个数据,计数器减1。
参考源程序如下: ORG 2000H ADD1: MOV R2,#20 ; 计数器初值送R2 MOV R3,#0 MOV R4, #0 ; 部分和清零 MOV R0, #50H ; R0指向数据块首址 LOOP: MOV A, R4 ; 部分和低位 ADD A, @R0 ; 加上新数据低8位 MOV R4, A CLR A ADDC A, R3 ; 加进位到部分和高8位 MOV R3, A INC R0 ; 修改指针至下一个单元 DJNZ R2, LOOP ; 求和未完,继续 SJMP $ ; 暂停 END
【例4.7】(4-16)有一字符串,依次放在内部RAM从30H开始的单元中。字符串以0AH作为结束标志,编写测试字符串长度的程序。(p.93)【例4.7】(4-16)有一字符串,依次放在内部RAM从30H开始的单元中。字符串以0AH作为结束标志,编写测试字符串长度的程序。(p.93) 解:本题不能用计数器来控制循环的结束。只能采用寻找终止符的方法控制循环。
ORG 0030H ST: MOV R4, #0FFH ; 字符长度计数初值 MOV R1, #2FH ; 字符串指针初值 NEXT: INC R4 ; 字符长度加1 INC R1 ; 指向下一字符 CJNE @R1,#0AH,NEXT; 未到字符串结束处,转回 SJMP $ END ST: MOV R4, #0 ; 字符长度计数初值 MOV R1, #30H ; 字符串指针初值 AGAIN: CJNE @R1, #0AH, NEXT ;未到字符串结束处 SJMP STOP NEXT: INC R4 ; 字符长度加1 INC R1 ; 指向下一字符 SJMP AGAIN STOP: SJMP $ END
} 【例4.8】(4-17)50ms延时程序 (多重循环)(p.94) 用12MHz晶振时,一个机器周期1us。软件用循环实现延时。 DEL: MOV R7, #200 ; 1us DEL1: MOV R6, #125 ; 1us DEL2: DJNZ R6, DEL2 ; 2 us [125×2=250 us] DJNZ R7, DEL1 ; 2us [(250+1+2)×200=50600 us] RET ; 2us 延时计算: 1+50600+2=50603 us
精确一些的程序 DEL: MOV R7, #200 ; 1us DEL1: MOV R6, #123 ; 1us NOP ; 1us DEL2: DJNZ R6, DEL2 ; 2us, (123×2=246 us) DJNZ R7, DEL1 ; 2us [(246+4)×200=50000 us] RET ; 2us 延时计算: 1+50000+2=50003 us=50.003ms
1.子程序概念 完成某一专门功能的独立程序段,具有通用性。 被其它程序调用。 调用子程序,即暂时中断主程序的执行而转到子 程序的入口地址去执行子程序。如图4-9所示。 SUB: ….. LCALL SUB RET 4.2.6 子程序 图4-9 子程序的调用与返回
编写子程序应注意: (1)子程序第一条指令前加标号,称为入口地址。 (2)注意保护所用的寄存器(一般用堆栈)。 (3)返回处放RET。 (4)子程序说明(入口参数,出口参数)。 调用子程序应注意: (1)子程序占用的存储单元和寄存器。 (2)参数的传递(主程序到子程序)。 (3)获取子程序的结果(子程序到主程序) (4)嵌套调用与递归调用。如图4-10所示。
LCALL A LCALL B RET RET 图4-10 子程序的嵌套调用与返回
2. 子程序基本结构: MAIN: ┇ ; 主程序或调用程序 LCALL SUB ;调子程序 ┇ SUB: PUSH PSW ;保护现场 PUSH A 子程序主体部分 POP A ;恢复现场 POP PSW RET ;返回指令
3. 子程序调用过程: 子程序调用指令 LCALL label, 子程序可在64k空间任意放置 ACALL label,子程序首址与调用指令下一条指令地址位于同一个2k区内。 (1)子程序调用发生时,主程序暂时中止运行。硬件自动把调用指令的下一条指令地址压入堆栈。 (2)硬件将子程序首址装入PC, 子程序开始运行。 (3)子程序保护现场。 (4)子程序主体工作。 (5)子程序恢复现场。 (6)RET指令将压栈的主程序地址弹出,主程序从断点处重新运行。
4.子程序设计举例 【例4.9】(4-3) 单字节有符号数加减法子程序 (p.78) 功能: (R2)±(R3)→R7, 溢出时OV置位。R2, R3放有符号原码数, R7放带符号原码数。 符号数加法:进行补码加法。加数(减数),被加数(被减数)用补 码表示。 11H+22H = (11H)补+(22H)补 = 33H 11H+(-22H) = (11H)补+ (A2H)补= (11H+DEH)补= (EFH)补=91H -11H+22H = (91H)补+ (22H)补= (EFH+22H)补= (11H)补=11H 符号数减法:减法改做加法,减数符号位取反即可。 11H-22H = 11H+A2H = (11H)补+ (A2H)补 = (11H+DEH)补 = (EFH)补 = 91H
SUB1: MOV A, R3 ; 取减数 (减法子程序入口) CPL ACC.7 ; 符号位取反, 减法改做加法 MOV R3, A ADD1: MOV A, R3 ;加数(减数)求补码 (加法子程序入口) ACALL CMPT MOV R3, A MOV A, R2 ; 被加数(被减数)求补码 ACALL CMPT ADD A, R3 ; 补码加 JB OV, OVER ; 溢出返回 ACALL CMPT ; 结果转回原码 MOV R7, A ; 存结果 OVER: RET
(4-11)(p.87) CMPT: JNB ACC.7, RETURN ; (A) > 0, 退出 MOV C, ACC.7 ; 保存符号 MOV F0, C CPL A ADD A, #1 ; 求补码 MOV C, F0 MOV ACC.7, C ; 恢复符号 RETURN: RET ----------------------------------------------------------- MAIN: MOV R2, #11H MOV R3, #22H LCALL SUB1 ; (R7)=91H (-11H) MOV R2, #11H MOV R3, #A2H ; A2H= -22H LCALL ADD1 ; (R7)=91H (-11H)
【例4.10】(4-4 p.78) 4位BCD码减法子程序(被减数 > 减 数)。被减数在 51H, 50H 中,减数在 61H, 60H 中,差在 41H, 40H中。 因减法指令后不能用DA A指令进行十进制调整,需用 BCD补码来编程。 BCD补码加子程序 减数在R0指向的单元,被减数在R1指向的单元。 BSUB: MOV A, #9AH SUBB A, @R0 ; 求减数十进制补码 ADD A, @R1 ; 补码加 DA A ; BCD调整 CPL C ; 调整借位 INC R0 INC R1 ; 指向高位字节 RET
2位十进制数补码加法对进位的影响分析: 被减数-减数=被减数+减数的补码 =被减数+(100-减数) =(被减数-减数)+100 当 (被减数-减数) > 0, 上式百位为1, 即 Cy=1, 但此时应没有借位,Cy应该是0; 当 (被减数-减数)≤0, 上式百位为0, 即 Cy=0, 但此时应有借位, Cy应该是1; 可见只要在补码加后,加上CPL C就能得到正确的结 果。