汇编程序:注释,最值的显示fortran 子程序返回值部分代码段

最近的浏览历史
浏览此书的还浏览过
购买此书的人还购买过
书  名:汇编语言:基于Linux环境(第3版)
作  者: Jeff Duntemann
出版时间:
出 版 社: 清华大学出版社
字  数: 675 千字
印  次: 1-1
印  张: 36.75
开  本: 16开
ISBN: 3
装  帧:
定  价:¥99.00
电子书价:¥69.30
节省:¥29.70
vip价:¥69.30
电子书大小:8.51M
配套资源下载:
点击图标下载
共有商品评论0条
  本书是风靡美国的经典汇编语言畅销书籍的最新版,美国计算机领域著名作者Jeff Duntemann的力作。作者以其渊博的专业知识,丰富的实战经验,结合生动详尽的实例,全面系统地介绍了Linux环境下如何使用汇编语言进行程序设计以及与之有关的背景知识和相关工具的使用。本书写作风格独特,全书采用作者最有特色的对话式风格,结合大量源于生活的暗喻,将晦涩难懂的知识点条分缕析地呈现出来,以便读者能以轻松愉快的心情学习。
  本书适合刚涉足Linux环境下汇编语言的读者,也可作为相关技术人员的参考书。
  “你为什么要做那件事情?”
  那是1985年,我和其他几个焦躁不安的媒体大腕一起,乘坐一辆出租车去纽约参加记者招待会。那时我刚刚开始媒体生涯(作为PC Tech杂志的技术编辑),我的第一本书还有几个月就要出版。我碰巧坐在一个已经成名的编程栏目的作者/大师旁边。我们谈论了很多这样那样的事情,他给我留下了深刻的印象。我不会说出他的名字,因为他已经在这个领域做了很多事情,如果他不把戒烟当成第一要务的话,肯定会作出更多的贡献。
  但是,碰巧我是一个Turbo Pascal的狂热爱好者,我真正想做的事情是要学习如何编写能够使用全新的Microsoft Windows用户界面的Turbo Pascal程序。在谈到下面这个臭名昭著的问题之前,他皱了皱鼻子,做了个鬼脸苦笑道:
  “你为什么想做那件事情呢?”
  我以前从来没有听到过这个问题(尽管后来不止一次地听到它),所以有点猝不及防。为什么?因为,嗯,因为……我想知道它的工作原理。
  “嗨! 那是C语言要做的事情。”
  更深一层的讨论使我彻底对Pascal迷失了方向。但是通过一番寻根究底之后,我了解到,不能用Turbo Pascal编写Windows应用程序。这样做是不可能的。或者这个编程栏目作者/大师根本不知道怎么做,或者二者兼而有之。我不知道真相属于哪一种,但是我的确知道了那个臭名昭著的问题的含义。
  各位看官,注意:当某些人问你“为什么你想做那件事情?”,它的真实含义是:“你在问我如何做一件或者通过使用我喜欢的工具无法实现,或者彻底位于我的经验之外的事情,但是我又不想承认这一点,以免丢脸。所以……如何和那些黑鹰队较量?”
  多年以来,我一遍又一遍地听到这句话:
  问:如何创建一个不用扫描就能读出它的长度的C字符串?
  答:你为什么想做那件事情?
  问:如何用汇编语言编写一个能够在Turbo Pascal中调用的子程序?
  答:你为什么想做那件事情?
  问:如何用汇编语言编写Windows应用程序?
  答:你为什么想做那件事情?
  你明白了吧。对于这个臭名昭著的问题的答案通常是一样的,如果哪个狡猾的人这样问你,你应该立即以最快的速度反驳道:因为我想知道它的工作原理。
  这是一个很不充分的回答。我每次回答这个问题都用这个答案,但是有一次例外,那是很多年以前,我宣布要写一本教那些初次接触编程的人们如何用汇编语言来编写程序的书。
  问:天哪,你为什么想做那件事情?
  答:因为要想具备理解所有其他编程体系工作原理的本事,这是现有的最佳方法。
  对于程序员而言,有一件事情高于一切,那就是理解事情的工作原理。而且,学习如何成为一名程序员的过程几乎就是一个掌握事情工作原理的过程。这可以在各个级别上完成,取决于你所使用的工具。如果你正在用Visual Basic编程,你必须理解某些事情的工作原理,但是这些事情总体来说局限于Visual Basic本身。Visual Basic在程序员和计算机之间放置了一个“层”,这个层隐藏了很多机制(同样的情况适用于Delphi、Java、Python以及很多其他的高级语言编程环境)。如果你在使用C编译器,那么你距离计算机更近了一些,你将看到更多的机制——而且必须看到,只有了解了这些机制的工作原理才能够正确地使用它。然而,即便如此,还有一些内容是隐藏的,哪怕是对于那些老练的C程序员而言。
  反过来,如果你在使用汇编语言,那么你与计算机的距离就最大限度地缩短了。汇编语言什么都没有隐藏,而且也没扣留任何权利。当然,从另一方面来讲,由于在你和机器之间没有任何神奇的“层”来替你“照顾”某些事情,所以再无法为自己的无知找到任何托词。如果不知道事情的工作原理,那么你死定了——除非你拥有的知识够多,能自己把它弄明白。
  我创作本书的目的不完全是为了教你汇编语言本身,这是关键所在。如果说本书有一个根本的指导思想,那就是:引入一种受过训练的对于机器的好奇心,以及一些基本的上下文,根据这些上下文,你能够从最底层开始探索计算机,并具备竭尽所能掌握它的信心。这是一件困难的事情,但是只要专注些,耐心些,没有什么你掌握不了的,而且只要有时间(我得提醒一下),可能相当长。
  事实上,这里我真正想教给你的是如何学习。
你需要准备些什么
  要想按照我教的方式编写程序,你需要一台运行Linux的基于Intel x86的计算机。本书的正文和示例都假设至少运行在386上,但是因为Linux本身至少需要386环境,所以你已经满足硬件要求了。
  你需要熟悉使用Linux。我不能在本书中教你如何安装和运行Linux,不过在某些不太直观易懂的情况下,我会提供一些暗示。如果你对Linux环境还没有熟悉,我建议你找本教程,借助它来进行工作。这样的书很多,但是我最喜欢的是William von Hagen撰写的Ubuntu 8.10 Linux Bible(Linux for Dummies虽然不错,但是内容不够全面)。
  到底使用哪个Linux版本并不是很重要,只要至少基于2.4版的内核即可,当然,2.6版更好一些。我用来编写本书示例程序的版本是Ubuntu 8.10。哪一种图形用户界面并不重要,因为所有的程序都被编写为运行在纯文本Linux控制台下。汇编程序本身,即NASM,也是纯文本。
  我在讲解编程逻辑的时候以Kate编辑器为模型,它需要用到GUI。实际上你可以使用任何你想用的编辑器。并不是程序本身需要Kate编辑器,而是如果你刚刚开始接触编程,或者经常使用高级语言的特定编辑环境的话,Kate编辑器是一个很好的选择。
  我在正文中引用的调试器是Gdb,但是大多数情况下是通过它的内置GUI前端——Insight来使用它。Insight需要一个有效的X Window子系统,但是并不绑定到某一特定的GUI系统上,如GNOME或KDE。
  你不必事先知道如何安装和配置这些工具,因为我会在合适的时候,在相应的章节里涵盖所有必要工具的安装及配置。
  注意,对于其他不是基于Linux内核的Unix实现而言,其功能的执行方式可能与基于Linux内核的不完全相同。例如在调用内核时,BSD Unix就使用不同的规则。其他一些Unix版本(如Solaris)我并不擅长。
  本书从基础开始讲起,我的意思是“零起点”。也许你已经入门,或者已略有心得也没关系。我对待起点问题非常慎重。我仍然相信,依次阅读本书各章并非浪费时间。复习很管用,嘿!你会发现,你了解的知识并不像想象中的那么多(我经常这样)。
  但是,如果你的时间很不充裕,下面这个学习进度安排表可以让你偷点儿懒。
