页数:36页文件大小:366.5 KB来源: 单片机原理及应用ppt课件
本课件讲解汇编语言程序设计方法:先说明程序设计步骤与流程图绘制,再逐条介绍ORG、END、EQU、DB、DW、DS、BIT七条伪指令,接着用实例拆解顺序、分支、循环、查表与子程序五种基本结构。
项目4「汇编语言程序设计」讲解汇编语言源程序的编制与汇编、常用伪指令,以及顺序、分支、循环、查表和子程序五种程序结构。
什么是程序设计?程序设计=结构+算法。程序设计就像盖房子:数据结构就像砖、瓦,算法就是设计图纸;有了原料还要按图纸一砖一瓦地砌,才能建成想要的房子。
4.1.1 程序设计步骤:对单片机系统进行程序设计时必须考虑硬件资源的配置,硬件系统设计完成后可按以下步骤进行程序设计。
用图形符号将总体设计思路及程序流向绘制在平面图上,使程序的结构关系直观明了,便于检查和修改。
4.1.2 汇编语言源程序的格式:汇编语言源程序由若干语句组成,每一语句可由4个部分组成——标号、操作码、操作数及注释,各部分以不同的分隔符分隔。
语句格式:[标号]:操作码[目的操作数][源操作数];[注释]
4.1.3 汇编语言源程序的汇编:将汇编语言源程序翻译成机器语言目标程序的过程称为汇编,对单片机助记符的汇编有人工汇编和机器汇编两种方法。
4.1.4 伪指令:在机器汇编时对汇编过程进行控制和指导的指令称为伪指令,供汇编程序识别和执行但不产生可执行的目标代码,如规定目标代码在ROM中的存放区域、给符号与标号赋值、指示汇编结束等。标准的MCS-51常用伪指令有以下7条。
1.汇编起始地址伪指令——ORG(Origin):格式为 ORG 16位地址,功能是规定该指令后的下一段源程序经汇编后生成代码的存放起始地址。
2.汇编结束伪指令——END(End of Assembly):指令格式为[标号:]END,功能是结束汇编语言源程序的操作。在源程序中只能有一条END,END之后所写的指令汇编程序不予处理。
3.符号赋值伪指令——EQU(EQUate):指令格式为「字符名称 EQU 数或汇编符号」,功能是将一个数或特定的汇编符号赋给指定的字符名称。
使用EQU伪指令可以把抽象的数字地址表示成有一定意义的符号,增强程序的可读性。
4.定义数据字节伪指令——DB(Define Byte):格式为[标号:]DB 项或项表。
例如:ORG 1100H TAB:DB 01H,04H,09H,10H DB 00001111B,1,A,BC
5.定义数据字命令——DW(Define Word):格式为[标号:]DW 项或项表。
例如:ORG 5000H MOV A,#30H …… ORG 5020H ADDTAB: DW 1234H,100H,10 …… END
一条DB和DW语句定义的数表其数的个数不得超过80个,数据较多时可使用多个定义命令;在MCS-51程序设计应用中常以DW来定义地址。
6.预留存储区伪指令——DS(Define Storage):格式为[标号:]DS 表达式,功能是从指定地址开始保留表达式的值所需数目的字节单元作为存储区以备后用,汇编时对这些单元不赋值。
例如:ORG 0100H MOV A,#50H …… ADDRTABL:DS 05H DB 20H END,即从标号ADDRTABL代表的地址开始保留5个连续的ROM地址单元,第6个单元存放20H。
对MCS-51单片机来说,DB、DW、DS伪指令只能对程序存储器使用,而不能对数据存储器进行初始化。
7.位地址赋值伪指令——BIT:格式为[字符名称]BIT 位地址,功能是给字符名称赋以位地址,其中位地址可以是绝对地址,也可以是符号地址(位符号名称)。
在其后的编程中AQ和A2就可以作为位地址使用。
4.1.5 程序设计技巧:1.模块化程序设计方法。单片机应用系统的程序一般由包含多个模块的主程序和各种子程序组成,每一程序模块都要完成一个明确的任务、实现某个具体的功能,如发送、接收、延时、打印、显示等。
采用模块化的程序设计方法,就是将这些不同的具体功能程序进行独立的设计和分别调试,最后将这些模块程序装配成整体程序并进行联调。
把一个多功能的、复杂的程序划分为若干个简单的、功能单一的程序模块,具有以下明显优点:
模块的划分有很大的灵活性,但也不能随意划分,划分时应遵循下述原则:
2.程序设计技巧:
4.2 程序结构 4.2.1 顺序程序:顺序结构是按照逻辑操作顺序,从某一条指令开始逐条顺序执行,直至某一条指令为止,无分支也无循环。
顺序结构是所有程序设计中最基本、最单纯的程序结构形式,在程序设计中使用最多,是一种最简单且应用最普遍的程序结构。实际应用程序远比顺序结构复杂,但它是组成复杂程序的基础和主干。
【例4.1】将两个半字节数合并成一个一字节数:设内部RAM 40H、41H单元中分别存放着8位二进制数,要求取出两个单元的低半字节,合并成一个字节后存入42H单元。流程如图4-1所示。
【例4.2】用顺序结构程序编写三字节无符号数的加法程序:被加数存放在40H(高字节)、41H(中字节)、42H(低字节),加数存放在43H(高字节)、44H(中字节)、45H(低字节),运算结果仍存在被加数单元中。流程如图4-2所示。
4.2.2 分支程序:实际问题一般比较复杂,总是伴随逻辑判断或条件选择,要求计算机能根据给定条件进行判断、选择不同的处理路径。程序的流向有两个或两个以上出口、根据指定条件选择程序流向的结构称为分支程序结构。
使用这些指令,可以完成为0、为1,为正、为负,以及相等、不相等各种条件判断,实现程序有条件地转移。
【例4.3】两个无符号数比较(两分支):内部RAM的30H单元和31H单元各存放了一个8位无符号数,请比较这两个数的大小,大数放在32H中。流程如图4-3所示。
【例4.4】两个无符号数比较(三分支程序):内部RAM的20H单元和30H单元各存放了一个8位有符号数,根据条件编程点亮相应的发光二极管,电路如图4-4所示。
流程为:开始→判断X=Y?→判断X>Y?→分别点亮黄灯、绿灯或红灯→结束。
3.散转程序:经过某个条件判断之后程序有多个流向(三个以上)的程序称为散转程序,MCS-51指令系统中专门提供了散转指令,使散转程序的编制更加简洁。
【例4.5】在例4.4电路的基础上加两个开关组成简单的信号灯电路(图4-6),编程实现按下不同开关点亮不同颜色灯的功能。
例4.5 开关状态与信号灯状态的对应关系:读P1口引脚状态送A,屏蔽无关位后以转移指令表基地址送DPTR,实现散转移。对应关系如下表。
| K0 | K1 | 状态 | 信号灯状态 |
|---|---|---|---|
| 0 | 0 | 状态1 | 红黄绿灯全亮(都按下) |
| 0 | 1 | 状态2 | 红灯亮(K0单独按下) |
| 1 | 0 | 状态3 | 绿灯亮(K1单独按下) |
| 1 | 1 | 状态4 | 黄灯亮(都未按下) |
4.2.3 循环程序:循环结构程序是把需要多次重复使用的程序段,利用转移指令反复转向该程序段,从而大大缩短程序代码、减少占用程序空间,程序结构也大大优化。如图4-8所示。
1.单重循环程序设计 【例4.6】数据极值查找程序:设内部RAM从30H单元开始存放有8个数,找出其中最大的数放到60H单元。流程如图4-9所示。
极值查找操作的主要内容是进行数值大小比较,采用先执行后判断的结构,首先设定比较次数,比较结束后把查找到的最大数送到60H单元。
【例4.7】将内部RAM中30H单元开始的数据传送到外部RAM 1200H开始的存储空间内,直到发现数据100停止传送。流程如图4-10所示。
由于循环次数事先不知道,但循环条件可以测试到,因此采用先判断后执行的程序结构。
2.多重循环程序设计—定时程序:在循环内套循环的程序结构称多重循环或循环嵌套。若把每重循环的内部看作一个整体,则多重循环的结构与单重循环一样,也由四部分组成。
定时程序是一种很典型的多重循环程序,用于定时检测、定时扫描、定时中断等。所谓定时就是让CPU做一些与主程序功能无关的操作(例如将一个数字逐次减1直到为0)来空耗掉CPU的时间,由于知道CPU执行每条指令的准确时间,延时程序的时间可以精确计算出来。
【例4.8】设计一个延时50ms的程序,设单片机时钟晶振频率为fosc=12MHz。
机器周期的计算方法:T机器=12T时钟=12×(1/12M)=1μs。最简单的单循环定时程序:
NOP指令的机器周期为1,用来提高定时精度,DJNZ指令的机器周期为2,故一次循环共4个机器周期;一个机器周期是1μs,则一次循环的延迟时间为4μs,程序总的延迟时间为4×time(μs)。
R7是8位寄存器,故这个程序的最长定时时间为256×4=1020(μs),定时范围是4~1024μs,可见单循环定时程序的时间延迟较小。
为了加长定时时间,通常采用多重循环方法,流程如图4-11所示,程序如下:
流程为:外循环次数TIME1→R7,内循环次数TIME2→R6,空操作后判断R6-1=0?再判断R7-1=0?,完成后返回。
最大定时时间计算公式为:(256×2+2+2)×256+1=132097(μs)。若定时50ms,采取合适的TIME1和TIME2即可,如TIME1=200和TIME2=123。
循环控制:在重复执行循环体的过程中,不断修改和判别循环变量,直到符合循环结束条件。一般情况下循环控制有以下几种方式:
4.2.4 查表程序:在微型机控制系统中,有些参数的计算非常复杂,用计算法不仅程序长、难于计算,而且耗费大量时间;还有一些非线性参数要涉及指数、对数、三角函数以及积分、微分等运算,用汇编语言编程都比较复杂,甚至无法建立数学模型,这时可以采用查表法。
所谓查表法,就是把事先计算或测得的数据按一定顺序编制成表格,查表程序的任务就是根据被测参数的值或者中间结果查出最终所需要的结果,具有程序简单、执行速度快等优点。
【例】查表计算函数 y=x!(x=0、1、2、…、7)的值:每个阶乘值占两个字节,以TABLE为起始地址按x的顺序依次存放,查表时用 MOVC A,@A+DPTR 取出对应结果。
| Y地址 | Y值 |
|---|---|
| TABLE | 00H |
| TABLE+1 | 00H |
| TABLE+2 | 01H |
| TABLE+3 | 00H |
| TABLE+4 | 02H |
| TABLE+5 | 00H |
| TABLE+6 | 06H |
| TABLE+7 | 00H |
| TABLE+8 | 24H |
| TABLE+9 | 00H |
| TABLE+A | 20H |
| TABLE+B | 01H |
| TABLE+C | 20H |
| TABLE+D | 07H |
| TABLE+E | 40H |
| TABLE+F | 50H |
说明:源文本中本表地址与数值完全粘连(例如「TABLE+A205」),此处按地址顺序拆分为相邻两字节的BCD结果(如x=6时为0720,即720;x=7时为5040),建议对照原课件图片核对后再入库。
4.2.5 子程序:在实际程序设计中,常会遇到多次应用的、完成相同的某种基本运算或操作的程序段。如果每用一次都从头编写一次,不仅麻烦、使程序冗长,而且浪费存储空间,还使出错率增加、给调试带来困难。
因此将那些需多次应用的、完成相同基本运算或操作的程序段从整个程序中独立出来,单独编制成一个程序段,尽量使其标准化,并存放于某一存储区域,需要时通过调用指令进行调用,这样的程序段称为子程序。
子程序作为一个具有独立功能的程序段,编程时需遵循以下原则:
编制子程序前,最好以程序注释的形式对子程序进行说明,说明内容包括:
下载地址:{{downurl}}
{{{a}}}
{{#b}}{{{b}}}
{{/b}} {{/title}} {{#nolog}}登陆注册
{{/nolog}} {{#djsx}}点我刷新
{{/djsx}} {{#gocz}} {{/gocz}} {{#ffqr}} {{/ffqr}}