电视看不几分钟就如图这个样子了,折纸青蛙按一下会跳键就好了,过几分钟就又这个样子了,周而复始的,这是怎么回事?

本类热门信息
周而复与《夜行集》
作者:郑豫广
(福建师范大学图书馆
我国皖籍现代著名作家周而复,饱浸旧学,一生写作不辍。作品体裁涉猎小说、诗歌、散文、戏剧、文学评论、童话、报告文学和回忆录等计12000万字。他主要以小说名世,鲜为人知他还是一位诗人,第一部专著却是诗集《夜行集》。本文较详细介绍他的平生业绩和创作《夜行集》的缘起、内容梗概及名家评价。
[关键词]周而复;夜行集;内容梗概;名家评价
周而复()原名周祖武,笔名周而复、吴疑、萄寰,室名北望楼,安徽省旌
(福建师范大学图书馆
我国皖籍现代著名作家周而复,饱浸旧学,一生写作不辍。作品体裁涉猎小说、诗歌、散文、戏剧、文学评论、童话、报告文学和回忆录等计12000万字。他主要以小说名世,鲜为人知他还是一位诗人,第一部专著却是诗集《夜行集》。本文较详细介绍他的平生业绩和创作《夜行集》的缘起、内容梗概及名家评价。
[关键词]周而复;夜行集;内容梗概;名家评价
周而复()原名周祖武,笔名周而复、吴疑、萄寰,室名北望楼,安徽省旌德县人(长于南京),现代著名作家、诗人、书法家、社会活动家。他才识超凡,饱浸旧学,仰以察古,俯以视今,一生创作不辍,兼综诸体,甚至还擅长书法艺术。他创作时间跨度70年,作品体载涉猎小说、诗歌、散文、戏剧、文学评论、童话、报告文学和回忆录等,凡28部,计1200万字。他主要以小说名世,在20世纪中国文学流变的历史上,周而复的名字永远是和《上海的早晨》这部长篇巨构宏著联系在一起,佳评迭起,久负盛名。但鲜为人知他却是一位诗人。第一部专著却是诗集《夜行集》,既是学生时代创作的唯一一部短诗集,又是他的代表作。
周而复日生于南京一个小职员家庭,祖籍安徽旌德。父亲周熙培,初从商,后为旧政府小职员,能诗善画。周丽复幼年时,家庭贫困,父亲无法供给他上正式学校,只好从师受读,在私塾读“四书五经”。八九岁时就开始接触中国古典作家作品,熟读甚至背诵他们的诗歌和散文。十岁前后就读《三国演义》、《水浒传》和《红楼梦》等中国著名的长篇小说,接着阅读”五四“运动以后的新文艺作品,如鲁迅、郭沫若和茅盾的著作,以及外国古典作家的作品,如托尔斯泰、巴尔扎克、福楼拜和果戈理的小说,莎士比亚和莫里哀的戏剧及荷马、拜伦、雪莱等人的诗篇。周而复曾说:“小时父亲对我也有一定的影响。他是一个小职员,很喜欢作1日诗,对古典文学,特别是散文,如文起八代之衰的韩愈和柳宗元、欧阳修、苏东坡的文章他都爱读。所以除了跟私塾老师学习之外,我也受了父亲的熏陶。”
1929年入南京青年会中学,“中学时代,通过当时文学研究会、创造社的介绍,还读了一些旧俄、法国、英国和北欧国家的作品。中国旧的学习方法要背书,不懂也要背,真是苦事,背了以后才慢慢懂了。”中学时代他就开始写短文在报刊上发表。1933年秋,考入上海光华大学英国文学系,参加左翼文艺活动,并开始写作诗歌和小说。1936年4月,同田间等合编《文学丛报》,提出文学工作者宣告,发表对形势和文学主张;同年6月,与欧阳山等编辑《小说家》月刊,发表了萧军、沙汀、艾芜、周文等人的文学座谈以及纪念鲁迅的回忆文章。同年同月,以“文学丛报”社名义,自费出版了诗集《夜行集》。
1938年夏,大学毕业后到延安,任陕甘宁边区文化协会文化顾问委员会主任;同年10月,参加由陕甘宁边区文化界救亡会文艺突出社编辑《文艺突击》半月刊。1939年秋,到晋察冀边区,参加十八集团军总政治部文艺小组,赴敌后晋察冀民主抗日根据地,在晋察冀军区做文艺宣传工作。19420年冬返回延安。1943年人中共中央党校学习。1944年11月,为纪念白求恩逝世五周年,也是他在中共中央党校学习,组织上给他的创作任务,除了写秧歌剧和报告文学外还写了《诺尔曼·白求恩断片》,是中国第一部反映白求恩生平作品。在延安《解放日报》发表后,于1945年3月,由八路军联防政治部正式出版。报道了白求愚大夫深入抗战为中华民族独立解放事业献身感人事迹,是40年代解放区有影响的报告文学之一。1944年冬,从延安到重庆,担任中央机关杂志《群众》半月刊编辑。1945年8月,由重庆新华日报图书课出版《秧歌剧初集》;同年9月,由重庆编译所出版短篇小说集《第十三粒子弹》;同年11月,由重庆作家书屋出版剧本《子弟兵》。
1946年任新华社特派员,奔赴华北、东北等地采访,写了不少揭露国民党蒋介石内战阴谋的通迅报道。同年去香港,在党领导下从事文化工作。1947年3月,由香港中国出版社出舨报告文学《松花江的风云》;同年4月,在香港参加茅盾、楼适夷主编的《小说月刊》的编辑工作,并主编《北方文丛》,编辑小说介绍解放区文艺作品;同年4月,由上海华夏书店和阳光书店分别出版短篇小说集《春荒》和报告文学《晋察冀行》;同年6月,由香港海洋书屋出版短篇小说集《高原短曲》;同年12月,由今日出版社出版报告文学《东北横断面》。1947年9月,由佳木斯东北书店再版《秧歌剧选集(二)》。1949年2月,由上海知识出版社出版长篇小说《白求恩大夫》,主要是写中国人民的朋友、国际主义战士、加拿大共产党员白求恩大夫,在抗日战争时期率领着加拿大人和美国人组成的医疗队来到我国解放区。在当时十分艰苦的条件下,他对八路军的医疗卫生工作,作出了极大的贡献,以至献出了自已的生命。这本书忠实地描写了白求恩大夫的英雄事迹,也写出了中国共产党领导的八路军和解放区人民对敌人的英勇顽强的战斗。这部作品很有影响,全国解放后,东京和莫斯科翻译出版了这部小说的日文和俄文译本。&&&1&&&&当前位置: >>
51单片机基础学习资料
51 单片机汇编语言教程:第 1 课:单片机简叙1、什么是单片机 一台能够工作的计算机要有这样几个部份构成 :CPU(进行运算、控制) 、 RAM(数据存储 ) 、ROM(程序存储 ) 、输入/输出设备(例如:串行口、并行输出口等 ) 。 在个人计算机上这些部份被分成若干块芯片 , 安装一个称之为主板的印刷线路板上 。 而在单 片机中,这些部份,全部被做到一块集成电路芯片中了,所以就称为单片(单芯片)机 , 而 且有一些单片机中除了上述部份外,还集成了其它部份如 A/D,D/A 等。 单片机是一种控制芯片,一个微型的计算机,而加上晶振,存储器,地址锁存器,逻辑 门,七段译码器(显示器 ) ,按钮(类似键盘) ,扩展芯片,接口等那是单片机系统。 PC 中的 CPU 一块就要卖几千块钱,这么多东西做在一起,还不得买个天价!再说这块 芯片也得非常大了。 不,价格并不高,从几元人民币到几十元人民币,体积也不大,一般 用 40 脚封装,当然功能多一些单片机也有引脚比较多的,如 68 引脚,功能少的只有 10 多 个或 20 多个引脚,有的甚至只 8 只引脚。 为什么会这样呢? 功能有强弱,打个比方,市场上面有的组合音响一套才卖几百块钱 ,可是有的一台功放 机就要卖好几千。另外这种芯片的生产量很大,技术也很成熟, 51 系列的单片机已经做了 十几年,所以价格就低了。 既然如此,单片机的功能肯定不强,干吗要学它呢? 话不能这样说, 实际工作中并不是任何需要计算机的场合都要求计算机有很高的性能 , 一个 控制电冰箱温度的计算机难道要用 PIII?应用的关键是看是否够用 , 是否有很好的性能价格 比。所以 8051 出来十多年,依然没有被淘汰,还在不断的发展中。 2、MCS51 单片机和 、89C51 等的关系 我们平常老是讲 8051,又有什么 8031,现在又有 89C51、89s51、STC89C52 它们之间究竟 是什么关系? MCS51 是指由美国 INTEL 公司(对了,就是大名鼎鼎的 INTEL)生产的一系列单片机 的总称,这一系列单片机包括了好些品种,如 ,, 等, 其中 8051 是最早最典型的产品, 该系列其它单片机都是在 8051 的基础上进行功能的增 、 减、 改变而来的,所以人们习惯于用 8051 来称呼 MCS51 系列单片机,而 8031 是前些年在我国 最流行的单片机,所以很多场合会看到 8031 的名称。INTEL 公司将 MCS51 的核心技术授 权给了很多其它公司,所以有很多公司在做以 8051 为核心的单片机,当然,功能或多或少 有些改变,以满足不同的需求,其中 89C51 就是这几年在我国非常流行的单片机,它是由 美国 ATMEL公司开发生产的。以后我们将用 STC89C52 单片机来完成一系列的实验。 重要说明 1、本教程是网上收整理,版权归互联网,全部免费 共享2、教程中的实验不保证 100% 100%正确,当你能认真学习时你会有 能力修正实验中的小错误。 3、请不要再问如何学单片机,如何写程序,为什么这样写程序 的问题,共享人不提供源码分析,如果你有心学单片机的,全部 由你自己自学完成4、祝你学业有成,以后多点共享各种单片机资料,使中国电子 技术更强。 51 单片机汇编语言教程:第 2 课-单片机引脚介绍STC89C52 单片机引脚功能介绍 首先我们来认识一下 51 单片机芯片的引脚图,具体功能在下面介绍。 单片机的 40 个引脚大致可分为 4 类:电源、时钟、控制和 IO 引脚。 ⒈ 电源 ⑴ VCC - 芯片电源,接+5V;当然也有 3.3V 供电的芯片。 ⑵ VSS - 接地端; ⒉ 时钟 XTAL1、XTAL2 - 晶体振荡电路反相输入端和输出端。 ⒊ 控制线控制线共有 4 根, ⑴ ALEPROG 地址锁存允许片内 EPROM 编程脉冲(旧的 AT89C51 用到,最新的 51 芯片可以在 线编程,一条 USB 线搞定单片机,下面的说明不理解的可以不用看,因为最新的 51 芯片都 没有了 VPP 功能了。 ) ① ALE 功能:用来锁存 P0 口送出的低 8 位地址 ② PROG 功能:片内有 EPROM 的芯片,在 EPROM 编程期间,此引脚输入编程脉冲。 ⑵ PSEN 外 ROM 读选通信号。 ⑶ RSTVPD 复位备用电源。 ① RST(Reset)功能:复位信号输入端。 ② VPD 功能:在 Vcc 掉电情况下,接备用电源。 ⑷ EAVpp 内外 ROM 选择片内 EPROM 编程电源。 ① EA 功能:内外 ROM 选择端。 ② Vpp 功能:片内有 EPROM 的芯片,在 EPROM 编程期间,施加编程电源 Vpp。 ⒋ IO 线 STC89C52 共有 4 个 8 位并行 IO 端口:P0、P1、P2、P3 口,共 32 个引脚。P3 口还具有第二 功能,用于特殊信号输入输出和控制信号(属控制总线 ) 。〈51 单片机引脚图及引脚功能〉 拿到一块芯片,想要使用它,首先必须要知道怎样连线 ,我们用的一块称之为 STC89C52 的芯片,下面我们就看一下如何给它连线。 1、 电源: 这当然是必不可少的了 。 单片机使用的是 5V 电源, 其中正极接 40 管脚, (地) 负极 接 20 管脚。 2、 振蒎电路:单片机是一种时序电路 ,必须供给脉冲信号才能正常工作 ,在单片机内部已 集成了振荡器,使用晶体振荡器,接 18、19 脚。只要买来晶体震荡器 ,电容,连上就能了, 按图 1 接上即可。 3、 复位管脚:按图 1 中画法连好,至于复位是何含义及为何需要复要复位 ,在单片机功能 中介绍。 4、 EA 管脚:EA 管脚接到正电源端。 至此,一个单片机就接好 ,通上电,单片机就开始工 作了。 我们的第一个任务是要用单片机点亮一只发光二极管 LED,显然,这个 LED 必须要和单 片机的某个管脚相连, 不然单片机就没法控制它了 , 那么和哪个管脚相连呢?单片机上除了 刚才用掉的 5 个管脚,还有 35 个, 我们将这个 LED 和 1 脚相连。 (见图 1,其中 R1 是限流电阻)〈单片机接线图〉图 1 按照这个图的接法,当 1 脚是高电平时,LED 不亮,只有 1 脚是低电平时,LED 才发亮。 因此要 1 脚我们要能够控制,也就是说,我们要能够让 1 管脚按要求变为高或低电平 。即然 我们要控制 1 脚,就得给它起个名字,总不能就叫它一脚吧?叫它什么名字呢?设计 51 芯 片的 INTEL 公司已经起好了,就叫它 P1.0,这是规定,不能由我们来更改。 名字有了,我们又怎样让它变 '高'或变'低'呢?叫人做事,说一声就能,这叫发布命令 , 要 计算机做事,也得要向计算机发命令 ,计算机能听得懂的命令称之为计算机的指令 。让一个 管脚输出高电平的指令是 SETB,让一个管脚输出低电平的指令是 CLR。因此,我们要 P1.0 输出高电平,只要写 SETB P1.0,要 P1.0 输出低电平,只要写 CLR P1.0 就能了。 现在我们已经有办法让计算机去将 P10 输出高或低电平了, 但是我们怎样才能计算机执 行这条指令呢?总不能也对计算机也说一声了事吧。要解决这个问题,还得有几步要走 。 第 一,计算机看不懂 SETB CLR 之类的指令,我们得把指令翻译成计算机能懂的方式,再让计 算机去读。计算机能懂什么呢?它只懂一样东西 ――数字 0、1。因此我们得把 SETB P1.0 变为( D2H,90H ) ,把 CLR P1.0 变为 (C2H,90H ) ,至于为什么是这两个数字,这也是 由 51 芯片的设计者--INTEL 规定的,我们暂不去研究。第二步,在得到这两个数字后 ,怎样让 这两个数字进入单片机的内部呢?这要借助于一个硬件工具编程器 。 如果你还不知道是什么 是编程器, 我来介绍一下, 就是把你在电脑上写出来来的代码用汇编器等编译器生成的一个 目标烧写到单片机的 eprom 里面去的工具,80c51 这种类型的单片机编程是一件很麻烦的事 情,必要要先装到编程器上编程后才能在设备上使用,而目前最新的 STC89C52 单片机居然 在线编程(isp)功能,不用拔出来利用简单的电路就可以实现把代码写入单片机内部,我 们将编程器与电脑连好 (实验板内部已集成编程器 ), 运行编程器的软件, 然后在编缉区内写 入(D2H,90H) 。(图 2) 写入程序后, 我们看什么灯都不亮?这就对了 , 因为我们写进去的指令就是让 P10 输出高电 平,灯当然不亮,要是亮就错了。现在我们重新回到编程软件上,将编缉区的内容改为 (C2H,90H) ,也就是 CLR P1.0,写入单片机内,现在好了,灯亮了。因为我们写入的() 就是让 P10 输出低电平的指令。这样我们看到,硬件电路的连线没有做任何改变 ,只要改变 写入单片机中的内容,就能改变电路的输出效果。 总结:我们收集这个资料主要是讲解用汇编语言来学单片机的,这是最基础的教程,学 校教学也是用汇编语言上课的 ,学了这个课程,你不但学会了单片机硬件知识 ,同时你也无 意中学会了汇编语言,现在淘宝上出售的 51 实验板,都是基于 C 语言学习的,慧净实验板 具有汇编与 C 语言实验,一个正真的单片机高手 ,一会要学会汇编语言 ,在这里,请有机会 看到的同学,都能认真的把汇编学好,用好。同时可以配套慧净的 HJ-1G、HJ-3G 实验板, 使用你学习单片机更容易上手,也可以到单片机学习网 WWW.HLMCU.COM 免费下载配套 的 HJ-3G 仿真电路。 51 单片机汇编语言教程:第 3 课-单片机存储器结构单片机内部存储结构分析 我们来思考一个问题,当我们在编程器中把一条指令写进单片要内部,通电后,单片机 就可以执行这条指令, 那么这条指令一定保存在单片机的某个地方 , 并且这个地方在单片机 掉电后依然可以保持这条指令不会丢失 , 这是个什么地方呢?这个地方就是单片机内部的只 读存储器即 ROM(READ ONLY MEMORY) 。为什么称它为只读存储器呢?刚才我们不是明明把 两个数字写进去了吗?原来在 STC89C52 中的 ROM 是一种电可擦除的 ROM,称为 FLASH ROM, 刚才我们是用编程器, 在特殊的条件下由外部设备对 ROM 进行写的操作, 在单片机正常工作 条件下,只能从那里面读,不能把数据写进去,所以我们还是把它称为 ROM。 数的本质和物理现象 :我们知道,计算机能进行数学运算 ,这可令我们非常的难以理解 , 计算机吗, 我们虽不了解它的组成 , 但它总只是一些电子元器件 , 怎么能进行数学运算呢?我们做数学 题如 37+45 是这样做的,先在纸上写 37,然后在下面写 45,然后大脑运算,最后写出结果, 运算的原材料:37、45 和结果:82 都是写在纸上的,计算机中又是放在什么地方呢?为了 解决这个问题,先让我们做一个实验:这里有一盏灯,我们知道灯要么亮,要么不亮,就有 两种状态,我们能用 ‘0’和‘1’来代替这两种状态,规定亮为 ‘1’ ,不亮,为‘0’ 。现在 放上两盏灯,一共有几种状态呢?我们列表来看一下:请大家自已写上 3 盏灯的情况 000 001 010 011 100 101 110 111 我们来看,这个 000,001,101 不就是我们学过的的二进制数吗?本来,灯的亮和灭只是 一种物理现象,可当我们把它们按一定的次序排好后 ,灯的亮和灭就代表数字了 。让我们再 抽象一步,灯为什么会亮呢? 是因为输出电路输出高电平 ,给灯通了电。因此,灯亮和灭就能用电路的输出是高电平还是 低电平来替代了。这样,数字就和电平的高、低联系上了。 什么是位: 通过上面的实验我们已经知道:一盏灯亮或者说一根线的电平的高低,能代表两种状态: 0 和 1。实际上这就是一个二进制位,因此我们就把一根线称之为一个 “位” ,用 BIT 表示。 什么是字节: 一根线能表达 0 和 1,两根线能表达 00,01,10,11 四种状态,也就是能表达 0 到 3 的数, 而三根能表达 0-7 的数,计算机中常常用 8 根线放在一起,同时计数,就能表过到 0-255 一共 256 种状态。这 8 根线或者 8 位就称之为一个字节( BYTE) 。不要问为什么是 8 根而不 是其它数,因为我也不知道 。 (计算机世界是一本人造的世界,不是自然界,很多事情你无 法问为什么,只能说:它是一种规定,大家在以后的学习过程中也要注意这个问题) 存储器的工作原理: 1、存储器构造 存储器就是用来存放数据的地方 。它是利用电平的高低来存放数据的 ,也就是说,它存放的 实际上是电平的高、低,而不是我们所习惯认为的 1234 这样的数字,这样,我们的一个谜 团就解开了,计算机也没什么神秘的吗。 让我们看图 2。单片机里面都有这样的存储器 ,这是一个存储器的示意图 :一个存储器就象 一个个的小抽屉,一个小抽屉里有八个小格子 ,每个小格子就是用来存放“电荷”的,电荷 通过与它相连的电线传进来或释放掉 , 至于电荷在小格子里是怎样存的 , 就不用我们操心了 , 你能把电线想象成水管 ,小格子里的电荷就象是水 ,那就好理解了。存储器中的每个小抽屉 就是一个放数据的地方,我们称之为一个 “单元” 。 有了这么一个构造,我们就能开始存放数据了,想要放进一个数据 12,也就是 , 我们只要把第二号和第三号小格子里存满电荷 , 而其它小格子里的电荷给放掉就行了(看图 3) 。可是问题出来了,看图 2,一个存储器有好多单元,线是并联的,在放入电荷的时候 , 会将电荷放入所有的单元中 , 而释放电荷的时候, 会把每个单元中的电荷都放掉 , 这样的话, 不管存储器有多少个单元 ,都只能放同一个数,这当然不是我们所希望的 ,因此,要在结构 上稍作变化,看图 2,在每个单元上有个控制线 ,我想要把数据放进哪个单元 ,就给一个信 号这个单元的控制线,这个控制线就把开关打开 ,这样电荷就能自由流动了 ,而其它单元控 制线上没有信号,所以开关不打开,不会受到影响,这样,只要控制不一样单元的控制线 , 就能向各单元写入不一样的数据了 ,同样,如果要某个单元中取数据 ,也只要打开对应的控 制开关就行了。 2、存储器译码 那么, 我们怎样来控制各个单元的控制线呢?这个还不简单 , 把每个单元元的控制线都引到 集成电路的外面不就行了吗?事情可没那么简单,一片 27512 存储器中有 65536 个单元, 把 每根线都引出来,这个集成电路就得有 6 万多个脚?不行,怎么办?要想法减少线的数量 。 我们有一种办法称这为译码 ,简单介绍一下:一根线能代表 2 种状态,2 根线能代表 4 种状 态,3 根线能代表几种,256 种状态又需要几根线代表? 8 种,8 根线,所以 65536 种状态我 们只需要 16 根线就能代表了。 3、存储器的选片及总线的概念 至此,译码的问题解决了,让我们再来关注另外一个问题。送入每个单元的八根线是用 从什么地方来的呢?它就是从计算机上接过来的 , 一般地, 这八根线除了接一个存储器之外 , 还要接其它的器件,如图 4 所示。这样问题就出来了,这八根线既然不是存储器和计算机之 间专用的,如果总是将某个单元接在这八根线上 ,就不好了,比如这个存储器单元中的数值 是 0FFH 另一个存储器的单元是 00H,那么这根线到底是处于高电平,还是低电平?岂非要 打架看谁历害了?所以我们要让它们分离 。 办法当然很简单, 当外面的线接到集成电路的管 脚进来后,不直接接到各单元去 ,中间再加一组开关(参考图 4)就行了。平时我们让开关 打开着,如果确实是要向这个存储器中写入数据 ,或要从存储器中读出数据 ,再让开关接通 就行了。这组开关由三根引线选择:读控制端、写控制端和片选端。要将数据写入片中 , 先 选中该片,然后发出写信号,开关就合上了,并将传过来的数据(电荷)写入片中。如果要 读,先选中该片,然后发出读信号,开关合上,数据就被送出去了。注意图 4,读和写信号 同时还接入到另一个存储器 ,但是由于片选端不一样 ,所以虽有读或写信号 ,但没有片选信 号,所以另一个存储器不会“误会”而开门,造成冲突。那么会不一样时选中两片芯片呢? 只要是设计好的系统就不会 ,因为它是由计算控制的 ,而不是我们人来控制的 ,如果真的出 现同时出现选中两片的情况,那就是电路出了故障了,这不在我们的讨论之列。 从上面的介绍中我们已经看到,用来传递数据的八根线并不是专用的,而是很多器件大 家共用的,所以我们称之为数据总线 ,总线英文名为 BUS,总即公交车道,谁者能走。而十 六根地址线也是连在一起的,称之为地址总线。 半导体存储器的分类 按功能能分为只读和随机存取存储器两大类。所谓只读,从字面上理解就是只能从里面读 , 不能写进去,它类似于我们的书本 ,发到我们手回之后 ,我们只能读里面的内容 ,不能随意 更改书本上的内容。只读存储器的英文缩写为 ROM(READ ONLY MEMORY) 所谓随机存取存储器,即随时能改写,也能读出里面的数据 ,它类似于我们的黑板 ,我能随 时写东西上去, 也能用黑板擦擦掉重写 。 随机存储器的英文缩写为 RAM( READ RANDOM MEMORY) 这两种存储器的英文缩写一定要记牢。 注意: 所谓的只读和随机存取都是指在正常工作情况下而言 , 也就是在使用这块存储器的时 候,而不是指制造这块芯片的时候 。不然,只读存储器中的数据是怎么来的呢?其实这个道 理也很好理解,书本拿到我们手里是不能改了 ,能当它还是原材料――白纸的时候,当然能 由印刷厂印上去了。 顺便解释一下其它几个常见的概念。 PROM,称之为可编程存储器。这就象我们的练习本,买来的时候是空白的,能写东西上去 , 可一旦写上去,就擦不掉了,所以它只能用写一次,要是写错了,就报销了。 EPROM,称之为紫外线擦除的可编程只读存储器。它里面的内容写上去之后,如果觉得不满 意,能用一种特殊的办法去掉后重写,这就是用紫外线照射,紫外线就象 “消字灵” ,能把 字去掉,然后再重写。当然消的次数多了,也就不灵光了,所以这种芯片能擦除的次数也是 有限的――几百次吧。FLASH,称之为闪速存储器,它和 EPROM 类似,写上去的东西也能擦 掉重写,但它要方便一些,不需要光照了,只要用电学办法就能擦除,所以就方便许多 , 而 且寿面也很长(几万到几十万次不等 ) 。 再次强调, 这里的所有的写都不是指在正常工作条件下 。 不管是 PROM、 EPROM 还是 FLASH ROM, 它们的写都要有特殊的条件 ,一般我们用一种称之为“编程器”的设备来做这项工作 ,一旦 把它装到它的工作位置,就不能随便改写了。 总结:没有学过模数的同学看到这一课可能觉得学单片机这么难呀 ,要记这么多东西 , 其实,上面的我们不需要记住,你只要能看一次,理解一次就可以了,有时间我们用实验 板多做实验,加深对单片机的硬件认识。内部存储结构到时你自然就会明白,单片机内部 是如何工作的,对我们来说不重要,最重要的是我们如何写程序来控制单片机的输入,输 出,实现我们需要的功能。 51 单片机汇编语言教程:第 4 课-第一个单片机小程序上一次我们的程序实在是没什么用 , 要灯亮还要重写一下片子 , 下面我们要让灯持续地 闪烁,这就有一定的实用价值了 ,比如能把它当成汽车上的一个信号灯用了 。怎样才能让灯 持续地闪烁呢?实际上就是要灯亮一段时间 , 再灭一段时间, 也就是说要 P10 持续地输出高 和低电平。怎样实现这个要求呢?请考虑用下面的指令是否可行: SETB P10 CLR P10 …… 这是不行的,有两个问题,第一,计算机执行指令的时间很快,执行完 SETB P10 后,灯是 灭了,但在极短时间(微秒级)后,计算机又执行了 CLR P10 指令,灯又亮了,所以根本分 辨不出灯曾灭过。第二,在执行完 CLR P10 后,不会再去执行 SETB P10 指令,所以以后再 也没有机会让灭了。 为了解决这两个问题,我们能做如下设想,第一,在执行完 SETB P10 后,延时一段时 间(几秒或零点几秒)再执行第二条指令,就能分辨出灯曾灭过了 。第二在执行完第二条指 令后,让计算机再去执行第一条指令 ,持续地在原地兜圈,我们称之为循环,这样就能完成 任务了。 以下先给出程序(后面括号中的数字是为了便于讲解而写的,实际不用输入 ) : ;主程序: LOOP: SETB P10 ; (1) LCALL DELAY ; (2) CLR P10 ; (3) LCALL DELAY ; (4) AJMP LOOP ; (5) ;以下子程序 DELAY: MOV R7,#250 ; (6) D1: MOV R6,#250 ; (7) D2: DJNZ R6,D2 ; (8) DJNZ R7,D1 ; (9) RET ; (10) END ; (11) 按上面的设想分析一下前面的五条指令。 第一条是让灯灭,第二条应当是延时,第三条是让灯亮,第四条和第二条一模一样 , 也 是延时, 第五条应当是转去执行第一条指令 。 第二和第四条实现的原理稍后谈 , 先看第五条, LJMP 是一条指令,意思是转移,往什么地方转移呢?后面跟的是 LOOP,看一下,什么地方 还有 LOOP,对了,在第一条指令的前面有一个 LOOP,所以很直观地,我们能认识到,它要 转到第一条指令处。这个第一条指令前面的 LOOP 被称之为标号,它的用途就是给这一行起 一个名字,便于使用。是否一定要给它起名叫 LOOP 呢?当然不是,起什么名字,完全由编 程序的人决定,能称它为 A,X 等等,当然,这个时候,第五条指令 LJMP 后面的名字也得跟 着改了。 第二条和第四条指令的用途是延时 ,它是怎样实现的呢?指令的形式是 LCALL,这条指 令称为调用子程序指令,看一下指令后面跟的是什么, DELAY,找一下 DELAY,在第六条指 令的前面,显然,这也是一个标号。这条指令的作用是这样的 :当执行 LCALL 指令时,程序 就转到 LCALL 后面的标号所标定的程序处执行,如果在执行指令的过程中遇到 RET 指令, 则 程序就返回到 LCALL 指令的下面的一条指令继续执行 , 从第六行开始的指令中 , 能看到确实 有 RET 指令。在执行第二条指令后 ,将转去执行第6条指令 ,而在执行完6,7,8,9条 指令后将遇到第10条令: RET,执行该条指令后,程序将回来执行第三条指令,即将 P10 清零,使灯亮,然后又是第四条指令,执行第四条指令就是转去执行第 6,7,8,9,10 条 指令,然后回来执行第 5 条指令,第 5 条指令就是让程序回到第 1 条开始执行,如此周而复 始,灯就在持续地亮、灭了。 在标号 DELAY 标志的这一行到 RET 这一行中的所有程序, 这是一段延时程序, 大概延时 零点几秒,至于具体的时间,以后我们再学习如何计算。 程序的最后一行是 END,这不是 一条指令,它只是告诉我们程序到此结束,它被称为伪指令。 单片机内部结构分析: 为了知道延时程序是如何工作的 , 我们必需首先了解延时程序中出现 的一些符号,就从 R1 开始,R1 被称之为工作寄存器。什么是工作寄存器呢?让我们从现实 生活中来找找答案。如果出一道数学题: 123+567,让你回答结果是多少,你会马上答出 是 690,再看下面一道题:123+567+562,要让你要上回答,就不这么不难了吧?我们会怎样做 呢?如果有张纸, 就不难了, 我们先算出 123+567=690, 690 写在纸上, 把 然后再算 690+562 得到结果是 1552。这其中 1552 是我们想要的结果 ,而 690 并非我们所要的结果 ,但是为了 得到最终结果,我们又不得不先算出 690,并记下来,这其实是一个中间结果 ,计算机中做 运算和这个类似,为了要得到最终结果 ,一般要做很多步的中间结果 ,这些中间结果要有个 地方放才行, 把它们放哪呢?放在前面提到过的 ROM 中能吗?显然不行, 因为计算机要将结 果写进去,而 ROM 是不能写的,所以在单片机中另有一个区域称为 RAM 区(RAM 是随机存取 存储器的英文缩写) ,它能将数据写进去。 特别地,在 MCS-51 单片机中,将 RAM 中分出一 块区域,称为工作寄存器区 。 51 单片机汇编语言教程:第 5 课-单片机延时程序分析上一次课中,我们已经知道,程序中的符号 R7、R6 是代表了一个个的 RAM 单元,是用来放 一些数据的,下面我们再来看一下其它符号的含义。 DELAY: MOV R7,#250 ; (6) D1: MOV R6,#250 ; (7) D2: DJNZ R6,D2 ; (8) DJNZ R7,D1 ; (9) RET ; (10) 〈单片机延时程序〉 MOV:这是一条指令,意思是传递数据。说到传递,我们都很清楚,传东西要从一本人的手 上传到另一本人的手上 , 也就是说要有一个接受者 , 一个传递者和一样东西 。 从指令 MOV R7, #250 中来分析, R7 是一个接受者, 250 是被传递的数,传递者在这条指令中被省略了(注 意:并不是每一条传递指令都会省的,事实上大部份数据传递指令都会有传递者 ) 。它的意 义也很明显: 将数据 250 送到 R7 中去, 因此执行完这条指令后 , 单元中的值就应当是 250。 R7 在 250 前面有个#号, 这又是什么意思呢?这个 #就是用来说明 250 就是一个被传递的东西本 身,而不是传递者。那么 MOV R6,#250 是什么意思,应当不用分析了吧。 DJNZ:这是另一条指令,我们来看一下这条指令后面跟着的两个东西,一个是 R6,一个是 D2,R6 我们当然已知是什么了 ,查一下 D2 是什么。D2 在本行的前面,我们已学过,这称之 为标号。标号的用途是什么呢?就是给本行起一个名字。 DJNZ 指令的执行过程是这样的, 它将其后面的第一个参数中的值减 1,然后看一下,这个值是否等于 0,如果等于 0,就往 下执行,如果不等于 0,就转移,转到什么地方去呢?可能大家已猜到了 ,转到第二个参数 所指定的地方去(请大家用自已的话讲一下这条语句是怎样执行的 ) 。本条指令的最终执行 结果就是,在原地转圈 250 次。 执行完了 DJNZ R6,D2 之后(也就是 R6 的值等于 0 之后) ,就会去执行下面一行,也就 是 DJNZ R7,D1,请大家自行分析一下这句话执行的结果 。 (转去执行 MOV R6,#250,同时 R7 中的值减 1) ,最终 DJNZ R6,D2 这句话将被执行 00 次,执行这么多次同一条指 令干吗?就是为了延时。 一个问题:如果在 R6 中放入 0,会有什么样的结果。 二、时序分析: 前面我们介绍了延时程序 ,但这还不完善,因为,我们只知道 DJNZ R6,D2 这句话会被执行 62500 次,但是执行这么多次需要多长时间呢?是否满足我们的要求呢?我们还不知道 ,所 以下面要来解决这个问题。 先提一个问题:我们学校里什么是最重要的 。 (铃声)校长能出差,老师能休息,但学校一 日无铃声必定大乱。整个学校就是在铃声的统一指挥下,步调一致,统一协调地工作着 。 这 个铃是按一定的时间安排来响的,我们能称之为 “时序��时间的次序” 。一个由人组 成的单位尚且要有一定的时序 ,计算机当然更要有严格的时序 。事实上,计算机更象一个大 钟,什么时候分针动,什么时候秒针动,什么时候时针动,都有严格的规定,一点也不能乱。 计算机要完成的事更复杂,所以它的时序也更复杂。 我们已知, 计算机工作时, 是一条一条地从 ROM 中取指令, 然后一步一步地执行 , 我们规定: 计算机访问一次存储器的时间 , 称之为一个机器周期 。 这是一个时间基准, 好象我们人用 “秒” 作为我们的时间基准一样,为什么不干脆用 “秒” ,多好,很习惯,学下去我们就会知道用 “秒”反而不习惯。 一个机器周期包括 12 个时钟周期。下面让我们算一下一个机器周期是多长时间吧。设一个 单片机工作于 12M 晶体震荡器, 它的时钟周期是 112 (微秒) 它的一个机器周期是 12 。 (112) 也就是 1 微秒。 (请计算一个工作于 6M 晶体震荡器的单片机,它的机器周期是多少 ) 。 MCS-51 单片机的所有指令中,有一些完成得比较快,只要一个机器周期就行了,有一些完 成得比较慢,得要 2 个机器周期,还有两条指令要 4 个机器周期才行。这也不难再解,不是 吗?我让你扫地的执行要完成总得比要你完成擦黑板的指令时间要长 。 为了恒量指令执行时 间的长短, 又引入一个新的概念: 指令周期。 所谓指令周期就是指执行一条指令的时间 。 INTEL 对每一条指令都给出了它的指令周期数 ,这些数据,大部份不需要我们去记忆 ,但是有一些 指令是需要记住的,如 DJNZ 指令是双周期指令。 下面让我们来计算刚才的延时 。 首先必须要知道晶体震荡器的频率 , 我们设所用晶体震荡器 为 12M,则一个机器周期就是 1 微秒。而 DJNZ 指令是双周期指令,所以执行一次要 2 个微 秒。一共执行 62500 次,正好 125000 微秒,也就是 125 毫秒。 练习:设计一个延时 100 毫秒的延时程序。 要点分析:1、一个单元中的数是否能超过 255。2、如何分配两个数。 三、复位电路 一、复位方式 ⒈ 复位条件 RST 引脚保持 2 个机器周期以上的高电平。 ⒉ 复位电路〈单片机复位电路〉 ⒊ 复位后 CPU 状态 PC: 0000H Acc: 00H B: 00H PSW: 00H TMOD: 00H TCON: 00H TH0: 00H TL0: 00H SP: 07H DPTR:0000H P0~P3:FFH IP:×××00000B IE:0××00000BTH1: 00H TL1: 00H SCON: 00H SBUF: 不定 PCON: 0×××0000B任何单片机在工作之前都要有个复位的过程 , 复位是什么意思呢?它就象是我们上课之前打 的预备铃。预备铃一响,大家就自动地从操场、其它地方进入教室了,在这一段时间里 , 是 没有老师干预的,对单片机来说,是程序还没有开始执行 ,是在做准备工作。显然,准备工 作不需要太长的时间,复位只需要 5ms 的时间就能了。如何进行复位呢?只要在单片机 的 RST 管脚上加上高电平,就能了,按上面所说,时间不少于 5ms。为了达到这个要求,能用 很多种办法,这里供给一种供参考,见图 1。实际上,我们在上一次实验的图中已见到过了 。 这种复位电路的工作原理是:通电时,电容两端相当于是短路,于是 RST 管脚上为高电平, 然后电源通过电阻对电容充电 ,RST 端电压慢慢下降,降到一定程序,即为低电平,单片机 开始正常工作。 51 单片机汇编语言教程:第 6 课--单片机并行口结构上两次我们做过两个实验 ,都是让 P1.0 这个管脚使灯亮,我们能设想:既然 P1.0 能让 灯亮,那么其它的管脚可不能呢?看一下图 1,它是 8031 单片机管脚的说明 ,在 P1.0 旁边 有 P1.1,P1.2….P1.7,它们是否都能让灯亮呢?除了以 P1 开头的外,还有以 P0,P2,P3 开头的,数一下,一共是 32 个管脚,前面我们以学过 7 个管脚,加上这 32 个这 39 个了。 它们都以 P 字开头, 只是后面的数字不一样 , 它们是否有什么联系呢?它们能不能都让灯亮 呢?在我们的实验板上,除了 P10 之外,还有 P11��P17 都与 LED 相连,下面让我们 来做一个实验,程序如下: MAIN: MOV P1,#0FFH LCALL DELAY MOV P1,#00H LCALL DELAY LJMP MAIN DELAY:MOV R7,#250 D1: MOV R6,#250 D2: DJNZ R6,D2 DJNZ R7,D1 RET END 将这段程序转为机器码 ,用编程器写入单片机中 ,结果如何?通电以后我们能看到 8 只 LED 全部在闪动。因此,P10��P17 是全部能点亮灯的。事实上,凡以 P 开头的这 32 个管 脚都是能点亮灯的,也就是说:这 32 个管脚都能作为输出使用,如果不用来点亮 LED,能 用来控制继电器,能用来控制其它的执行机构。 程序分析:这段程序和前面做过的程序比较 ,只有两处不一样:第一句:原来是 SETB P1.0, 现在改为 MOV P1,#0FFH,第三句:原来是 CLR P1.0,现在改为 MOV P1.0,#00H。从中能 看出,P1 是 P1.0��P1.7 的全体的代表,一个 P1 就表示了所有的这八个管脚了。当 然用的指令也不一样了,是用 MOV 指令。为什么用这条指令?看图 2,我们把 P1 作为一个 整体,就把它当作是一个存储器的单元,对一个单元送进一个数能用 MOV 指令。 二、第四个实验 除了能作为输出外, 32 个管脚还能做什么呢?下面再来做一个单片机实验 , 这 源程序如下: MAIN: MOV P3,#0FFH LOOP: MOV A,P3 MOV P1,A LJMP LOOP 先看一下这个实验的结果 :所有灯全部不亮,然后我按下一个按钮 ,第()个灯亮了,再按 下另一个按钮,第()个灯亮了,松开按钮灯就灭了。从这个实验现象结合电路来分析一下 程序。 从硬件电路的连线能看出 ,有四个按钮被接入到 P3 口的 P32,P33,P34,P35。第一条指令 的用途我们能猜到:使 P3 口全部为高电平。第二条指令是 MOV A,P3,其中 MOV 已经见, 是送数的意思,这条指令的意思就是将 P3 口的数送到 A 中去,我们能把 A 当成是一个中间 单元(看图 3) ,第三句话是将 A 中的数又送到 P1 口去,第四句话是循环,就是持续地重复 这个过程,这我们已见过。当我们按下第一个按钮时,第( 3)只灯亮了,所以 P12 口应当 输出是低电平,为什么 P12 口会输出低电平呢?我们看一下有什么被送到了 P1 口,只有从 P3 口进来的数送到 A,又被送到了 P1 口,所以,肯定是 P3 口进来的数使得 P12 位输出电平 的。P3 口的 P32 位的按钮被按下,使得 P32 位的电平为低,通过程序,又使 P12 口输出低 电平,所以 P3 口起来了一个输入的作用。验证:按第二、三、四个按钮,同时按下 2 个、 3 个、4 个按钮都能得到同样的结论,所以 P3 口确实起到了输入作用,这样,我们能看到 , 以 P 字开头的管脚,不仅能用作输出,还能用作输入,其它的管脚是否能呢?是的,都能 。 这 32 个管脚就称之为并行口,下面我们就对并行口的结构作一个分析,看一下它是怎样实 现输入和输出的。 并行口结构分析: 1、 输出结构并行口结构图 先看 P1 口的一位的结构示意图(只画出了输出部份) :从图中能看出,开关的打开和合上代 表了管脚输出的高和低 ,如果开关合上了,则管脚输出就是低,如果开关打开了,则输出高 电平,这个开关是由一根线来控制的 ,这根数据总线是出自于 CPU,让我们回想一下,数据 总线是一根大家公用的线 ,很多的器件和它连在一起 ,在不一样的时候,不一样的器件当然 需要不一样的信号,如某一时刻我们让这个管脚输出高电平 ,并要求保持若干时间 ,在这段 时间里,计算机当然在忙个不停 ,在与其它器件进行联络 ,这根控制线上的电平未必能保持 原来的值不变,输出就会发生变化了。怎么解决这个问题呢?我们在存储器一节中学过 , 存 储器中是能存放电荷的,我们不妨也加一个小的存储器的单元,并在它的前面加一个开关 , 要让这一位输出时,就把开关打开,信号就进入存储器的单元 ,然后马上关闭开关,这样这 一位的状态就被保存下来 , 直到下一次命令让它把开关再打开为止 。 这样就能使这一位的状 态与别的器件无关了,这么一个小单元,我们给它一个很形象的名字,称之为 “锁存器” 。 2、输入结构 这是并行口的一位的输出结构示意图 ,再看,除了输出之外,还有两根线,一根从外部管脚 接入,另一根从锁存器的输出接出 ,分别标明读管脚和读锁存器 。这两根线是用于从外部接 收信号的,为什么要两根呢?原来,在 51 单片机中输入有两种方式,分别称为 ‘读管脚’ 和‘读锁存器’ ,第一种方式是将管脚作为输入,那是真正地从外部管脚读进输入的值,第 二种方式是该管脚处于输出状态时 , 有时需要改变这一位的状态 , 则并不需要真正地读管脚 状态,而只是读入锁存器的状态,然后作某种变换后再输出。 请注意输入结构图, 如果将这一根引线作为输入口使用 , 我们并不能保证在任何时刻都能得 到正确的结果(为什么?)参考图 2 输入示意图。接在外部的开关如果打开 ,则应当是输入 1,而如果闭合开关,则输入 0,但是,如果单片机内部的开关是闭合的,那么不管外部的 开关是开还是闭,单片机接受到的数据都是 0。可见,要让这一端口作为输入使用 ,要先做 一个‘准备工作’ ,就是先让内部的开关断开 ,也就是让端口输出‘1’才行。正因为要先做 这么一个准备工作,所以我们称之为 “准双向 IO 口” 。 以上是 P1 口的一位的结构, P1 口其它各位的结构与之相同,而其它三个口: P0、P2、P3 则除入作为输入输出口之外还有其它用途 ,所以结构要稍复杂一些 ,但其用于输入、输出的 结构是相同的。看图( ) 。对我们来说,这些附加的功能不必由我们来控制,所以我们就不 去关心它了。推荐使用慧净 51 实验板。推荐 51 学习网 WWW.HLMCU.COM 淘宝网:http://shop.taobao.com/ 51 单片机汇编语言教程:第 7 课--单片机的特殊功能寄存器通过前面的学习,我们已知单片机的内部有 ROM、有 RAM、有并行 IO 口,那么,除了这 些东西之外,单片机内部究竟还有些什么 ,这些个零碎的东西怎么连在一起的 ,让我们来对 单片机内部的寄存器作一个完整的功能分析吧! 下图中我们能看出,在 51 单片机内部有一个 CPU 用来运算、控制,有四个并行 IO 口, 分别是 P0、P1、P2、P3,有 ROM,用来存放程序,有 RAM,用来存放中间结果 ,此外还有定 时计数器,串行 IO 口,中断系统,以及一个内部的时钟电路 。在一个 51 单片机的内部包含 了这么多的东西。单片机内部结构图 对上面的图进行进一步的分析,我们已知,对并行 IO 口的读写只要将数据送入到对应 IO 口的锁存器就能了,那么对于定时计数器,串行 IO 口等怎么用呢?在单片机中有一些独立 的存储单元是用来控制这些器件的 ,被称之为特殊功能寄存器(SFR) 。事实上,我们已接触 过 P1 这个特殊功能寄存器了,还有哪些呢?看下表 1 表1 特殊功能寄存器地址映象表(一)特殊功能寄存器地址映象表(二)特殊功能寄存器地址映象表(三)下面,我们介绍一下几个常用的 SFR,看图 2。 ACC:累加器,常常用 A 表示。这是个什么东西,可不能从名字上理解,它是一个寄存器, 而不是一个做加法的东西 , 为什么给它这么一个名字呢?或许是因为在运算器做运算时其中 一个数一定是在 ACC 中的缘故吧。它的名字特殊,身份也特殊,稍后我们将学到指令 ,能发 现,所有的运算类指令都离不开它。 2、B:一个寄存器。在做乘、除法时放乘数或除数,不做乘除法时,随你怎么用。 3、PSW:程序状态字。这是一个很重要的东西,里面放了 CPU 工作时的很多状态,借此 , 我 们能了解 CPU 的当前状态,并作出对应的处理。它的各位功能请看表 2表2 PSW 也称为标志寄存器,了解这个对于了解单片机原理非常的重要 ,存放各有关标志。其结 构和定义如下:下面我们逐一介绍 sfr 各位的用途 (1)CY:进位标志。用于表示 Acc.7 有否向更高位进位 。8051 中的运算器是一种 8 位的运 算器, 我们知道, 位运算器只能表示到 0-255, 8 如果做加法的话, 两数相加可能会超过 255, 这样最高位就会丢失,造成运算的错误,怎么办?最高位就进到这里来。这样就没事了。 例:78H+97H(10111) (2)AC:辅助进位标志也叫半进位标志。 用于表示 Acc.3 有否向 Acc.4 进位 例:57H+3AH(11010) (3)F0:用户标志位,由我们(编程人员)决定什么时候用,什么时候不用。 (4)RS1、RS0:工作寄存器组选择位。这个我们已知了。 RS1、RS0 = 00 ―― 0 区(00H~07H) RS1、RS0 = 01 ―― 1 区(08H~0FH) RS1、RS0 = 10 ―― 2 区(10H~17H) RS1、RS0 = 11 ―― 3 区(18H~1FH) (5)0V:溢出标志位。 表示 Acc 在有符号数算术运算中的溢出 ,什么是溢出我们稍后再谈 吧。 (6)P:奇偶校验位:它用来表示 ALU 运算结果中二进制数位 “1”的个数的奇偶性。若为 奇数,则 P=1,不然为 0。 例:某运算结果是 78H() ,显然 1 的个数为偶数,所以 P=0。 4、DPTR(DPH、DPL) :数据指针,能用它来访问外部数据存储器中的任一单元,如果不用 , 也能作为通用寄存器来用,由我们自已决定如何使用。 16 位,由两个 8 位寄存器 DPH、DPL 组成。主要用于存放一个 16 位地址,作为访问外部存储器(外 RAM 和 ROM)的地址指针。 5、P0、P1、P2、P3:这个我们已经知道,是四个并行输入输出口的寄存器。它里面的内容 对应着管脚的输出。 6、SP:堆栈指针。 (专用于指出堆栈顶部数据的地址 。 ) 堆栈介绍:日常生活中,我们都注意到过这样的现象,家里洗的碗,一只一只摞起来, 最晚放上去的放在最上面 ,而最早放上去的则放在最下面 ,在取的时候正好相反 ,先从最上 面取,这种现象我们用一句话来概括 : “先进后出,后进先出” 。请大家想想,还有什么地方 有这种现象?其实比比皆是 ,建筑工地上堆放的砖头 、材料,仓库里放的货物,都是“先进 后出,后进先出” ,这实际是一种存取物品的规则,我们称之为 “堆栈” 。 在单片机中,我们也能在 RAM 中构造这样一个区域,用来存放数据,这个区域存放数据 的规则就是“先进后出,后进先出” ,我们称之为“堆栈” 。为什么需要这样来存放数据呢? 存储器本身不是能按地址来存放数据吗?对 , 知道了地址的确就能知道里面的内容 , 但如果 我们需要存放的是一批数据 , 每一个数据都需要知道地址那不是麻烦吗?如果我们让数据一 个接一个地放置,那么我们只要知道第一个数据所在地址单元就能了 (看图 2)如果第一个 数据在 27H,那么第二、三个就在 28H、29H 了。所以利用堆栈这种办法来放数据能简化操 作。 那么 51 中堆栈什么地方呢?单片机中能存放数据的区域有限 , 我们不能够专门分配一块 地方做堆栈,所以就在内存( RAM)中开辟一块地方,用于堆栈,但是用内存的哪一块呢? 还是不好定,因为 51 是一种通用的单片机,各人的实际需求各不相同,有人需要多一些堆 栈,而有人则不需要那么多 ,所以怎么分配都不合适 ,怎样来解决这个问题分不好干脆就不 分了,把分的权利给用户(编程者) ,根据自已的需要去定吧 ,所以 51 单片机中堆栈的位置 是能变化的。而这种变化就体现在 SP 中值的变化,看图 2,SP 中的值等于 27H 不就相当于 是一个指针指向 27H 单元吗?当然在真正的 51 机中,开始指针所指的位置并非就是数据存 放的位置,而是数据存放的前一个位置 ,比如一开始指针是指向 27H 单元的,那么第一个数 据的位置是 28H 单元,而不是 27H 单元,为什么会这样,我们在学堆栈命令时再说明 。其它 的 SFR,我们在用到时再介绍。 51 单片机汇编语言教程:8 课单片机寻址方式与指令系统通过前面的学习, 我们已经了解了单片机内部的结构 , 并且也已经知道, 要控制单片机, 让它为我们干活,要用指令,我们已学了几条指令,但很零散,从现在开始,我们将要系统 地学习 8051 单片机的指令部份。 一、概述 1、指令的格式 我们已知, 要让计算机做事, 就得给计算机发送各种指令, 并且我们已知, 计算机很 “笨” , 只能懂得数字,如前面我们写进机器的 75H,90H,00H 等等,所以指令的第一种格式就是机 器码格式,也说是数字的形式。但这种形式实在是为难我们人了 ,太难记了,于是有另一种 格式,助记符格式,如 MOV P1,#0FFH,这样就好记了。 这两种格式之间的关系呢,我们 不难理解,本质上它们完全等价,只是形式不一样而已。 2、汇编 我们写指令使用汇编格式 , 而计算机和单片机只懂机器码格式 , 所以要将我们写的汇编 格式的指令转换为机器码格式 ,这种转换有两种办法 :手工汇编和机器汇编 。手工汇编实际 上就是查表,因为这两种格式纯粹是格式不一样,所以是一一对应的,查一张表格就行了 。 不过手工查表总是嫌麻烦 ,所以就有了计算机软件 ,用计算机软件来替代手工查表 ,这就是 机器汇编。 二、单片机的寻址 让我们先来复习一下我们学过的一些指令: MOV P1,#0FFH,MOV R7,#0FFH 这些指令 都是将一些数据送到对应的位置中去 , 为什么要送数据呢?第一个因为送入的数能让灯全灭 掉,第二个是为了要实现延时 ,从这里我们能看出来 ,在用单片机的编程语言编程时 ,经常 要用到数据的传递, 事实上数据传递是单片机编程时的一项重要工作 , 一共有 28 条指令 (单 片机共 111 条指令) 。下面我们就从数据传递类指令开始吧。 分析一下 MOV P1,#0FFH 这条指令,我们不难得出结论,第一个词 MOV 是命令动词, 也 就是决定做什么事情的, MOV 是 MOVE 少写了一个 E,所以就是“传递” ,这就是指令,规定 做什么事情,后面还有一些参数,分析一下,数据传递必须要有一个“源”也就是你要送什 么数,必须要有一个 “目的” ,也就是你这个数要送到什么地方去,显然在上面那条单片机 指令中,要送的数(源)就是 0FFH,而要送达的地方(目的地)就是 P1 这个寄存器。在数 据传递类指令中,均将目的地写在指令的后面,而将源写在最后。 这条指令中,送给 P1 是这个数本身,换言之,做完这条指令后,我们能明确地知道 , P1 中的值是 0FFH,但是并不是任何时候都能直接给出数本身的。例如,在我们前面给出的 单片机延时程序例是这样写的: MAIN: SETB P1.0 ; (1) LCALL DELAY ; (2) CLR P1.0 ; (3) LCALL DELAY ; (4) AJMP MAIN ; (5) ;以下子程序 DELAY: MOV R7,#250 ; (6) D1: MOV R6,#250 ; (7) D2: DJNZ R6,D2 ; (8) DJNZ R7,D1 ; (9) RET END; (10) ; (11)表1 ----------------------------------------------------MAIN: SETB P1.0 ; (1) MOV 30H,#255 LCALL DELAY ; CLR P1.0 ; (3) MOV 30H,#200 LCALL DELAY ; (4) AJMP MAIN ; (5) ;以下子程序 DELAY: MOV R7,30H ; (6) D1: MOV R6,#250 ; (7) D2: DJNZ R6,D2 ; (8) DJNZ R7,D1 ; (9) RET ; (10) END ; (11) 表2 这样一来,我每次调用延时程序延时的时间都是相同的(大致都是 0.13S),如果我提出 这样的要求:灯亮后延时时间为 0.13S 灯灭,灯灭后延时 0.1 秒灯亮,如此循环,这样的程 序还能满足要求吗?不能 ,怎么办?我们能把延时程序改成这样 (见表 2):调用则见表 2 中 的主程,也就是先把一个数送入 30H,在子程序中 R7 中的值并不固定,而是根据 30H 单元 中传过来的数确定。这样就能满足要求。 从这里我们能得出结论,在数据传递中要找到被传递的数,很多时候,这个数并不能直 接给出,需要变化,这就引出了一个概念:如何寻找操作数,我们把寻找操作数所在单元的 地址称之为寻址。 在这里我们直接使用数所在单元的地址找到了操作数 , 所以称这种办法为 直接寻址。除了这种办法之外,还有一种,如果我们把数放在工作寄存器中 ,从工作寄存器 中寻找数据,则称之为寄存器寻址。例: MOV A,R0 就是将 R0 工作寄存器中的数据送到累 加器 A 中去。提一个问题:我们知道,工作寄存器就是内存单元的一部份 ,如果我们选择工 作寄存器组 0,则 R0 就是 RAM 的 00H 单元,那么这样一来, MOV A,00H,和 MOV A,R0 不 就没什么区别了吗?为什么要加以区别呢?的确,这两条指令执行的结果是完全相同的 , 都 是将 00H 单元中的内容送到 A 中去, 但是执行的过程不一样 , 执行第一条指令需要 2 个周期, 而第二条则只需要 1 个周期,第一条指令变成最终的目标码要两个字节 (E5H 00H) ,而第二 条则只要一个字节(E8h)就能了。 这么斤斤计较!不就差了一个周期吗 ,如果是 12M 的晶体震荡器的话,也就 1 个微秒时 间了,一个字节又能有多少? 不对,如果这条指令只执行一次 ,也许无所谓,但一条指令如果执行上 1000 次,就是 1 毫秒,如果要执行 1000000 万次,就是 1S 的误差,这就很可观了,单片机做的是实时控制 的事,所以必须如此“斤斤计较” 。字节数同样如此。 再来提一个问题,现在我们已知,寻找操作数能通过直接给的方式(立即寻址)和直接 给出数所在单元地址的方式(直接寻址 ) ,这就够了吗? 看这个问题,要求从 30H 单元开始,取 20 个数,分别送入 A 累加器。 就我们目前掌握的办法而言 ,要从 30H 单元取数,就用 MOV A,30H,那么下一个数呢? 是 31H 单元的,怎么取呢?还是只能用 MOV A,31H,那么 20 个数,不是得 20 条指令才能 写完吗?这里只有 20 个数,如果要送 200 个或 2000 个数,那岂不要写上 200 条或 2000 条 命令这未免太笨了吧。 为什么会出现这样的状况?是因为我们只会把地址写在指令中 , 所以 就没办法了, 如果我们不是把地址直接写在指令中 , 而是把地址放在另外一个寄存器单元中 , 根据这个寄存器单元中的数值决定该到哪个单元中取数据 , 比如, 当前这个寄存器中的值 是 30H,那么就到 30H 单元中去取,如果是 31H 就到 31H 单元中去取,就能解决这个问题了。 怎么个解决法呢?既然是看的寄存器中的值 , 那么我们就能通过一定的办法让这里面的值发 生变化,比如取完一个数后 ,将这个寄存器单元中的值加 1,还是执行同一条指令 ,可是取 数的对象却不一样了,不是吗。通过例程来说明吧。 MOV R7,#20 MOV R0,#30H LOOP:MOV A,@R0 INC R0 DJNZ R7,LOOP 这个例程中大部份指令我们是能看懂的 ,第一句,是将立即数 20 送到 R7 中,执行完后 R7 中的值应当是 20。第二句是将立即数 30H 送入 R0 工作寄存器中,所以执行完后, R0 单 元中的值是 30H,第三句,这是看一下 R0 单元中是什么值,把这个值作为地址,取这个地 址单元的内容送入 A 中,此时,执行这条指令的结果就相当于 MOV A,30H。第四句,没学 过,就是把 R0 中的值加 1,因此执行完后,R0 中的值就是 31H,第五句,学过,将 R7 中的 值减 1,看是否等于 0,不等于 0,则转到标号 LOOP 处继续执行,因此,执行完这句后 ,将 转去执行 MOV A,@R0 这句话,此时相当于执行了 MOV A,31H(因为此时的 R0 中的值已是 31H 了) ,如此,直到 R7 中的值逐次相减等于 0,也就是循环 20 次为止,就实现了我们的要 求:从 30H 单元开始将 20 个数据送入 A 中。 这也是一种寻找数据的办法,由于数据是间接地被找到的,所以就称之为间址寻址 。 注 意,在间址寻址中,只能用 R0 或 R1 存放等寻找的数据。推荐使用慧净 51 实验板。推荐 51 学习网 WWW.HLMCU.COM 淘宝网:http://shop.taobao.com/ 51单片机汇编语言教程:9课单片机数据传递类指令单片机数据传递类指令 (1)以直接地址为目的操作数的指令 MOV direct,A 例: MOV 20H,A MOV direct,Rn MOV 20H,R1 MOV direct1,direct2 MOV 20H,30H MOV direct,@Ri MOV 20H,@R1 MOV direct,#data MOV 20H,#34H (2)以间接地址为目的操作数的指令 MOV @Ri,A 例:MOV @R0,A MOV @Ri,direct MOV @R1,20H MOV @Ri,#data MOV @R0,#34H (3)十六位数的传递指令 MOV DPTR,#data16 8051是一种8位机,这是唯一的一条 16位立即数传递指令,其功能是将一个 16位的立即数送 入 DPTR 中去。其中高8位送入 DPH,低8位送入 DPL。例:MOV DPTR,#1234H,则执行完了之 后 DPH 中的值为12H,DPL 中的值为 34H。反之,如果我们分别向 DPH,DPL 送数,则结果也 一样。如有下面两条指令: MOV DPH,#35H,MOV DPL,#12H。则就相当于执行了 MOV DPTR, #3512H。 数据传递类指令综合练习: 1 2 给出每条指令执行后的结果 上机练习: (23h)=30h MOV 45H,34H MOV 12H,#34H MOV R0,#23H MOV R7,#22H MOV R1,12H MOV A,@R0 MOV 34H,@R1 (12h)=34h MOV DPTR,#6712H (R0)=23H MOV 12H,DPH (R7)=22H MOV R0,DPL (R1)=12H MOV A,@R0 (A)=30H (34H)=34H (A)=67H (R0)=12H (12H)=67H (DPTR)=6712H (45H)=34HMOV 23H,#30H 说明:用括号括起来代表内容 ,如(23H)则代表内部 RAM23H 单元中的值, (A)则代表累加 器 A 单元中的值。 进入 DOS 状态,进入 WAVE 所在的目录,例 D:\WAVE 键入 MCS51,出现如下画面&单片机数据传递指令&图1 按 File-&Open,出现对话框后,在 Name 处输入一个文件名(见图2) ,如果是下面列表中已 存在的,则打开这个文件,如果不存在这个文件,则新建一个文件(见图 3) 图2 在空白处将上面的程序输入 。见图4。用 ALT+A 汇编通过。用 F8即可单步执行,在执行过程 中注意观察屏幕左边的工作寄存器及 A 累加器中的值的变化。图4 内存中值的变化在此是看不到的 ,可以用如下方法观察(看图5) :将鼠标移到 DATA,双击, 则光标进入此行, 此时可以键盘上的上下光标键上下翻动来观察内存值的变化 。 本行的最前 面 DATA 后面的数据代表的是“一段”的开始地址,如现在为20H,再看屏幕的最上方,数字 从0到 F,显示两者相加就等于真正的地址值,如现在图上所示的内存 20H、21H、22H、23H 中的值分别是 FBH、0EH、E8H、30H。 图5 当运行完程序后,即进入它的反汇编区 ,不是我们想要的东西 。为了再从头开始,可以 用 CTRL+F2功能键复位 PC 值。 注意此时不会看到原来的窗口 , 为看到原来的窗口, 请用 ALT+4 或 ALT+5等来切换。当然以上操作也可以菜单进行。 CTRL+F2是程序复位,用 RUN 菜单。窗 口用 WINDOWS 菜单。 此次大家就用用熟这个软件吧,说实话,我并不很喜欢它,操作起来不方便,但给我 的机器只能上这个,没办法,下次再给网友单独介绍一个好一点的吧。 总结:上面用到的 DOS 软件,各位也不用找了在哪里有下载了 ,请你用学习板配套光碟 里的 KEIL 软件吧,有专门的使用方法,请自己在光碟中查看,当大家学 C 语言时,我们有 详细介绍。这一课,大家只要能认识 单片机数据传递类指令 是什么就可以了。 51单片机汇编语言教程:第10课-数据传送类指令单片机的累加器 A 与片外 RAM 之间的数据传递类指令 MOVX A,@Ri MOVX @Ri,A MOVX A,@DPTR MOVX @DPTR,A 说明: 1)在51系列单片机中,与外部存储器 RAM 打交道的只能是 A 累加器。所有需要传送入外 部 RAM 的数据必需要通过 A 送去,而所有要读入的外部 RAM 中的数据也必需通过 A 读入。在此 我们能看出内外部 RAM 的区别了, 内部 RAM 间能直接进行数据的传递 , 而外部则不行, 比如, 要将外部 RAM 中某一单元(设为0100H 单元的数据)送入另一个单元(设为 0200H 单元) 也 , 必须先将0100H 单元中的内容读入 A,然后再传送到0200H 单元中去。 要读或写外部的 RAM,当然也必须要知道 RAM 的地址,在后两条单片机指令中 ,地址是被直 接放在 DPTR 中的。而前两条指令,由于 Ri(即 R0或 R1)只是一个8位的寄存器,所以只供 给低8位地址。因为有时扩展的外部 RAM 的数量比较少,少于或等于 256个,就只需要供给 8 位地址就够了。 使用时应当首先将要读或写的地址送入 DPTR 或 Ri 中,然后再用读写命令。 例:将单片机外部 RAM 中100H 单元中的内容送入外部 RAM 中200H 单元中。 MOV DPTR,#0100H MOVX A,@DPTR MOV DPTR,#0200H MOVX @DPTR,A 程序存储器向累加器 A 传送指令 MOVC A,@A+DPTR 本指令是将 ROM 中的数送入 A 中。本指令也被称为单片机查表指令 , 说明:常用此指令来查一个已做好在 ROM 中的表格此条指令引出一个新的寻址办法 : 变址寻址。 本指令是要在 ROM 的一个地址单元中找出数据 , 显然必须知道这个单元的地址,这个单元的地址是这样确定的:在执行本指令立脚点 DPTR 中有一个数,A 中有一个数,执行指令时,将 A 和 DPTR 中的数加起为,就成为要查找的单 元的地址。 查找到的结果被放在 A 中,因此,本条指令执行前后, A 中的值不一定相同。 例:有一个数在 R0中,要求用查表的办法确定它的平方值(此数的取值范围是 0-5) MOV DPTR,#TABLE MOV A,R0 MOVC A,@A+DPTR TABLE: DB 0,1,4,9,16,25 设 R0中的值为2,送入 A 中,而 DPTR 中的值则为 TABLE,则最终确定的 ROM 单元的地址就是 TABLE+2,也就是到这个单元中去取数,取到的是 4,显然它正是2的平方。其它数据也能类 推。 标号的真实含义: 从这个地方也能看到另一个问题 , 我们使用了标号来替代具体的单元地址 。 事实上,标号的真实含义就是地址数值 。在这里它代表了,0,1,4,9,16,25这几个数据 在 ROM 中存放的起点位置。而在以前我们学过的如 LCALL DELAY 单片机指令中,DELAY 则代 表了以 DELAY 为标号的那段程序在 ROM 中存放的起始地址。事实上,CPU 正是通过这个地址 才找到这段程序的。 能通过以下的例程再来看一看标号的含义: MOV DPTR,#100H MOV A,R0 MOVC A,@A+DPTR ORG 0100H. DB 0,1,4,9,16,25 如果 R0中的值为2,则最终地址为100H+2为102H,到102H 单元中找到的是4。这个能看懂了 吧? 那为什么不这样写程序,要用标号呢?不是增加疑惑吗? 如果这样写程序的话,在写程序时,我们就必须确定这张表格在 ROM 中的具体的位置,如果 写完程序后,又想在这段程序前插入一段程序 ,那么这张表格的位置就又要变了 ,要改 ORG 100H 这句话了,我们是经常需要修改程序的,那多麻烦,所以就用标号来替代,只要一编 译程序, 位置就自动发生变化 , 我们把这个麻烦事交给计算机 ��指我们用的电脑去做 了。 堆栈操作 PUSH direct POP direct 第一条指令称之为推入,就是将 direct 中的内容送入堆栈中,第二条指令称之为弹出,就 是将堆栈中的内容送回到 direct 中。推入指令的执行过程是,首先将 SP 中的值加1,然后 把 SP 中的值当作地址,将 direct 中的值送进以 SP 中的值为地址的 RAM 单元中。例: MOV SP,#5FH MOV A,#100 MOV B,#20 PUSH ACC PUSH B 则执行第一条 PUSH ACC 指令是这样的:将 SP 中的值加1,即变为60H,然后将 A 中的值送到 60H 单元中,因此执行完本条指令后, 内存60H 单元的值就是100,同样,执行 PUSH B 时, 是将 SP+1,即变为61H,然后将 B 中的值送入到61H 单元中,即执行完本条指令后, 61H 单 元中的值变为20。 POP 指令的在单片机中执行是这样的,首先将 SP 中的值作为地址,并将此地址中的数送 到 POP 指令后面的那个 direct 中,然后 SP 减1。 接上例: POP B POP ACC 则执行过程是:将 SP 中的值(现在是61H)作为地址,取61H 单元中的数值(现在是 20) , 送到 B 中,所以执行完本条指令后 B 中的值是20,然后将 SP 减1,因此本条指令执行完后 , SP 的值变为60H,然后执行 POP ACC,将 SP 中的值(60H)作为地址,从该地址中取数(现 在是100) ,并送到 ACC 中,所以执行完本条指令后, ACC 中的值是100。 这有什么意义呢?ACC 中的值本来就是100,B 中的值本来就是20,是的,在本例中,的确没 有意义,但在实际工作中,则在 PUSH B 后一般要执行其他指令,而且这些指令会把 A 中的 值,B 中的值改掉,所以在程序的结束,如果我们要把 A 和 B 中的值恢复原值,那么这些指 令就有意义了。 还有一个问题,如果我不用堆栈,比如说在 PUSH ACC 指令处用 MOV 60H,A,在 PUSH B 处 用指令 MOV 61H,B,然后用 MOV A,60H,MOV B,61H 来替代两条 POP 指令,不是也一样吗? 是的,从结果上看是一样的,但是从过程看是不一样的, PUSH 和 POP 指令都是单字节,单 周期指令,而 MOV 指令则是双字节,双周期指令。更何况,堆栈的作用不止于此 ,所以一般 的计算机上都设有堆栈,单片机也是一样 ,而我们在编写子程序,需要保存数据时,常常也 不采用后面的办法,而是用堆栈的办法来实现。 例:写出以下单片机程序的运行结果 MOV 30H,#12 MOV 31H,#23 PUSH 30H PUSH 31H POP 30H POP 31H 结果是30H 中的值变为23,而31H 中的值则变为12。也就两者进行了数据交换。从这个例程 能看出:使用堆栈时,入栈的书写次序和出栈的书写次序必须相反 ,才能保证数据被送回原 位,不然就要出错了。推荐使用慧净 51 实验板。推荐 51 学习网 WWW.HLMCU.COM 淘宝网:http://shop.taobao.com/ 51 单片机汇编语言教程:第 11 课-单片机算术运算指令 不带进位位的单片机加法指令 ADD A,#DATA;例:ADD A,#10H ADD A,例:ADD A,10H ADD A,R例:ADD A,R7 ADD A,@R例:ADD A,@R0 用途:将 A 中的值与其后面的值相加,最终结果否是回到 A 中。 例:MOV A,#30H ADD A,#10H 则执行完本条指令后, A 中的值为 40H。 下面的题目自行练习 MOV 34H,#10H MOV R0,#13H MOV A,34H ADD A,R0 MOV R1,#34H ADD A,@R1 带进位位的加法指令 ADDC A,Rn ADDC A,direct ADDC A,@Ri ADDC A,#data 用途:将 A 中的值和其后面的值相加,并且加上进位位 C 中的值。 说明:由于 51 单片机是一种 8 位机,所以只能做 8 位的数学运算,但 8 位运算的范围只有 0-255,这在实际工作中是不够的,因此就要进行扩展,一般是将 2 个 8 位的数学运算合起 来,成为一个 16 位的运算,这样,能表达的数的范围就能达到 0-65535。如何合并呢?其 实很简单,让我们看一个 10 进制数的例程: 66+78。 这两个数相加,我们根本不在意这的过程,但事实上我们是这样做的:先做 6+8(低位) , 然后再做 6+7,这是高位。做了两次加法,只是我们做的时候并没有刻意分成两次加法来做 罢了,或者说我们并没有意识到我们做了两次加法 。之所以要分成两次来做 ,是因为这两个 数超过了一位数所能表达的范置( 0-9) 。 在做低位时产生了进位 , 我们做的时候是在适当的位置点一下 , 然后在做高位加法是将这一 点加进去。那么计算机中做 16 位加法时同样如此,先做低 8 位的,如果两数相加产生了进 位,也要“点一下”做个标记,这个标记就是进位位 C,在 PSW 中。在进行高位加法是将这 个 C 加进去。例:H,先做 67H+A0H=107H,而 107H 显然超过了 0FFH,因此 最终保存在 A 中的是 7,而 1 则到了 PSW 中的 CY 位了,换言之,CY 就相当于是 100H。 然后再做 10H+10H+CY,结果是 21H,所以最终的结果是 2107H。 带借位的单片机减法指令 SUBB A,Rn SUBB A,direct SUBB A,@Ri SUBB A,#data 设(每个 H, (R2)=55H,CY=1,执行指令 SUBB A,R2 之后,A 中的值为 73H。 说明: 没有不带借位的单片机减法指令 , 如果需要做不带位的减法指令 (在做第一次相减时) , 只要将 CY 清零即可。 乘法指令 MUL AB 此单片机指令的功能是将 A 和 B 中的两个 8 位无符号数相乘,两数相乘结果一般比较大, 因此最终结果用 1 个 16 位数来表达,其中高 8 位放在 B 中,低 8 位放在 A 中。在乘积大于 FFFFFH(65535)时,0V 置 1(溢出) ,不然 OV 为 0,而 CY 总是 0。 例: (A)=4EH, (B)=5DH,执行指令 MUL AB 后,乘积是 1C56H,所以在 B 中放的是 1CH,而 A 中放的则是 56H。 除法指令 DIV AB 此单片机指令的功能是将 A 中的 8 位无符号数除了 B 中的 8 位无符号数(A/B) 。除法一般 会出现小数, 但计算机中可没法直接表达小数 , 它用的是我们小学生还没接触到小数时用的 商和余数的概念,如 13/5,其商是 2,余数是 3。除了以后,商放在 A 中,余数放在 B 中。 CY 和 OV 都是 0。如果在做除法前 B 中的值是 00H,也就是除数为 0,那么 0V=1。 加 1 指令 INC A INC Rn INC direct INC @Ri INC DPTR 用途很简单,就是将后面目标中的值加 1。 (A) 例: =12H, (R0) =33H, (21H) =32H, (34H) =22H,DPTR=1234H。执行下面的指令: INC A (A)=13H INC R2 (R0)=34H INC 21H (21H)=33H INC @R0 (34H)=23H INC DPTR ( DPTR)=1235H 后结果如上所示。 说明:从结果上看 INC A 和 ADD A,#1 差不多,但 INC A 是单字节,单周期指令,而 ADD #1 则是双字节,双周期指令,而且 INC A 不会影响 PSW 位,如(A)=0FFH,INC A 后(A) =00H,而 CY 依然保持不变。如果是 ADD A ,#1,则(A)=00H,而 CY 一定是 1。因此 加 1 指令并不适合做加法,事实上它主要是用来做计数 、地址增加等用途。另外,加法类指 令都是以 A 为核心的��其中一个数必须放在 A 中,而运算结果也必须放在 A 中, 而 加 1 类指令的对象则广泛得多,能是寄存器、内存地址、间址寻址的地址等等。 减 1 指令 减 1 指令 DEC A DEC RN DEC direct DEC @Ri 与加 1 指令类似,就不多说了。 综合练习: MOV A,#12H MOV R0,#24H MOV 21H,#56H ADD A,#12H MOV DPTR,#4316H ADD A,DPH ADD A,R0 CLR C SUBB A,DPL SUBB A,#25H INC A SETB C ADDC A,21H INC R0 SUBB A,R0 MOV 24H,#16H CLR C ADD A,@R0 先写出每步运行结果,然后将以上题目建入 ,并在软件仿真中运行 ,观察寄存器及有关单元 的内容的变化,是否与自已的预想结果相同。推荐使用慧净 51 实验板。推荐 51 学习网 WWW.HLMCU.COM 淘宝网:http://shop.taobao.com/ 51单片机汇编语言教程:第12课-单片机逻辑运算类指令对单片机的累加器 A 的逻辑操作: CLR A ;将 A 中的值清0,单周期单字节指令,与 MOV A,#00H 效果相同。 CPL A ;将 A 中的值按位取反 RL A ;将 A 中的值逻辑左移 RLC A ;将 A 中的值加上进位位进行逻辑左移 RR A ;将 A 中的值进行逻辑右移 RRC A ;将 A 中的值加上进位位进行逻辑右移 SWAP A ;将 A 中的值高、低4位交换。 例: (A)=73H,则执行 CPL A,这样进行: 73H 化为二进制为, 逐位取反即为 ,也就是8CH。 RL A 是将(A)中的值的第7位送到第0位,第0位送1位,依次类推。 例:A 中的值为68H,执行 RL A。68H 化为二进制为,按上图进行移动。 化为,即 D0H。 RLC A,是将(A)中的值带上进位位( C)进行移位。 例:A 中的值为68H,C 中的值为1,则执行 RLC A 1 后,结果是0 ,也就是 C 进位位的值变成了0,而(A)则变成了 D1H。 RR A 和 RRC A 就不多谈了,请大家参考上面两个例程自行练习吧。 SWAP A,是将 A 中的值的高、低4位进行交换。 例: (A)=39H,则执行 SWAP A 之后,A 中的值就是93H。怎么正好是这么前后交换呢?因为 这是一个16进制数,每1个16进位数字代表4个二进位。注意,如果是这样的 : (A)=39,后 面没 H, 执行 SWAP A 之后, 可不是( )=93。 A 要将它化成二进制再算 : 39化为二进制是10111, 也就是高4位是0001,低4位是0111,交换后是,也就是71H,即113。 练习,已知(A)=39H,执行下列单片机指令后写出每步的结果 CPL A RL A CLR C RRC A SETB C RLC A SWAP A 通过前面的学习, 我们已经掌握了相当一部份的单片机指令 , 大家对这些枯燥的单片机指令 可能也有些厌烦了,下面让我们轻松一下,做个实验。 实验五: ORG 0000H LJMP START ORG 30H START: MOV SP,#5FH MOV A,#80H LOOP: MOV P1,A RL A LCALL DELAY LJMP LOOP delay: mov r7,#255 d1: mov r6,#255 d2: nop nop nop nop djnz r6,d2 djnz r7,d1 ret END 先让我们将程序写入片中,装进实验板,看一看现象。 看到的是一个暗点流动的现象,让我们来分析一下吧。 前而的 ORG 0000H、LJMP START、ORG 30H 等我们稍后分析。从 START 开始,MOV SP,#5FH, 这是初始化堆栈,在本程序中有无此句无关紧要 ,不过我们慢慢开始接触正规的编程 ,我也 就慢慢给大家培养习惯吧。 MOV A,#80H,将80H 这个数送到 A 中去。干什么呢?不知道,往下看。 MOV P1,A。将 A 中的值送到 P1端口去。此时 A 中的值是80H,所以送出去的也就是 80H,因 此 P1口的值是80H,也就是B,通过前面的分析,我们应当知道,此时 P1。7接的 LED 是不亮的,而其它的 LED 都是亮的,所以就形成了一个 “暗点”。继续看,RL A,RL A 是将 A 中的值进行左移,算一下,移之后的结果是什么?对了,是 01H,也就是B, 这样,应当是接在 P1。0上的 LED 不亮,而其它的都亮了,从现象上看“暗点”流到了后面。 然后是调用延时程序,这个我们很熟悉了,让这个 “暗点”“暗”一会儿。然后又调转 到 LOOP 处(LJMP LOOP) 。请大家计算一下,下面该哪个灯不亮了。。。对了,应当是接在 P1。 。。 1上灯不亮了。这样依次循环,就形成了 “暗点流动”这一现象。 问题: 如何实现亮点流动? 如何改变流动的方向? 答案: 1、将 A 中的初始值改为7FH 即可。 2、将 RL A 改为 RR A 即可。 51单片机汇编语言教程:第13课-单片机逻辑与或异或指令详解ANL A,RA 与 Rn 中的值按位'与',结果送入 A 中 ANL A,A 与 direct 中的值按位'与',结果送入 A 中 ANL A,@RA 与间址寻址单元@Ri 中的值按位'与',结果送入 A 中 ANL A,#A 与立即数 data 按位'与',结果送入 A 中 ANL direct,A ;direct 中值与 A 中的值按位'与',结果送入 direct 中 ANL direct,#direct 中的值与立即数 data 按位'与',结果送入 direct 中。 这几条指令的关键是知道什么是逻辑与。这里的逻辑与是指按位与 例:71H 和56H 相与则将两数写成二进制形式: (71H)
即20H,从上面的式子能看出,两个参与运算的值只要其中有一个位上是 0, 则这位的结果就是0,两个同是1,结果才是1。 理解了逻辑与的运算规则,结果自然就出来了。看每条指令后面的注释 下面再举一些例程来看。 MOV A,#45H ;(A)=45H MOV R1,#25H ;(R1)=25H MOV 25H,#79H ;(25H)=79H ANL A,@R1 ;45H 与79H 按位与,结果送入 A 中为 41H (A)=41H ANL 25H,#15H ;25H 中的值(79H)与15H 相与结果为(25H)=11H) ANL 25H,A ;25H 中的值(11H)与 A 中的值(41H)相与,结果为(25H)=11H 在知道了逻辑与指令的功能后 , 逻辑或和逻辑异或的功能就很简单了 。 逻辑或是按位“或”, 即有“1”为1,全“0”为0。例:
而异或则是按位“异或”,相同为“0”,相异为“1”。例:
而所有的或指令,就是将与指仿中的 ANL 换成 ORL,而异或指令则是将 ANL 换成 XRL。即 或指令: ORL A,RA 和 Rn 中的值按位'或',结果送入 A 中 ORL A,A 和与间址寻址单元@Ri 中的值按位'或',结果送入 A 中 ORL A,#A 和立 direct 中的值按位'或',结果送入 A 中 ORL A,@RA 和即数 data 按位'或',结果送入 A 中 ORL direct,A ;direct 中值和 A 中的值按位'或',结果送入 direct 中 ORL direct,#direct 中的值和立即数 data 按位'或',结果送入 direct 中。 异或指令: XRL A,RA 和 Rn 中的值按位'异或',结果送入 A 中 XRL A,A 和 direct 中的值按位'异或',结果送入 A 中 XRL A,@RA 和间址寻址单元@Ri 中的值按位'异或',结果送入 A 中 XRL A,#A 和立即数 data 按位'异或',结果送入 A 中 XRL direct,A ;direct 中值和 A 中的值按位'异或',结果送入 direct 中 XRL direct,#direct 中的值和立即数 data 按位'异或',结果送入 direct 中。 练习: MOV A,#24H MOV R0,#37H ORL A,R0 XRL A,#29H MOV 35H,#10H ORL 35H,#29H MOV R0,#35H ANL A,@R0 四、控制转移类指令 无条件转移类指令 短转移类指令 AJMP addr11 长转移类指令 LJMP addr16 相对转移指令 SJMP rel 上面的三条指令,如果要仔细分析的话 ,区别较大,但开始学习时,可不理会这么多,统统 理解成:JMP 标号,也就是跳转到一个标号处。事实上, LJMP 标号,在前面的例程中我们 已接触过,并且也知道如何来使用了 。而 AJMP 和 SJMP 也是一样。那么他们的区别何在呢? 在于跳转的范围不一样。好比跳远, LJMP 一下就能跳64K 这么远(当然近了更没关系了 ) 。 而 AJMP 最多只能跳2K 距离, SJMP 则最多只能跳256这么远。 而 原则上, 所有用 SJMP 或 AJMP 的地方都能用 LJMP 来替代。因此在开始学习时,需要跳转时能全用 LJMP,除了一个场合。 什么场合呢?先了解一下 AJMP,AJMP 是一条双字节指令,也就说这条指令本身占用存储器 (ROM)的两个单元。而 LJMP 则是三字节指令,即这条指令占用存储器(ROM)的三个单元。 下面是第四条跳转指令。 间接转移指令 JMP @A+DPTR 这条指令的用途也是跳转 , 转到什么地方去呢?这可不能由标号简单地决定了 。 让我们从一 个实际的例程入手吧。 MOV DPTR,#TAB ;将 TAB 所代表的地址送入 DPTR MOV A,R0 ;从 R0中取数(详见下面说明) MOV B,#2 MUL A,B ;A 中的值乘2(详见下面的说明) JMP A,@A+DPTR ;跳转 TAB: AJMP S1 ;跳转表格 AJMP S2 AJMP S3 图 应用背景介绍:在单片机开发中,经常要用到键盘,见上面的 9个按钮的键盘。我们的 要求是:当按下功能键 A………..G 时去完成不一样的功能。这用程序设计的语言来表达的 话, 就是: 按下不一样的键去执行不一样的程序段 , 以完成不一样的功能。 怎么样来实现呢? 看图2,前面的程序读入的是按钮的值 ,如按下'A'键后获得的键值是0,按下'B'键后获 得的值是'1'等等,然后根据不一样的值进行跳转 ,如键值为0就转到 S1执行,为1就转到 S2 执行。。 。。如何来实现这一功能呢? 先从程序的下面看起, 是若干个 AJMP 语句, 这若干个 AJMP 语句最后在存储器中是这样 存放的(见图3) ,也就是每个 AJMP 语句都占用了两个存储器的空间,并且是连续存放的。 而 AJMP S1存放的地址是 TAB,到底 TAB 等于多少,我们不需要知道,把它留给汇编程序来 算好了。 下面我们来看这段程序的执行过程:第一句 MOV DPTR,#TAB 执行完了之后,DPTR 中的 值就是 TAB,第二句是 MOV A,R0,我们假设 R0是由按钮处理程序获得的键值,比如按下 A 键,R0中的值是0,按下 B 键,R0中的值是1,以此类推,现在我们假设按下的是 B 键,则执 行完第二条指令后,A 中的值就是1。并且按我们的分析,按下 B 后应当执行 S2这段程序, 让我们来看一看是否是这样呢?第三条 、 第四条指令是将 A 中的值乘2, 即执行完第4条指令 后 A 中的值是2。下面就执行 JMP @A+DPTR 了,现在 DPTR 中的值是 TAB,而 A+DPTR 后就是 TAB+2,因此,执行此句程序后,将会跳到 TAB+2这个地址继续执行。看一看在 TAB+2这个地 址里面放的是什么?就是 AJMP S2这条指令。因此,马上又执行 AJMP S2指令,程序将跳到 S2处往下执行,这与我们的要求相符合。 请大家自行分析按下键 “A”、“C”、“D”……之后的情况。 这样我们用 JMP @A+DPTR 就实现了按下一键跳到对应的程序段去执行的这样一个要求 。 再问大家一个问题,为什么取得键值后要乘 2?如果例程下面的所有指令换成 LJMP,即: LJMP S1,LJMP S2……这段程序还能正确地执行吗?如果不能,应该怎么改?推荐使用慧净 51 实验板。推荐 51 学习网 WWW.HLMCU.COM 淘宝网:http://shop.taobao.com/ 51单片机汇编语言教程:第14课-单片机条件转移指令条件转移指令是指在满足一定条件时进行相对转移。 判 A 内容是否为0转移指令 JZ rel JNZ rel 第一指令的功能是:如果(A)=0,则转移,不然次序执行(执行本指令的下一条指令 ) 。转移 到什么地方去呢?如果按照传统的办法 ,就要算偏移量,很麻烦,好在现在我们能借助于机 器汇编了。因此这第指令我们能这样理解: JZ 标号。即转移到标号处。下面举一例说明: MOV A,R0 JZ L1 MOV R1,#00H AJMP L2 L1: MOV R1,#0FFH L2: SJMP L2 END 在执行上面这段程序前如果 R0中的值是0的话,就转移到 L1执行,因此最终的执行结果 是 R1中的值为0FFH。而如果 R0中的值不等于0,则次序执行,也就是执行 MOV R1,#00H 指令。 最终的执行结果是 R1中的值等于0。 第一条指令的功能清楚了,第二条当然就好理解了,如果 A 中的值不等于0,就转移。把上 面的那个例程中的 JZ 改成 JNZ 试试吧,看看程序执行的结果是什么 ? 比较转移指令 CJNE A,#data,rel CJNE A,direct,rel CJNE Rn,#data,rel CJNE @Ri,#data,rel 第一条指令的功能是将 A 中的值和立即数 data 比较,如果两者相等,就次序执行(执行本 指令的下一条指令) ,如果不相等,就转移,同样地,我们能将 rel 理解成标号,即:CJNE A, #data,标号。 这样利用这条指令, 我们就能判断两数是否相等 , 这在很多场合是非常有用的 。 但有时还想得知两数比较之后哪个大 ,哪个小,本条指令也具有这样的功能 ,如果两数不相 等,则 CPU 还会反映出哪个数大,哪个数小,这是用 CY(进位位)来实现的。如果前面的 数(A 中的)大,则 CY=0,不然 CY=1,因此在程序转移后再次利用 CY 就可判断出 A 中的数 比 data 大还是小了。 例: MOV A,R0 CJNE A,#10H,L1 MOV R1,#0FFH AJMP L3 L1: JC L2 MOV R1,#0AAH AJMP L3 L2: MOV R1,#0FFH L3: SJMP L3 上面的程序中有一条单片机指令我们还没学过 ,即 JC,这条指令的原型是 JC rel,作用和上 面的 JZ 类似,但是它是判 CY 是0,还是1进行转移,如果 CY=1,则转移到 JC 后面的标号处 执行,如果 CY=0则次序执行(执行它的下面一条指令 ) 。 分析一下上面的程序,如果(A)=10H,则次序执行,即 R1=0。如果(A)不等于10H,则转 到 L1处继续执行,在 L1处,再次进行判断,如果( A)&10H,则 CY=1,将次序执行,即执 行 MOV R1,#0AAH 指令,而如果(A)&10H,则将转移到 L2处指行,即执行 MOV R1,#0FFH 指令。因此最终结果是:本程序执行前,如果(R0)=10H,则(R1)=00H,如果(R0)&10H, 则(R1)=0AAH,如果(R0)&10H,则(R1)=0FFH。 弄懂了这条指令,其它的几条就类似了,第二条是把 A 当中的值和直接地址中的值比较 , 第 三条则是将直接地址中的值和立即数比较,第四条是将间址寻址得到的数和立即数比较 , 这 里就不详谈了,下面给出几个对应的例程。 CJNE A,10H ;把 A 中的值和10H 中的值比较(注意和上题的区别) CJNE 10H,#35H ;把10H 中的值和35H 中的值比较 CJNE @R0,#35H ;把 R0中的值作为地址,从此地址中取数并和 35H 比较 循环转移指令 DJNZ Rn,rel DJNZ direct,rel 第一条指令在前面的例程中有详细的分析,这里就不多谈了。第二条指令,只是将 Rn 改成 直接地址,其它一样,也不多说了,给一个例程。 DJNZ 10H,LOOP 3.调用与返回指令 (1)主程序与子程序 在前面的灯的实验中,我们已用到过了子程序 ,只是我们并没有明确 地介绍。子程序是干什么用的,为什么要用子程序技术呢?举个例程 ,我们数据老师布置了 10道算术题,经过观察,每一道题中都包含一个( 3*5+2)*3的运算,我们能有两种选择, 第一种,每做一道题,都把这个算式算一遍,第二种选择,我们能先把这个结果算出来 , 也 就是51,放在一边,然后要用到这个算式时就将 51代进去。这两种办法哪种更好呢?不必多 言。设计程序时也是这样,有时一个功能会在程序的不一样地方反复使用 ,我们就能把这个 功能做成一段程序,每次需要用到这个功能时就 “调用”一下。 (2)调用及回过程:主程序调用了子程序 ,子程序执行完之后必须再回到主程序继续执行 , 不能“一去不回头”,那么回到什么地方呢?是回到调用子程序的下面一条指令继续执行 (当然啦,要是还回到这条指}

我要回帖

更多关于 键盘按一下出好几个 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信