1.如果你已经理解了计算机编程的基本概念,可跳过第1章。
2.如果你已经理解了除了十进制之外的其他数制(尤其是十六进制和二进制)背后的思想,可跳过第2章。
3.如果你已经对计算机内部原理(内存、CPU结构等)有了一些了解,可跳过第3章。
4.如果你已经理解了x86内存寻址机制,可跳过第4章。
5.不。停!勾掉它(第4点)。即使你已经理解了x86内存寻址机制,也请阅读第4章。
  强调一下,这里的第5点是出于这样的原因:汇编语言编程是关于内存寻址的编程。如果不理解内存寻址机制,学习所有其他关于汇编的知识将毫无用处。所以,不要跳过第4章,无论你了解了或者认为了解了其他知识与否。从这一章开始,一直通读到本书的结尾。加载每一个示例程序,汇编每一个示例程序,运行每一个示例程序。力求理解每一个程序中的每一行代码。对什么内容都不要无条件地相信。
  而且,不仅限于此。当你理解了知识之后,修改那些示例程序。试着采用不同的方式完成它们。勇于尝试我没有提到的那些内容。大胆些。这样还不够,最好更疯狂一些——这些二进制位是没有感情的,可能发生的最糟糕的事情无非就是Linux抛出一个分段错误,它将会破坏你的程序(也许会伤害你的自尊),但是并不会破坏Linux(“保护模式”不是白叫的!)。唯一可能存在的困难是:当你在尝试某些知识的时候,要了解程序不工作的原因,而且要像你了解所有它做的其他事情一样的清晰。然后将其记录下来。
  最后是我追求的目标:教给你一种方法,通过这个方法,你可以理解计算机的每一个组成部分正在做的事情,以及它们是如何协同工作的。这并不意味着我本人会讲解计算机的每一个组成部分——即使我活得再长,也做不到。计算过程已经不再像以前那样简单,但是如果具备了耐心研究和实验的品质,你很有可能自己把它完成。最后,学习的唯一方法是:一切要靠自己。不能否认,你能够找到一些指导性内容——来自朋友的,来自互联网的,来自像本书一样的书籍的,但那仅仅是指导,车轴上的润滑剂而已。你必须搞清楚谁才是真正的主人,是你还是机器,然后使其成为主人。只有汇编语言程序员才真正有资格声称是主人,这是一个值得思考的事实。
留意大写习惯
  汇编语言是所有编程语言中最为独特的一种,它对于大小写的区分没有统一的标准。在C语言中,所有的标识符都是区分大小写的,但是,在汇编语言中,存在根本不区分大小写的汇编编译器。我在本书中用到的汇编编译器NASM,只对程序员定义的标识符区分大小写。但是,对于指令助记符以及寄存器名却不区分大小写。
  在有关汇编语言的书籍中常有一些书写习惯,其中之一就是将CPU指令助记符和寄存器名在正文中大写,而在散布于正文之中的源代码文件和代码片段中小写。这里,我也遵循这个习惯。在讨论部分的正文里,我会说MOV、EAX寄存器、EFLAGS等。在示例代码中,我会用mov、eax及eflags表示它们。
  这样做出于两个原因。
* 在正文中,助记符和寄存器需要醒目。因为在众多的一般文字之中,非常容易失去它们的线索。
* 为了阅读和学习本书之外的其他已有文档和源代码,你需要能够轻松地阅读汇编语言,无论它是大写的,小写的,还是大小写混合的。适应同一内容的不同表达方式,这一点非常重要。
  这可能会激怒某些Unix界的人们,因为他们盲目崇拜小写字符。我事先为激怒他们这件事情而道歉,但是我仍然坚定地认为,那样做就是一种盲目崇拜,而且相当孩子气。
为什么我又到这了
  无论你选择从什么地方开始学习本书,现在都是时间开始行动了。你只需记住,无论你面对的是什么,管它是什么黄鼠狼、机器,还是你自己的经验不足,脑海中首先要记住一点:你学习的目的是为了搞清楚它的工作原理。
  让我们出发吧。
  首先,我要感谢Wiley的Carol Long和Brain Herrmann,是他们允许这本书再版,并确保了再版的实现,而且比上次出版耗时更短。
  对于所有三个版本,我都欠Michael Abrash 太多人情债,是他始终如一地在诸多方面为我提供非常明智的建议,尤其是那些Intel微体系结构之间的晦涩难解的区别。
  尽管Randy Hyde、Frank Kotler、Beth和alt.lang.asm上的其余所有人没有意识到,但是他们其实已经通过各种方式为我提供了帮助,正是由于他们听取和回答来自汇编语言初学者的要求,才更有助于我决定哪些内容必须涵盖在像本书一样的书籍中,哪些不应该包含在里面。
  最后,一如既往,向Carol致敬!是她40年如一日给予我绝对的支持和神圣的友谊,使我能够从事诸如本书之类的项目,并且将其进行到底。
  作者简介
  Jeff Duntemann,技术作家、编辑和讲师,同时也是一个出版业分析师。在他涉足技术领域的30年中,他曾经担任过施乐公司的程序员和系统分析员,Ziff-Davis出版公司的技术期刊编辑,Coriolis Group Books及后来的Paraglyph 杂志社的编辑部主任。他目前是一名技术出版顾问,同时拥有Copperwood出版社(的按需印刷出版商)。Jeff与妻子Carol住在科罗拉多州斯普林斯市。
又一个令人愉快的星期六 1
一切尽在计划之中 1
步骤和测试 2
不止两种方式 3
计算机像我们一样
如果这是真实情况 4
此路不通,请绕行 5
Big Bux游戏 6
玩Big Bux游戏 8
像棋盘游戏一样的汇编语言
代码和数据 10
隐喻,将军 12
外星基数 14
新数学怪物归来 14
在火星上计数 15
火星数字剖析 17
数字基数的本质 19
八进制:绿色精怪怎样偷走
十六进制:解决数字的短缺 23
从十六进制到十进制,从十进制
到十六进制 27
从十六进制到十进制 27
从十进制到十六进制 28
练习!练习!
十六进制运算 31
列和进位 34
减法和借位 34
跨多列借位 36
意义何在 37
二进制值 39
为什么使用二进制 41
二进制简写方式:十六进制 42
摘下面具 44
RAXie,我们怎么不认识你 44
开关、晶体管和存储器 46
如果走陆路,就是1 47
晶体管开关 47
难以置信的位缩水 49
随机访问 51
存储器访问时间 52
字节,字,双字,
精致的芯片排成一行 54
车间工长和流水线 57
对话内存 57
驾驭数据总线 58
车间工长的口袋 59
遵循计划行事的盒子 60
取指和执行 61
车间工长的内脏 62
改变航向 64
是什么vs.怎么做:体系结构和
微体系结构 65
体系结构的演变 66
地下室里的秘密机制 67
工厂经理 68
操作系统:角落
BIOS:是软件,但并
多任务魔术 70
内核提升 71
内核爆炸 73
位置,位置,位置 74
内存模式的乐趣 74
16 位将带来64K
存储空间 75
兆字节的本质 79
向后兼容和虚拟
16位眼罩 80
段的本质 81
一个界限,而非
一个位置 84
用两个16位寄存器
构成20位地址 84
16位和32位寄存器 87
通用寄存器 88
半寄存器 90
指令指针寄存器 91
标志寄存器 92
三种主要的汇编编程模型 93
实模式平面模型 93
实模式段模型 95
保护模式平面模型 97
保护模式下不再允许我们做的
内存映射视频系统 100
直接访问端口硬件 101
直接调用BIOS 102
展望未来:64位“长模式” 102
汇编的权利 105
文件及其包含的内容 106
二进制文件 vs.
文本文件 106
用 Bless 编辑器查看
文件内容 108
解释原始数据 112
“字节序” 113
文本进去, 代码出来 116
汇编语言 117
当心“只写”
源代码 120
目标代码和连接器 120
重定位能力 123
汇编语言开发过程 124
工作目录规范 125
编辑源代码文件 126
编译源代码文件 126
汇编错误 127
回到编辑器 129
汇编警告 129
连接目标代码文件 130
连接错误 131
测试.EXE文件 131
错误vs.漏洞 132
我们还在那里吗 133
调试器和调试 133
沿着汇编小路旅行 134
安装软件 135
第1步:在编辑器中
编辑程序 137
第2步:使用NASM
编译程序 138
第3步:使用LD
连接器 140
第4步:测试可执行
第5步:在调试器中
观察程序运行 142
准备好要来
真格的了吗 148
有地儿,有工具 149
Kate 编辑器 151
安装Kate编辑器 151
启动Kate 152
Kate 会话 156
Kate编辑器的
文件管理 158
向工具栏添加
菜单项 161
Kate编辑器的
编辑控制 162
编程期间使用Kate
编辑器 166
Linux 和终端 169
Linux 控制台 169
Konsole中的字符
三个标准Unix文件 172
I/O 重定向 173
简易文本过滤器 175
使用转义序列进行终
端控制 177
为什么不用汇编语言编写
GUI应用程序呢 178
使用Linux Make 179
依赖条件 180
文件何时最新 182
依赖链 182
从Kate编辑器内部
调用Make实用工具 184
使用touch命令强制
执行生成操作 187
Insight 调试器 187
运行Insight 188
Insight的众多窗口 189
快速体验Insight 190
拿起你的工具 193
跟踪指令 194
为自己建立一个沙盒 194
一个最小的NASM
指令及其操作数 197
源操作数和目标
操作数 197
立即数 198
寄存器数据 200
内存数据 202
混淆数据和它的
内存数据的尺寸 204
糟糕的过去 204
CPU的标志位 205
标志规范 208
使用INC指令和DEC
指令加1和减1 208
从Insight中观察
标志如何改变程序的
有符号值和无符号值 214
补码和NEG 214
符号扩展和MOVSX 217
隐式操作数和Mul 219
MUL 和进位标志 221
使用DIV实现无符号
x86中的“慢动作”
阅读和使用汇编语言参考资料 223
对于复杂记忆的唤醒
初学者汇编语言参考
NEG:求补(求补码;即,
与-1相乘) 225
合法形式 227
操作数符号 227
这里没有包含的
我们的崇高目标 230
汇编语言程序的基本框架 230
最开始处的注释块 232
.data段 233
.bss?段 233
.text段 234
已初始化变量 235
字符串变量 235
通过EQU和$推导
字符串的长度 237
通过堆栈实现后进先出 239
每小时500个盘子 239
堆栈的内容上下
Push-y指令 242
POP 指令 244
临时存储 246
通过INT80使用Linux内核
不中断任何事情的
再次返回 252
通过使用 INT 80h
退出一个程序 253
软件中断VS硬件
INT 80h和可移植性
盲目崇拜 255
设计一个有价值的程序 256
问题定义 257
从伪代码开始 258
连续改进 259
不可避免的“哎呀!”
扫描缓冲区 264
缓冲溢出(“Off By One”)
进一步学习 271
位、标志、分支和表 272
位就是二进制位(字节也是
二进制位) 272
位编号 273
逻辑操作 273
与指令 274
位屏蔽 275
或指令 276
异或指令 276
非指令 278
段寄存器对逻辑操作
没有反应 278
移位操作 279
根据什么进行移位
移位指令的工作
将位移入进位标志 280
循环移位指令 280
将已知值存入进位
标志CF 282
位操作 282
将一个字节分解为
两个“半字节” 285
将高半字节移入
低半字节 286
使用查找表 286
通过移位和相加来
实现相乘 288
标志、测试和分支 291
无条件转移 292
条件转移指令 292
条件“缺席”时
进行跳转 293
通过CMP进行
比较操作 295
转移指令的错综
复杂之处 296
“大于”与“以上” 296
使用TEST指令
查找位1 298
使用BT指令
查找位0 300
保护模式下内存寻址详解 301
有效地址计算 303
位移量 303
基址+位移量寻址
基址+索引寻址方式 304
索引×缩放比例+位
移量寻址方式 305
其他寻址方式 307
LEA:最机密的
数学机器 309
16位寄存器的负担 311
字符表转换 312
转换表 312
用MOV或者XLAT
进行转换 315
用表来代替计算 319
盒子里面的盒子 322
调用和返回 331
调用中的调用 334
意外递归的危险 335
一个需要提防的标志
规范Bug 336
过程及其所需的
保存主调程序的
寄存器 338
局部数据 341
更多的表格技巧 342
在过程定义中加入
常量数据 344
局部标号和跳转的长度 345
“强行”访问局部
短转移、近转移和
远转移 349
生成外部过程库 350
全局声明和外部
全局过程和外部
过程的机制 353
连接库文件到
程序中 361
太多过程和太多库的
自定义过程的艺术 362
可维护性和
可重用性 363
确定哪些代码应该
成为一个过程 364
使用注释标头 365
Linux控制台下的简单光标
创建和使用宏 374
宏定义机制 375
定义带参数的宏 380
宏调用机制 382
宏内部的局部标号 383
像包含文件一样的
宏库文件 384
宏?vs.?过程:优点和
字符串奏鸣曲 387
汇编语言字符串的概念 387
彻底颠覆你的
“字符串感觉” 388
源字符串和目标
字符串 388
虚拟文本显示屏 389
REP STOSB,软件机枪 397
机枪扫射虚拟
显示器 397
执行STOSB 指令 398
STOSB 和方向
标志(DF) 399
在显示缓冲区中
定义行 400
将缓冲区发送到
Linux控制台 401
半自动武器:不带REP的
是谁递减了ECX 402
LOOP指令 402
在屏幕上显示一个
MUL并非 IMUL 404
添加ASCII数字 406
调整AAA 408
Ruler过程的教训 409
STOS指令的16位
版本和32位版本 409
MOVSB:快速块拷贝 409
DF和重叠块移动 411
使用Insight单步调试
REP字符串指令 413
将数据存储到不连续的
字符串中 414
显示一个ASCII表 414
嵌套指令循环 416
当ECX变为0时
进行跳转 416
关闭内层循环 417
关闭外层循环 418
Showchar小结 419
命令行参数和堆栈检查 419
两块虚拟内存 420
Linux堆栈剖析 422
为什么堆栈的地址
是不可预测的 424
使用Insight设置
命令行参数 424
通过Insight的内存
视图查看堆栈 425
使用SCASB进行字符串
REPNE v.s. REPE 431
从堆栈中弹出,
还是对堆栈寻址 432
额外的学分 434
什么是GNU 436
“瑞士军刀”
编译器 437
以GNU的方式生成
如何在汇编工作中
使用gcc 439
为什么不用gas 440
连接到标准的C函数库 441
C调用公约 442
建立一个框架 443
保存和恢复寄存器 443
建立堆栈帧 444
销毁堆栈帧 446
通过puts()输出
使用printf()格式化文本输出 448
使用fgets()和scanf()进行
数据输入 452
驾驭时间 459
C库的时间机制 459
从系统时钟中取出
time_t值 461
将time_t 值转换为
一个格式化字符串 461
生成单独的本地
时间值 462
通过使用MOVSD复制
glibc的tm结构 463
理解 ATandT 指令助记符 467
ATandT助记符公约 467
查看gcc创建的gas
源文件 468
ATandT 内存引用
产生随机数 472
利用srand()为随机
生成器“播种” 473
产生伪随机数 474
有些位比其他位更具
随机性 479
调用寄存器中的
C如何看待命令行参数 482
简单文件输入/输出 484
通过sscanf()将字符串
转换为数字 485
创建和打开文件 486
使用fgets()从文件中
读取文本 488
使用fprintf()写文本到
文件中 490
关于收集过程到库中的
结论:不是结束,而是刚刚开始 501
部分x86指令集 505
字符集图 565【图文】汇编语言第十章:模块化程序设计_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
评价文档:
汇编语言第十章:模块化程序设计
上传于||文档简介
&&汇​编​课​件
大小:304.00KB
登录百度文库,专享文档复制特权,财富值每天免费拿!
你可能喜欢汇编语言程序设计_单片机原理与接口技术(郭文川)_ppt_大学课件预览_高等教育资讯网
单片机原理与接口技术(郭文川):第四章
汇编语言程序设计
分类: 格式: 日期:日
第 4章 汇编语言程序设计4.1 汇编语言程序设计方法4.2 汇编语言源程序的基本结构顺序、循环、分支、子程序4.3 常用程序设计举例4.1.1 MCS-51汇编语言伪指令伪指令不属于指令系统,汇编后不会产生机器码,只用来对汇编过程进行控制或提供某些汇编信息 。如:规定汇编生成的目标代码在内存种的存放区域,给源程序中的符号和标号赋值以及指示汇编的结束等 。但它不会令计算机做任何操作,没有对应的机器语言代码,由于它有指令的形式而无指令的实质,所以称,伪,指令 。4.1 汇编语言程序设计方法4.1.3 MCS-51汇编语言伪指令1,ORG( Origin) 汇编起始地址命令功能:用于规定目标程序的起始地址 。格式:[标号,] ORG 地址地址项,16位绝对地址,也可以用标号或表达式表示 。如果不用 ORG规定,则汇编得到的目标程序将从 0000H开始 。一个源程序中,可多次使用 ORG指令以规定不同程序段的起始位置。地址应从小到大顺序排列,不允许重叠。例如,ORG 0000HLJMP MAINORG 4200HMAIN,MOV A,30H2,DB( Define Byte) 字节定义伪指令功能:用于从指定的地址单元开始,在程序存储器中定义字节数据 。格式,[标号,] DB 8位数表例如,DB,how are you?”常使用本命令存放数据表格,例如存放数码管显示的十六进制数的字形码,可使用多条 DB命令定义:DB C0H,F9H,A4H,B0HDB 99H,92H,82H,F8HDB 80H,90H,88H,83HDB C6H,A1H,86H,84H3,DW( Define Word) 字定义伪指令功能:用于从指定地址开始,在程序存储器单元中定义 16位的数据字 。格式,[标号,] DW 16位数表存放规则:高 8位在前 ( 低地址 ),低 8位在后 ( 高地址 ) 。例:DW 100H,1ACH,-814 ;按顺序存 01H,00H,01H,ACH,D2H,FCHDW,AA” ;存入 41H,41HDW,A” ;存入 00H,41HDW,ABC” ;不合法,因是两个字节查表时,为确定数据区的起始位置,可采用两种方法:( 1) 根据 DB命令前一条指令的地址确定 。例,8100H MOV A,#49H ( 1字节 )TAB,DB C0H,F9H,A4H,B0H( 2) 使用 ORG指令专门规定例,ORG 8100HTAB,DB C0H,F9H,A4H,B0H定义的数码管字形码从 8100地址开始存放 。注意,DB和 DW定义的数表,数的个数不得超过 80个。如果数据的数目较多时,可使用多个定义命令。在 MCS-51程序设计应用中,常以 DB定义数据,以 DW定义地址。4,DS( Define Storage) 定义存储区伪指令功能:用于从指定地址开始,保留指定数目的字节单元为存储区,供程序运行使用 。 汇编时对这些单元不赋值 。格式,[标号,] DS 16位数表例,ADDRTABL,DS 20例,ORG 8100HDS 08H注意:对 MSC-51单片机来说,DB,DW,DS命令只能对程序存储器使用,不能对数据存储器使用 。5,EQU( Equate) 赋值伪指令功能:用于给字符名称赋予一个特定值 。 赋值以后,其值在整个过程中有效 。格式:字符名称 EQU 赋值项,赋值项,,可以是常数,地址,标号或表达式 。8位或 16位二进制数 。 赋值以后的字符名称即可作地址使用,也可作立即数使用 。PA8155 EQU 8001H给标号 PA8155赋值 8001H。6,BIT 定义位地址符号伪指令功能,用于给字符名称赋以位地址 。格式,字符名称 BIT 位地址例如:AAA BIT 40HBBB BIT 50H其中,位地址,可以是绝对地址,也可以是符号地址 。7,END( END of assembly) 汇编终止命令功能:用于终止源程序的汇编工作。END之后的指令,汇编程序不予处理。格式:[标号,] END [表达式 ]只有主程序模块才有,表达式,项,且,表达式,的值等于该程序模块的入口地址 。 而其他程序模块就没有,表达式,项。,标号:,也是选择项 。一个源程序只能有一个 END命令 。4.1.2 程序的设计步骤与方法汇编和高级语言程序设计的过程:首先对问题进行分析,然后确定算法,再根据算法流程编写程序,最后是调试程序 。汇编语言程序设计的 独特点 在于:( 1) 用汇编语言进行程序设计时,对 数据的存放,寄存器和工作单元的使用等要由设计者安排 。 而高级语言程序设计时,这些工作都由计算机软件安排,程序设计者不必考虑 。( 2) 汇编语言程序设计要求设计人员必须对所使用的计算机的硬件结构有较为详细的了解 。特别是对 各类寄存器、端口、定时器 /计数器、中断等 内容要熟悉,以便在程序设计时能熟练使用。汇编语言程序的设计步骤:( 1)分析问题,抽象出描述问题的数学模型( 2)确定解决问题的算法( 3)根据算法绘制流程图( 4)分配存储空间及工作单元( 5)编写源程序( 6)上机调试程序质量的判断标准:程序的执行时间短;占用的内存单元少;程序的语句行数少。4.1.3 汇编语言源程序的编辑和汇编1,汇编语言源程序的编辑编辑好的源程序应以,,ASM”扩展名存盘2,汇编语言源程序的汇编源程序经机器汇编之后,若无语法错误,一般将生成两个新文件,它们的扩展名分别是,OBJ和,LST。例 4-1 将内部 RAM从 30H开始的 10个单元的内容相加,其和保存于 A(假设其和仍为 8位数)。列表文件(,LST)信息如下:地址 机器码 汇编语言源程序 注释ORG 2000H ;定义程序起始地址 START,MOV R0,#30H ;初始地址送 R0A MOV R2,#10 ;循环初始值送 R2 MOV A,#00H ;累加和初始值送 A2006 26 LOOP,ADDC A,@R0 ;完成累加2007 08 INC R0 ;修改地址2008 DAFC DJNZ R2,LOOP ;循环判断200A 80FE SJMP $ ;暂停END ;程序结束C INCLUDE IN HASHTABC START,2000C LOOP,2006目标文件(,OBJ)信息如下:07A0ADAFC80FE方法一:用逻辑指令将高,低半字节分开,对数字 0~9加上 30H即可得到所对应的 ASCII码 30H~39H。ORG 2000HMOV A,40H ;取数ANL A,#0FH ;分离出低半字节ADD A,#30H ;变为 ASCII码MOV 42H,A ;保存MOV A,40H ;重新取数SWAP A ;高、低半字节交换ANL A,#0FH ;分离出高半字节ADD A,#30H ;变为 ASCII码MOV 41H,A ;保存END例 4-2 将 40H单元的高、低半字节的两个 BCD码拆开并变成其 ASCII码,并分别存入 41H和 42H单元汇编语言程序共有四种结构形式:顺序结构、循环结构、分支结构和子程序结构。方法二:采用 BCD数除以 10H的方法,可把处于高、低半字节的两个 BCD码分别移到 A和 B的低 4位,然后再各自与 30H相“或”即变为 ASCII码。参考程序如下:ORG 2000HMOV A,40H ;取数MOV B,#10H ;送被除数DIV AB ;分离高、低半字节ORL B,#30H ;低 4位调整为 ASCII码MOV 42H,BORL A,#30H ;高 4位调整为 ASCII码MOV 41H,AEND例 4-2 将 40H单元的高、低半字节的两个 BCD码拆开并变成其 ASCII码,并分别存入 41H和 42H单元例 求两个 8位无符号数的和 。设两个 8位无符号数分别存放在内部 RAM 20H和 21H单元,所求和 ( 不超过 255) 存放在 22H单元 。ORG 2000HSTART,MOV R0,#20HMOV A,@R0INC R0ADD A,@R0INC R0MOV @R0,ASJMP $END4.2.5 循环程序设计循环初态循环程序一般由四个主要部分组成,(1) 初始化部分,为循环程序做准备,如规定循环次数,给各变量和地址指针预置初值 。(2) 处理部分,为反复执行的程序段,是循环程序的实体,也是循环程序的主体 。(3) 循环控制部分,这部分的作用是修改循环变量和控制变量,并判断循环是否结束,直到符合结束条件时,跳出循环为止 。(4) 结束部分,这部分主要是对循环程序的结果进行分析、处理和存放。循环:单重循环多重循环 ( 二重以上 ) --循环嵌套 。在多重循环程序中,只允许外重循环嵌套内重循环程序,而不允许循环体互相交叉,另外,也不允许从循环程序的外部跳入循环程序的内部 。例 4-3 把外部 RAM 5000H~50FFH单元的内容清零 。ORG 2000HSTART1,MOV DPTR,#5000H ;循环初始化MOV R0,#00HMOV A,#00HLOOP1,MOVX @DPTR,A ;循环体INC DPTRINC R0CJNE R0,#00H,LOOP1;循环控制END例 4-4 将内部 RAM从 40H开始连续单元的数据传送到外部 RAM从 2000H开始的连续单元中,当所传送的数据为 0FFH时,传送停止。解:ORG 2000HMOV R0,#40H ;循环初始化MOV DPTR,#2000HLOOP,MOV A,@R0CJNE A,#0FFH,LOOP1 ;循环控制SJMP NEXTLOOP1:MOVX @DPTR,A ;循环体INC R0INC DPTRSJMP LOOPNEXT,SJMP $END例 4-5 从 P1口重复 256次读数并取平均值,平均值的整数和小数部分分别保存于内部 RAM的 30H和 31H单元中。解:假设将 R2 R3作为 16位寄存器以保存连续 256次读数的累加和ORG 4000HINTEGER EQU 30HDECIMAL EQU 31HAVR,MOV R2,#0 ;循环初始化MOV R3,#0MOV R4,#0 ;累加次数为 256AVR1,MOV A,P1 ;循环体ADD A,R3 ;累加至低 8位JNC AVR2 ;无进位则暂存结果INC R2 ;有进位则高 8位加增 1AVR2,MOV R3,A ;暂存低 8位DJNZ R4,AVR1 ;循环控制MOV INTEGER,R2MOV DECIMAL,R3END例 设单片机外部数据存储器起始地址为 3000H的数据块中有100个补码,要求逐一检查,若为负数则求补后放回,正数则不变 。 ORG 1000HSTART1,MOV R7,#64H ;设置循环初始值MOV DPTR,#3000HLOOP1,MOVX A,@DPTRJNB ACC.7,LOOP2CPL AINC AMOVX @DPTR,ALOOP2,INC DPTR ;外部 RAM单元加 1DJNZ R7,LOOP1END例 有 10个无符号数依次存放在内部 RAM 30H开始的单元中,求其和,并将结果放在 R2和 R3中 。ORG 2000HMOV R0,#30HMOV R2,#00HMOV R3,#00HMOV R7,#0AHNEXT,MOV A,@R0 ;设置循环初始值ADD A,R3MOV R3,AMOV A,R2ADDC A,#00HMOV R2,AINC R0DJNZ R7,NEXTSJMP $END例 4.6 设 MCS-51单片机的时钟频率为 fosc = 12 MHz,试设计延时 50ms的延时程序 。延时程序所花费的时间是该程序指令的总机器周期数与机器周期的乘积 。通常,延时程序采用 MOV和 DJNZ指令来实现 。单循环延时程序,最大的循环次数位 256,则程序段为:MOV R0,#00H ;机器周期数为 1DJNZ R0,$ ;机器周期数为 2若单片机晶振为 12MHz,则一个机器周期为 1us。延时时间:( 1+256× 2) × 1μ s= 513μ s。需采用多重循环。多重循环,在一个循环体中又包含了其它的循环程序 。这种方式是实现延时程序的常用方法 。 使用多重循环时,必须 注意,(1) 循环嵌套,必须层次分明,不允许产生内外层循环交叉 。(2) 外循环可以一层层向内循环进入,结束时由里往外一层层退出 。(3) 内循环可以直接转入外循环,实现一个循环由多个条件控制的循环结构方式 。MOV R1,#MLOOP,MOV R2,#NNOPDJNZ R2,$DJNZ R1,LOOP内层循环的机器周期数为 Tn=1+1+2*N,总机器周期数为 Tm=( Tn+2)*M+1.设 N=123,M=200,则延时时间为 50.001ms。修改后程序清单:ORG 2000HMOV R1,#0C8H(200)LOOP,MOV R2,#7BH(123)NOPDJNZ R2,$DJNZ R1,LOOPSJMP $END补充例 设三字节无符号数相加被加数:内部 RAM 22H~ 20H单元 ( 低位在低字节 ),加数,内部 RAM 32H~ 30H单元 ( 低位在低字节 ),结果:存于内部 RAM 22H~ 20H单元,进位位存于 23H单元 。利用 ADDC指令进行多字节加法运算 。ORG 4200HMOV R0,#20H ;被加数的低字节地址MOV R1,#30H ;加数的低字节地址MOV R2,#03H ;循环次数CLR CLOOP,MOV A,@R0ADDC A,@R1 ;低字节相加MOV @R0,A ;存放字节相加结果INC R0INC R1DJNZ R2,LOOP ;循环控制MOV A,#00HADDC A,#00HMOV @R0,A ;进位位送 23HEND4.2.3 分支程序分支程序的基本结构:单分支和多分支 。其特点是:各处理模块是相互排斥的 。13条条件转移指令,分别为,JZ,JNZ,累加器判零转移指令;CJNE,比较条件转移指令;DJNZ,减 1条件转移指令 ;JC,JNC,JB,JNB,JBC,位控制条件转移指令等四类。(1)单重分支结构例 4-7 片内 RAM DATA1和 DATA2两个单元中各存有一个无符号数字,将两个数中的小者存入 MIN单元 。ORG 4000HMIN EQU 30HDATA1 EQU 31HDATA2 EQU 32HMOV A,DATA1 ;第一数送 ACLR CCJNE A,DATA2,UNEQU ;两数比较SJMP STORE ;相等,DATA1作为小的数UNEQU,JC STORE ;有借位,DATA1为小MOV A,DATA2 ;无借位,DATA2为小STORE,MOV MIN,A ;小者送 RAMEND例 4-8 片内 RAM两个单元中存有不相等的有符号数字 X和 Y,比较两数的大小,并将大数存入 MAX单元。若 X-Y> 0,则当( OV)= 0时,X> Y;当( OV)= 1时,X< Y;若 X-Y< 0,则当( OV)= 0时,X< Y;当( OV)= 1时,X> Y。图 4-6 例 4-8的流程图X 送 MAXX = Y?Y分支 0N( X - Y ) & 0?YOV = 1?NOV = 1?Y 送 MAXNNYY例 4-8 片内 RAM两个单元中存有不相等的有符号数字 X和 Y,比较两数的大小,并将大数存入 MAX单元。ORG 1000HXD EQU 31HYD EQU 32HMAX EQU 30HCLR CMOV A,XDSUBB A,YD ; X-Y,形成 OV标志JZ XMAX ;若 X=Y,则转向 FINISHJB ACC.7,NEG ;若 (X-Y)&0,则转向 NEGJB OV,YMAX ;若 (OV)=1,则转向 YMAXSJMP XMAX ;若 (OV)=0,则转向 XMAXNEG,JB OV,XMAX ;若 (OV)=1,则转向 XMAXYMAX,MOV A,YD ; Y&X,存 YSJMP FINISHXMAX,MOV A,XD ; X&Y,存 XFINISH,MOV MAX,A ;大数送 MAX单元END( 2)多重分支结构例 设 x,y分别存放在内部 RAM 30H和 40H中,根据 x的值,给 y赋值为 01H,00H,0FFH(-1).011y000xxxORG 2000HMOV A,30HJZ DONEJB ACC.7,LOOPMOV A,#01HSJMP DONELOOP,MOV A,#0FFHDONE,MOV 40H,ASJMP $END(3)散转结构例 设 R7的内容为 0~ n,对应的处理程序入口地址分别为PROG0~PROGn,编写散转程序 。跳转方法:逐个比较,类似 CASE。使用散转指令 JMP @A+DPTR 。设( R7)= 0~ n,对应的处理程序入口地址分别为PROG0~PROGn,且按照一定的规律排列 。ORG 2000HMOV DPTR,#TAB ;设置处理程序入口首地址MOV A,R7CLR CRLC A ;JNC NEXTINC DPHNEXT,JMP @A+DPTR ;转向形成的散转地址入口TAB,AJMP PROG0 ;直接转移地址表AJMP PROG1……AJMP PROGn例 4-9 在内部 RAM 20H和 21H单元中有两个无符号的数,由 22H中的值决定对该数完成加,减,乘或除运算 ( 20H单元的数为被减数或被除数 ),运算规则及结果保存处见表 4-1。表 4-1 例 4-9说明( 22H) 操作 结果保存处0 加 30H(低字节),31H(高字节 )1 减 40H2 乘 50H(低字节),51H(高字节 )3 除 60H(余数),61H(商 )ORG 1000HMOV A,22HMOV B,21HRL AMOV DPTR,#TABJMP @A+DPTRNOPTAB,AJMP ADDM ;散转表AJMP SUBMAJMP MULMAJMP DIVMADDM,MOV A,20H ;加法运算ADD A,BMOV 30H,AMOV A,#0ADDC A,#0MOV 31H,ASJMP FINISHSUBM,MOV A,20H ;减法运算SUBB A,BMOV 40H,ASJMP FINISHMULM,MOV A,20H ;乘法运算MUL ABMOV 51H,BMOV 50H,ASJMP FINISHDIVM,MOV A,20H ;除法运算DIV ABMOV 61H,AMOV 60H,BFINISH,END4.2.4 子程序设计子程序与一般程序的主要区别是在子程序的末尾有一条子程序返回指令 ( RET),其功能是执行完子程序后通过将堆栈内的断点地址弹出到PC而返回到主程序中 。在编写子程序时应注意以下几点:( 1) 要给每个子程序赋一个名字 。实际上是一个入口地址的代号 。( 2) 在子程序的末尾必须有子程序返回指令 RET。(3)要能正确地传递参数 。首先要有入口条件,说明进入子程序时它所要处理的数据如何得到,另外,要有出口条件,即处理的结果是如何存放的 。( 4) 注意保护现场和恢复现场。注意保存主程序和子程序共同涉及的,但值不同的累加器、寄存器和单元的内容。保护现场,PUSH恢复现场,POP( 5) 注意子程序的通用性。主程序调用子程序的指令:,LCALL”,,ACALL”。子程序返回指令,RET。子程序可以嵌套,嵌套次数从理论上说是无限的,但实际上由于受堆栈深度的影响,嵌套次数是有限的。例 4-10 在图 3-11 的 P1口与 LED的连接示意图中,若使得LED0~LED7依次点亮,其延时时间分别从 1s至 8s,LED7点亮之后又从 LED0开始循环。编写汇编语言源程序实现该功能 。C ORG 1000HMOV A,#1 ;主程序MOV R4,#0NEXT,INC R4C MOV P1,AC ACALL DELAYRL ASJMP NEXTDELAY,MOV R7,#10 ; 1s延时子程序DELAY3,MOV R6,#200DELAY2,MOV R5,#125DELAY1,DJNZ R5,DELAY1 ; 125× 4= 500μs= 0.5msDJNZ R6,DELAY2 ; 0.5 ms× 200= 0.1sDJNZ R7,DELAY3 ; 0.1s× 200= 1sDJNZ R4,DELAYRETEND例 4-11 两个无符号数据块的首地址分别为 30H和 40H,每个数据块的第一个字节都存放着数据块的长度(小于 15),求各数据块中最大值的乘积,并将结果存入 50H(乘积低字节)和 51H(乘积高字节)。解:可将求最大值的过程编写成一个子程序,子程序的入口参数是数据块的首地址,存放在 R1中,返回参数即为最大值,存放在 A中,参考程序如下,ORG 1000H ;主程序MOV R1,#30H ;置入口条件参数ACALL FMAX ;调用求最大值子程序MOV B,A ;第一个最大值存放于 BMOV R1,#40H ;置入口条件参数ACALL FMAX ;调用求最大值子程序MUL AB ;求乘积MOV 50H,A ;存乘积低字节MOV 51H,B ;存乘积低高字节SJMP $ORG 1200H ;子程序FMAX,MOV A,@R1 ;取数据块长度MOV R2,A ; R2中存放数据块的长度INC R1 ;改变地址指针MOV A,@R1 ;将第一个数放入 ADEC R2 ;数据个数减 1LOOP1,INC R1 ;修改地址指针CLR CSUBB A,@R1 ;相减比较大小JNC LOOP2 ; A中的数为大,跳向MOV A,@R1 ;否则,更换大数到 ASJMP LOOP3LOOP2,ADD A,@R1 ;恢复原最大值 LOOP3:LOOP3:DJNZ R2,LOOP1 ;若未比较完,则循环RETEND例,将 R0和 R1所指的内部 RAM中两个多字节无符号数相加,结果存入 R0所指的内部 RAM中 。NADD:CLR CNADD1:MOV A,@R0ADDC A,@R1MOV @R0,AINC R0INC R1DJNZ R7,NADD1JNC NADD2MOV @R0,#01HINC R0NADD2:DEC R0RET4.3 常用程序设计举例4.3.1 代码转换类程序计算机内部的运算一般都是用二进制,而在计算机与外设的数据传送中常采用 BCD码,ASCII码和其它代码,因此,就存在代码转换的问题 。 在程序设计中常采用 算法处理和查表方式 来实现代码转换 。1,十六进制数与 ASCII码之间的转换例 4-12 将从 30H单元开始的连续 8个单元中存放的十六进制数转换成其所对应的ASCII码,并分别存放在从 40H开始的 16个单元中。解,ORG 2000HMOV R0,#30H ;设定地址指针MOV R1,#40HMOV R7,#8 ;循环次数NEXT,MOV A,@R0 ;高字节转换SWAP AANL A,#0FHACALL HEXASMOV @R1,AINC R1MOV A,@R0 ;低字节转换ANL A,#0FHACALL HEXASMOV @R1,AINC R1 ;修改地址指针INC R0DJNZ R7,NEXTNOPSJMP $HEXAS,CLR C ;十六进制转换成 ASCII码子程序SUBB A,#10JC LOOPADD A,#7LOOP,ADD A,#10 ;补偿减掉的 10ADD A,#30HRETEND例 把外部 RAM 30H~3FH单元中的 ASCII码依次转换为十六进制数,并存入内部 RAM 60H~67H单元之中 。假设,被转换的 ASCII为 十六进制数 ( 0~F)的 ASCII,则,因为,0~9-- ASCII 30~39HA~F-- ASCII 41~46H若 ( 30H) = 41H-- A= 1041H- 30H= 11H= 17因为一个字节可装两个转换后得到的十六进制数,即两次转换才能拼装为一个字节。为了避免在程序中重复出现转换程序段,因此通常采用子程序结构,把转换操作编写为子程序。ORG 5000HMAIN,MOV R0,# 30H ;设置 ASCII码地址指针MOV R1,# 60H ;设置十六进制数地址指针MOV R7,# 08H ;字节个数AB,ACALL TRAN ;调用转换子程序SWAP A ; A高低字节交换MOVX @R1,AINC R0ACALL TRAN ; 调用转换子程序XCHD A,@R1 ;十六进制数拼装INC R0INC R1DJNZ R7,AB子程序 ( TRAN),TRAN,CLR CMOVX A,@R0 ;取 ASCII码SUBB A,#30HCJNE A,#0AH,BBAJMP BCBB,JC DONEBC,SUBB A,#07H ;大于等于 0AH,再减 07HDONE,RETEND例 4-13 将两字节十六进制整数转换成三字节的 BCD码 。 若待转换的双字节十六进制整数在 R6,R7中 ( R6中为高位 ),转换后的三字节 BCD码整数存于 R3,R4和 R5中 ( R3中为高位 ) 。解:二进制数 b7b6b5b4b3b2b1b0B所对应的十进制数 X可按照下式计算因此,只要按照十进制运算法则,将 bi( i=7,6,…,1,0)按权相加,就可以得到相应的十进制数 X。参考程序如下:ORG 2000HHEBCD,MOV A,#0 ; BCD码初始化MOV R3,AMOV R4,AMOV R5,AMOV R2,#16 ;循环次数NEXT,CLR CMOV A,R7 ; R7右移一位并送回RLC AMOV R7,AMOV A,R6 ; R6右移一位并送回RLC AMOV R6,AMOV A,R5 ;( R5) × 2并调整为 BCD码ADDC A,R5DA AMOV R5,AMOV A,R4 ;( R4) × 2并调整为 BCD码ADDC A,R4DA AMOV R4,AMOV A,R3ADDC A,R3MOV R3,A ;若万位数不超过 6,则不用调整DJNZ R2,NEXT ;处理完 16位了吗?NOPEND4.3.2 查表程序常用于非线性修正,非线性函数转换以及代码转换等 。专用的查表指令:MOVC A,@A+DPTR ;远程查表,64KB通过 以下三步操作实现查表 。·将所查表格的 首地址送入 DPTR;·将要查找的 数据序号,即数据在表中的位置送入 累加器 A中 ;·执行查表指令 MOVC A,@A+DPTR 进行读数并存结果存于累加器 A。MOVC A,@A+PC ;近程查表,0~+256B其实现查表也可通过以下三步操作来完成。· 将要查找的 数据序号,即数据在表中的位置 送入累加器 A中;· 把从 查表指令到表的首地址间的偏移量与 A值相加 ;· 执行查表指令 MOVC A,@A+PC 进行读数,查表结果送累加器 A。例 4-14 用查表指令编程实现将从 30H单元开始的连续 8个单元中存放的十六进制数转换成其所对应的 ASCII码,并分别存放在从 40H开始的 16个单元中 。ORG 2000HASCTAB,DB 30H,31H,32H,33H,34H,35H,36H,37H; ASCII码表DB 38H,39H,41H,42H,43H,44H,45H,46HMOV R0,#30H ;设定地址指针MOV R1,#40HMOV R7,#8 ;循环次数MOV DPTR,#ASCTABNEXT,MOV A,@R0 ;高字节转换SWAP AANL A,#0FHMOVC A,@A+DPTR ; 查表MOV @R1,AINC R1MOV A,@R0 ; 低字节转换ANL A,#0FHMOVC A,@A+DPTR ; 查表MOV @R1,AINC R1 ;修改地址指针INC R0DJNZ R7,NEXTNOPEND例 4-15 在一个巡回检测系统中,需对 8路输入进行控制,每路都有一最大允许值,为双字节数,且不全相同。控制时,需将输入值与最大值比较,若超过则进行报警。编写一子程序使其能查找每路的最大允许值。解:该查表运算中自变量 X是单字节,而因变量 Y是两字节的数。假设被检测路数存放在 R7中(入口参数),0~7路的最大允许值依次存放在 ROM中,查询得到的最大值存放在 30H(低字节)和 31H(出口参数)中,则参考程序如下:ORG 1000HMOV DPTR,#TABLEMOV A,R7RL A ;乘 2进行地址修正MOV R7,AMOVC A,@A+DPTR ;查表取高字节MOV 31H,AINC DPTRMOV A,R7MOVC A,@A+DPTR ;查表取低字节MOV 30H,ATABLE,DW H,H ; 最大允许值表DW H,HRET例 若累加器 A中存放的是一位 BCD码 。 通过查表将其转换成为相应的七段显示码,并存入寄存器 B中 。七段数码显示管连接方式:共阳极和共阴极两种 。共阳极是低电平为有效输入,共阴极为高电平为有效输入 。假设数码显示管为共阴极 。0~9的七段码为 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH。由于代码没有规律,一般采用查表完成 。h g f e d c b a0 0 1 1 1 1 1 1acedbgfh3FH若以 DPTR为基址,程序段如下:ORG 2000HMOV A,#05HMOV DPTR,#TABMOVC A,@A+DPTRMOV B,ASJMP $TAB,DB 3FH,06H,5BH,4FH,66H,DB 6DH,7DH,07H,7FH,6FH… …若以 PC为基地址,则程序段如下:… …MOV A,#05HADD A,#01HMOVC A,@A+PCNOPTAB,DB 3FH,06H,5BH,4FH,66H,DB 6DH,7DH,07H,7FH,6FH… …例 4-16 若内部 RAM 30H中存放的是一位 BCD码,通过查表将其转换成为相应的七段显示码,并存入寄存器 31H中。解,0~9的共阴极字形代码为 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH。ORG 1000HMOV A,30HADD A,#04H ;地址修正MOVC A,@A+PCMOV 31H,A ; 2字节指令SJMP $ ; 2字节指令TAB,DB 3FH,06H,5BH,4FH,66HDB 6DH,7DH,07H,7FH,6FHEND4.2.6 逻辑操作程序例 4-17 写出图 4-7所示电路的逻辑表达式,并编程实现其功能解:该电路图的最简逻辑表达式为,ORG 1000HX BIT P1.0 ;输入逻辑变量Y BIT P1.1Z BIT P1.2F BIT P1.3 ;输出逻辑变量EXOR,MOV C,XANL C,/YMOV F,C ;保存结果于 F位MOV C,YANL C,/XORL C,FANL C,ZMOV F,C ; F←()MOV C,XANL C,Y ; XYORL C,FMOV F,CEND图 4-7 例 4-17的逻辑电路图=1 & ≥11XYZ FXYZ)YX(F YXYXYX例 4-18 在图 3-7中,假设 K1,K2和 K3分别表示 X,Y和 Z三人对某一提案的表决,当 K闭合时,表示其同意该方案;当 K断开时,表示不同意该方案。当多数人同意时,输出 F为 1。假设 P1.7连接一共阴极 LED,将结果用 LED显示出来。编程实现此功能。解:根据数字电路中组合逻辑电路的设计知识,得出该逻辑电路的最简逻辑函数式是 F=XY+XZ+YZ,据此设计的参考程序如下:ORG 1000HX BIT P1.0Y BIT P1.1Z BIT P1.2MOV C,X ;实现 XYANL C,YMOV 20H,CMOV C,X ;实现 XZANL C,ZMOV 21H,CMOV C,Y ;实现 YZANL C,ZORL C,21HORL C,20HMOV P1.7,CNOPEND例 设 P1.0~P1.3为准备就绪信号输入端,当该 4位输入全为 1时说明各项工作已准备好,单片机可顺序执行主程序,否则循环等待 。ORG 2000HLOOP:MOV A,P1ANL A,#0FHCJNE A,#0FH,LOOPMAIN:例 用软件实现逻辑函数 。其中 X,Y,Z,W,F均为位变量,分别对应 P1.0,P1.1、P1.2,P1.3和 P1.7。 由开关为 P1.0,P1.1,P1.2,P1.3输入值,而由 P1.7输出该逻辑函数值 。X Y ZX Y Z WZYXFORG 5000HX BIT P1.0Y BIT P1.1Z BIT P1.2W BIT P1.3F BIT P1.7TEMP BIT 20H.0MOV C,XANL C,YANL C,Z ; C←XYZMOV TEMP,C ;暂存 XYZANL C,WORL C,TEMP ; C←XYZW + XYZMOV TEMP,CMOV C,XANL C,/YANL C,W ; C←ORL C,/TEMP ; C←MOV F,C ;输出最后结果END第 4 章 汇编语言程序设计思考题与习题4-1 把外部 RAM 5000H的内容拆开,高位送 5001H,低位送 5002H。4-2 把外部 RAM 3000H开始的 100字节的内容传送到从外部 RAM 3500H开始的连续单元中。4-3 设有 100个有符号数,连续存放在外部 RAM以2000H为首地址的存储区中,编程统计其中正数、负数和零的个数,并分别存放在 R5,R6和 R7。4-4 外部 RAM 1000H开始连续存放 20个双字节无符号数,低字节在前,高字节在后,编写求和程序,将结果存入内部 RAM 30H,31H,32H单元中。4-5 编程计算片内 RAM40H~47H单元中无符号数的算术平均值(假设和仍为 8位数),结果存放在 50H(商)和 51H(余数)中。4-6 从内部 RAM 30H开始存有一无符号数据块,其长度在 2FH单元中。求出数据块中最小值和最大值并分别存入 R6和 R7中。4-7 将上题中“无符号数”改为“有符号数”,求出其中的最小值和最大值(参考例 4-8)。4-8 从外部 RAM首地址为 1000H、长度为 50H的数据块中找出第一个 ASCII码‘ #’,并将其地址送到 1050H和 1051H单元中,如果没有‘ #’,则使 1050H和 1051H单元的内容为 0。4-9 把外部 RAM 30H~3FH单元中的 ASCII码依次转换为十六进制数,并存入内部 RAM 60H~67H单元之中。4-10 假设晶振频率 fosc =6MHz,根据图 3-11的线路设计灯亮程序。要求将 8只发光二极管间隔地分两组,每组 4只,两组交叉轮流发光,反复循环不止,每组灯亮持续时间为 1s。4-11 用软件实现逻辑函数 。其中 X,Y,Z,W,F均为位变量,分别对应 P1.0,P1.1,P1.2,P1.3和 P1.7。由 P1.0、P1.1,P1.2,P1.3输入值,而由 P1.7输出该逻辑函数值。4-1 把外部 RAM 5000H的内容拆开,高位送 5001H,低位送 5002H。MOV DPTR,#5000HMOVX A,@DPTRMOV R1,ASWAP AANL A,#0FHINC DPTRMOVX @DPTR,AMOV A,R1ANL A,#0FHINC DPTRMOVX @DPTR,A4-2 把外部 RAM 3000H开始的 100字节的内容传送到从外部RAM 3500H开始的连续单元中。MOV DPTR,#3000HMOV R7,#100LOOP:MOVX A,@DPTRMOV R1,AMOV A,DPHADD A,#5MOV DPH,AMOV A,R1MOVX @DPTR,AMOV A,DPHCLR CSUBB A,#05MOV DPH,ADJNZ R7,LOOP4-3 设有 100个有符号数,连续存放在外部 RAM以 2000H为首地址的存储区中,编程统计其中正数、负数和零的个数,并分别存放在 R5、R6和 R7。MOV DPTR,#2000HMOV R0,#100MOV R5,#0 ;正数个数MOV R6,#0 ;负数个数MOV R7,#0 ;0个数LOOP:MOVX A,@DPTRJZ ZEROJB ACC.7,NEGINC R5SJMP LOOP1NEG:INC R6SJMP LOOP1ZERO:INCR7LOOP1:DJNZ R0,LOOP4-4 外部 RAM 1000H开始连续存放 20个双字节无符号数,低字节在前,高字节在后,编写求和程序,将结果存入内部 RAM 30H,31H,32H单元中。MOV DPTR,#2000HMOV R7,#20MOV 30H,#0MOV 31H,#0MOV 32H,#0LOOP:MOVX A,@DPTRADD A,30HMOV 30H,AINC DPTRMOVX A,@DPTRADD A,31HMOV 31H,AJNC LOOP1INC 31HLOOP1:INC DPTRDJNZ R7,LOOP4-5 编程计算片内 RAM40H~47H单元中无符号数的算术平均值(假设和仍为 8位数),结果存放在 50H(商)和 51H(余数)中。MOV R0,#40HMOV R7,#8CLR CLOOP:ADD A,#@R0INC R0DJNZ R7,LOOPMOV B,#8DIV ABMOV 50H,AMOV 51H,B第 4 章 汇编语言程序设计4-6 从内部 RAM 30H开始存有一无符号数据块,其长度在 2FH单元中。求出数据块中最小值和最大值并分别存入 R6和 R7中 。MOV R0,#30HMOV A,@R0MOV R6,AMOV R7,ADEC 2FHLOOP:INC R0CLR CMOV A,R6SUBB A,@R0JNC MINCLR CMOV A,R7SUBB A,@R0JNC LOOP1MAX,MOV A,@R0MOV R7,ASJMP LOOP1MIN:MOV A,@R0MOV R6,ALOOP1:DJNZ 2FH,LOOP第 4 章 汇编语言程序设计4-8 从外部 RAM首地址为 1000H、长度为 50H的数据块中找出第一个 ASCII码‘ #’,并将其地址送到 1050H和 1051H单元中,如果没有‘ #’,则使 1050H和 1051H单元的内容为 0。C MOV DPTR,#1000HC MOV R7,#50HLOOP:MOVX A,@DPTRC CJNE A,#23H,LOOP1C SJMP DONE1LOOP1:INC DPTRC DJNZ R7,LOOPC CLR AC MOVX @DPTR,AC INC DPTRC MOVX @DPTR,AC SJMP DONEDONE1:MOV R1,DPLC MOV R2,DPHC MOV DPTR,#1050HC MOV A,R1C MOVX @DPTR,AC INC DPTRC MOV A,R2C MOVX @DPTR,ADONE:END第 4 章 汇编语言程序设计4-9 把外部 RAM 30H~3FH单元中的 ASCII码依次转换为十六进制数,并存入内部 RAM 60H~67H单元之中。ORG 5000HMAIN,MOV R0,# 30H ;设置 ASCII码地址指针MOV R1,# 60H ;设置十六进制数地址指针MOV R7,# 08H ;字节个数AB,ACALL TRAN ;调用转换子程序SWAP A ; A高低字节交换MOVX @R1,AINC R0ACALL TRAN ; 调用转换子程序XCHD A,@R1 ;十六进制数拼装INC R0INC R1DJNZ R7,AB第 4 章 汇编语言程序设计子程序 ( TRAN),TRAN,CLR CMOVX A,@R0 ;取 ASCII码SUBB A,#30HCJNE A,#0AH,BBAJMP BCBB,JC DONEBC,SUBB A,#07H ;大于等于 0AH,再减 07HDONE,RETEND第 4 章 汇编语言程序设计4-10 假设晶振频率 fosc =6MHz,根据图 3-11的线路设计灯亮程序。要求将 8只发光二极管间隔地分两组,每组 4只,两组交叉轮流发光,反复循环不止,每组灯亮持续时间为 1s。C ORG 1000HNEXT,MOV P1,#55HC ACALL DELAYC MOV P1,#0CCHC ACALL DELAYC SJMP NEXTDELAY,MOV R7,#10 ; 1s延时子程序DELAY3,MOV R6,#200DELAY2,MOV R5,#125DELAY1,DJNZ R5,DELAY1 ; 125× 4= 500μs= 0.5msDJNZ R6,DELAY2 ; 0.5 ms× 200= 0.1sDJNZ R7,DELAY3 ; 0.1s× 200= 1sRETEND第 4 章 汇编语言程序设计4-11 用软件实现逻辑函数 。其中 X,Y,Z,W,F均为位变量,分别对应 P1.0,P1.1,P1.2,P1.3和 P1.7。由 P1.0,P1.1,P1.2,P1.3输入值,而由 P1.7输出该逻辑函数值。4.2.8 实用程序设计举例( 1)排序类程序数据排序的算法有很多,常用的有冒泡排序法、插入排序法、选择排序法、二路归并排序法等。例 4.15:设在内部 RAM 30H单元连续存放了 8个单字节数据,编程实现按升序排列。ORG 2000HSTAR:MOV R0,#30HMOV R7,#07HCLR 00HLOOP:MOV A,@R0MOV 2BH,AINC R0MOV 2AH,@R0CLR CSUBB A,@R0JC NEXTMOV @R0,2BHDEC R0MOV @R0,2AHINC R0SETB 00HNEXT:DJNZ R7,LOOPJB 00H,STARSJMP $END习题 4-7:设内部 RAM的 30H和 31H单元中有两个带符号数,编写程序求出大数并存入内部 RAM的 32H单元 。ORG 4200HMOV A,30HXRL A,31HJB ACC.7,L1MOV A,30HCLR CSUBB A,31HJNC L2AJMP L3L1,MOV A,30HJNB ACC.7,L2L3,MOV 32H,31HAJMP L4L2,MOV 32H,30HSJMP $END习题 4-8:设 X为存放在内部 RAM 30H单元的无符号数,函数 Y存放在内部 RAM40H单元,编写满足下列关系的程序,ORG 4200HMOV A,30HCJNE A,#50H,LOOPAJMP AALOOP,JNC AACJNE A,#20H,LOOP2AJMP BBLOOP2,JC CCBB,MOV A,30HRL ARL AADD A,30HMOV 30H,AAJMP AACC,RL AMOV 30H,AAA,MOV 40H,30HEND习题 4-9:编写程序,求出内部 RAM 50H单元的数据含,1”的个数,并将结果存入 51H单元,MOV A,50HMOV 51H,#0MOV R1,#8LOOP:RLC AJNC LOOP1INC 51HLOOP1:DJNZ R1,LOOP习题 4-10,编写程序,将内部 RAM 30H~3FH单元的内容清零,ORG 4200HMOV R0,#30HMOV R7,#10HLOOP,MOV @R0,#0INC R0DJNZ R7,LOOPEND第 4 章 汇编语言程序设计习题 4-11:从内部 RAM 30H开始存有一无符号数据块,其长度在 2FH单元,求出数据块中最小值并存入 30H单元,ORG 4200HMOV R0,#30H ;数据区首地址MOV A,@R0 ;读第一个数DEC 2FHLOOP,INC R0MOV 20H,@R0 ;读下一个数CJNE A,20H,CHECK ;数值比较CHECK,JC LOOP1 ; A值大转MOV A,@R0 ;大数送 ALOOP1,DJNZ 2FH,LOOP ;未完,继续MOV 30H,A ;极值送 28H单元END习题 4-12,从外部 RAM 2000H单元起存放了 100个无符号数 。 统计其奇数和偶数的个数,并存放在内部 RAM 30H和 31H单元中 。ORG 4200HMOV DPTR,#2000HMOV R7,#100HMOV 30H,#0 ;QIMOV 31H,#0 ;OULOOP,MOVX A,@DPTRJB ACC.0,QIINC 31HAJMP AAQI,INC 30HAA,INC DPTRDJNZ R7,LOOPEND习题 4-13,将连续存放在外部 RAM 1000H开始的 100个单字节数据,传送到外部 RAM 2000H开始的连续地址单元中 。ORG 4200HMOV R7,#100MOV DPTR,#1000HLOOP,MOVX A,@DPTRMOV R0,AMOV A,DPHADD A,#10HMOV DPH,AMOV A,R0MOVX @DPTR,AMOV A,DPHCLR CSUBB A,#10HMOV DPH,AINC DPLDJNZ R7,LOOPEND习题 4-14,ORG 4200HMOV R7,#20MOV DPTR,#1000HMOV 30H,#0MOV 31H,#0MOV 32H,#0LOOP,MOVX A,@DPTRADD A,30HMOV 30H,AINC DPTRMOVX A,@DPTRADDC A,31HMOV 31H,AJNC LOOP1INC 32HLOOP1:INC DPTRDJNZ R7,LOOPEND习题 4-17:编写程序,实现 ∑2× i( i=1~10) 。 并将结果存放在内部 RAM 50H单元中 。ORG 4200HMOV R0,#10MOV 50H,#0LOOP,MOV A,R0RLAADD A,50HMOV 50H,ADJNZ R0,LOOPEND
课件名称:课件分类:计算机课件类型:教学课件文件大小:12.36MB下载次数:36评论次数:9用户评分:5.7
11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29.

我要回帖

更多关于 取进程id子程序代码 的文章

 

随机推荐