当前位置:首页 > 汇编语言
  • pic单片机编程串烧,pic单片机汇编语言讲解下篇

    pic单片机编程串烧,pic单片机汇编语言讲解下篇

    看到这篇文章的朋友,想必大家对pic单片机均具备一定兴趣,或对pic单片机具备一定使用需求。前文中,小编曾对pic单片机汇编语言进行过部分讲解。本文中,将对pic单片机的清零等指令加以讲解,以帮助大家更好掌握pic单片机编程。 一、清零指令 1.寄存器清零指令 实例:CLRW;寄存器W被清零 说明:该条指令很简单,其中W为PIC单片机的工作寄存器,相当于MCS-51系列单片机中的累加器A,CLR是英语Clear的缩写字母。 2.看门狗定时器清零指令。 实例:CLRWDT;看门狗定时器清零(若已赋值,同时清预分频器) 说明:WDT是英语Watchdog Timer的缩写字母。CLR见上述说明。注意该两条指令无操作数。 3.寄存器f清零指令。指令格式:CLRF f 实例:CLRF TMRO;对TMRO清零 说明:在PIC系列8位单片机中,常用符号F(或f)代表片内的各种寄程器和F的序号地址。F取值按PIC系列不同型号而不同,一般为Ox00~Ox1F/7F/FF。TMRO代表定时器/计数器TMRO,所以CLRF对寄程器清零,采用了直接寻址方式直接给出要访问的寄存器TMRO。 4.位清零指令。指令格式 BCF f,b 实例:BCF REG1,2;把寄存器REG1的D2位清零 说明:BCF是英语Bit Clear F的缩写。指令格式中的F,同上说明;符号b是表示PIC片内某个8位数据寄存器F的位号(或位地址),所以b的取值为0~7或D0~D7。实例中REG是Register的缩写。实例中的2代表指令格式中的b=2即寄存器REG1的D2位。 通过上述四条清零指令格式和实例,可以说明,学习PIC系列8位单片机的指令时应首先了解指令的助记符意义(功能),再有就是它的表达方式。初学者没有必要死记指令,重要是理解和实践。 二、面向字节、常数与控制操作的指令 1.传送立即数至工作寄存器W指令 指令格式:MOVLW k;k表示常数、立即数和标号 说明:MOVLW是Move Literal to w的缩写 实例:MOVL 0x1E;常数30送W 2.I/O口控制寄存器TRIS设置指令 指令格式;TRIS f 说明;TRIS f是Load TRIS Register的缩写。其功能是把工作寄存器W的内容送入I/O口控制寄存器f。当W=0时,置对应I/O口为输出;W=1,置I/O口为输入。 实例:MOVLW 0x00 ;把00H送入W TRIS RA ;置PIC RA口为输出 MOVLW 0xFF ;把FFH送入W TRIS RB ;置PIC RB口为输入 说明:这是PIC汇编语言中常用的几条指令,即设置某个I/O口(这里是RA口和RB口)为输入或输出的语句。可见,识读指令时,一应充分理解语句格式的功能,二应前后联系阅读。 3.W寄存器内容送寄存器f(W内容保持不变)指令 指令格式:MOVWF f 说明:MOVWF是Move W to f的缩写 实例:MOVLW 0x0B;送0BH送W MOVWF 6 ;送W内容到RB口 说明:第一条指令0x0B(常数11)送工作寄存器W,第二条指令,把W内容常数11送到寄存器F6中,查表F6即为RB口,所以PORT_B(B口)=0BH=D11 4.寄存器f传送指令 指令格式:MOVF f,d 说明:MOVF是Move f的缩写。F代表PIC中的某个寄存器。指令中的d规定:d=0时,f内容送W;d=1时,f内容送寄存器。 实例:MOVF 6,0 ;RB口内容送W MOVWF 8  ;RB口内容送f8 说明:第一条指令中的6代表寄存器f=6,查寄存器表f=6为RB口;0代表d=0,代表选择的目标为寄存器W。第二条指令中的8代表寄存器f=8。所以两条指令结果是把RB口的内容送f8。至于f8内容是多少?还应在汇编语言开始时附加指令,这里从略。 5.空操作指令 指令格式:NOP 说明:NOP是英语No OperaTIon的缩写。NOP无操作数,所以称为空操作。执行NOP指令只使程序计数器PC加1,所以占用一个机器周期。 实例:MOVLW 0xOF;送OFH到W MOVWF PORT_B ;W内容写入B口 NOP      ;空操作 MOVF PORT_B,W ;读操作 说明:该三条指令是一种对I/O口的B口连续操作的实例,其目的达到写入B口的内容要读出时,应保证写、读之间有个稳定时间,因此加入了空操作指令NOP。 6.无条件跳转指令 指令格式:GOTO k 说明:执行该条指令时,将指令转移到指定的地址(跳转)。指令中的k,常与程序中的标号联系起来。 实例:见第9条指令中 7.寄存器内容减1,结果为零的间跳指令 指令格式:DECFSZ f,d 说明:DECFSZ是英语Decrement f,Skip of not 0的缩写。符号f,d代表的意义,前述已作说明。该条指令是指寄存器的内容减1存入W(d=0)或f(d=1)中。若指令执行结果减1不为零,指令顺序执行;为零时,就间跳下一条指令后再执行(等效顺序执行一条空指令NOP),实际指令中,当d=1时,该项常被略去。 8.寄存器内容加1,结果为零间跳指令 指令格式:INCFSZ f,d 说明:INCFSZ是英语Increment f,Skip of 0的缩写。该条指令与上一条(7)指令差别仅在于“1”上,即执行这条指令时,寄存器f内容加1,若结果不为零,则指令顺序执行;为零则指令间跳执行。执行这条指令的其它逻辑关系与上条相同。 9.子程序返回指令 指令格式:RETLW k 说明:RETLW是Return Literal to W的缩写。该指令代表子程序返回,返回前先把8位立即数送W。 以上便是小编此次想和大家分享的内容,希望大家喜欢。

    时间:2019-11-25 关键词: 指令 汇编语言 pic单片机

  • pic单片机编程串烧,pic单片机汇编语言讲解上篇

    pic单片机编程串烧,pic单片机汇编语言讲解上篇

    pic单片机为最常用单片机之一,许多程序均基于pic单片机进行开发。因此,熟练pic单片机编程尤为重要。为保证大家能准确、熟练掌握pic单片机的使用,本文特带来pic单片机的各种汇编语言指令的讲解上篇,下篇将在后期文章中予以讲解。如果你对本文即将讲解的内容充满兴趣,不妨继续往下阅读哦。 一、pic的指令系统 pic8位单片机共有三个级别,有相对应的指令集。基本级pic系列芯片共有指令33条,每条指令是12位字长;中级pic系列芯片共有指令35条,每条指令是14位字长;高级pic系列芯片共有指令58条,每条指令是16位字长。其指令向下兼容。 二、pic汇编语言指令格式 pic系列微控制器汇编语言指令与MCS-51系列单片机汇编语言一样,每条汇编语言指令由4个部分组成,其书写格式如下: 标号 操作码助记符 操作数1,操作数2;注释 指令格式说明如下:指令的4个部分之间由空格作隔离符,空格可以是1格或多格,以保证交叉汇编时,PC机能识别指令。 1.标号 与MCS-51系列单片机功能相同,标号代表指令的符号地址。在程序汇编时,已赋以指令存储器地址的具体数值。汇编语言中采用符号地址(即标号)是便于查看、修改,尤其是便于指令转移地址的表示。标号是指令格式中的可选项,只有在被其它语句引用时才需派上标号。在无标号的情况下,指令助记符前面必须保留一个或一个以上的空格再写指令助记符。指令助记符不能占用标号的位置,否则该助记符会被汇编程序作标号误处理。 书写标号时,规定第一字符必须是字母或半角下划线“—”,它后面可以跟英文和数字字符、冒号(:)制符表等,并可任意组合。再有标号不能用操作码助记符和寄存器的代号表示。标号也可以单独占一行。 2.操作码助记符 该字段是指令的必选项。该项可以是指令助记符,也可以由伪指令及宏命令组成,其作用是在交叉汇编时,“指令操作码助记符”与“操作码表”进行逐一比较,找出其相应的机器码一一代之。 3.操作数 由操作数的数据值或以符号表示的数据或地址值组成。若操作数有两个,则两个操作数之间用逗号(,)分开。当操作数是常数时,常数可以是二进制、八进制、十进制或十六进制数。还可以是被定义过的标号、字符串和ASCⅡ码等。具体表示时,规定在二进制数前冠以字母“B”,例如B10011100;八进制数前冠以字母“O”,例如O257;十进制数前冠以字母“D”,例如D122;十六进制数前冠以“H”,例如H2F。在这里PIC8位单片机默认进制是十六进制,在十六进制数之前加上Ox,如H2F可以写成Ox2F。 指令的操作数项也是可选项。 PIC系列与MCS-51系列8位单片机一样,存在寻址方法,即操作数的来源或去向问题。因PIC系列微控制器采用了精简指令集(RISC)结构体系,其寻址方式和指令都既少而又简单。其寻址方式根据操作数来源的不同,可分为立即数寻址、直接寻址、寄存器间接寻址和位寻址四种。所以PIC系列单片机指令中的操作数常常出现有关寄存器符号。有关的寻址实例,均可在本文的后面找到。 4.注释 用来对程序作些说明,便于人们阅读程序。注释开始之前用分号(;)与其它部分相隔。当汇编程序检测到分号时,其后面的字符不再处理。值得注意:在用到子程序时应说明程序的入口条件、出口条件以及该程序应完成的功能和作用。 以上便是小编此次带来的“pic单片机”的相关内容,通过本文,希望大家对pic单片机的汇编语言的使用具备一个初步的认识。在后期文章中,小编将为大家带来本文的下篇,如果大家对汇编内容存在一定兴趣,请一定要关注哦。

    时间:2019-11-25 关键词: 单片机 汇编语言 pic单片机

  • 解读 | 华为方舟编译器的革命性到底体现在哪里?

    解读 | 华为方舟编译器的革命性到底体现在哪里?

    随着 2019 华为开发者大会的临近,华为消费者业务 CEO 余承东此前在 P30 国内发布会上宣布的 “能够实现 Android 性能革命” 的方舟编译器也即将进入到开源阶段。虽然此前在 4 月份华为已经就方舟编译器进行了介绍,但人们更加关心的是:华为方舟编译器的革命性到底体现在哪里?针对这个问题,余承东在 8 月 6 日推荐了一篇由“菊厂搞机”发表的一篇题为《华为新贵!方舟编译器的荣光和使命》的长文,该文对华为方舟编译器的实现原理和背后故事进行了解读——而记者(公众号:记者)也希望由此提取出关于华为方舟编译器实现 Android 性能革命的诸多要点。Android 代码编译的原理和弊端在目前全世界的多种编程语言中,Android 操作系统采用的是 Java 语言。Java 语言是在 1995 年 5 月发布的,它的一个重点特点就是可以跨平台操作,而且需要借助虚拟机机制来解释源代码并调度硬件资源;但同时 Java 是一种预编译语言,需要先在开发者环境中将源代码(Source Code)转换成字节码(Byte Code),然后在设备上运行时再将字节码编译或解释成硬件能听得懂的机器码。也就是说,从 Java 的字节码到机器码,中间需要两样东西:1、虚拟机,用来调度硬件资源;2、翻译器(将 Java 字节码解释成机器语言)或者编译器(将 Java 字节码编译成机器码)。此处要注意的是,翻译器和编译器是不同的;编译器是把源程序的每一条语句都编译成机器语言并保存成二进制文件,这样运行时计算机可以直接以机器语言来运行此程序,因而速度很快;而解释器则是只在执行程序时,才一条一条地解释成机器语言来让计算机执行,因此运行速度不如编译后的程序运行得快。而对于 Android 操作系统来说,为了将 Java 字节码变成机器语言,Google 在不同的版本中进行了多样化的尝试,其目的自然是不断推动应用程序的运行速度向前发展;我们来看一下 Android 在不同版本是怎么做的:Android 1.0(2008 年):采用一个名为 Dalvik 的虚拟机,并且集成了一个解释器。当 App 运行时,就会调用这个解释器,对代码进行逐句解释,速度很慢。Android 2.2(2010 年):引入 JIT(Just In Time)即时编译机制,当 App 运行时,会将用户经常使用的功能编译为机器能直接执行的 010101 机器码,不用一句一句地去翻译。当出现不常用的功能时,再调用解释器来翻译;这样速度加快,但每次启动 App 都要重新编译一次,不能一劳永逸。Android 5.0(2014 年 10 月):将虚拟机 Dalvik 换成 ART(Android Run Time),将 JIT 的编译器替换成 AOT(Ahead of Time)。如此,App 在下载后安装到手机上时同时把能编译的代码先编译成机器听得懂的 101010;剩下不太好翻译的代码,就在用户使用时再叫醒解释器来翻译。如此,不用每次打开 App 都需要编译,但安装 App 的时间有点长,而且占用手机空间。Android 7.0(2017 年):采用混合编译机制,安装时先不编译中间代码,而是在用户空闲时将能够编译成机器码的那部分代码,通过 AOT 编译器先静态编译了。如果 AOT 还没来得及编译或者不能编译,再调用 JIT+ 解释器。这种机制,相当于用时间换空间,既缩短了用户安装 APP 的等待时间,又将虚拟机里编译器和解释器能做的优化提升到最大效率了。可以看到,无论是编译器还是解释器,只是在虚拟机上打补丁;手机上的虚拟机+编译器+解释器本身不仅占用硬件资源,还无法最大发挥软件运行性能。正因如此,所以绝大部分手机厂商只能无奈的通过简单粗暴提升 Android 手机的内存和存储空间,来弥补虚拟机的弊端。由此出发,Android 系统在性能和应用运行层面有四个方面的问题:1、如前所述,离不开虚拟机;2、为了与 C/C++ 等代码进行交互,Java 原生接口(Java Native Interface,简称 JNI)应运而生。目前 95% 的TOP应用都是使用 Java 和 C/C++ 等多种语言混合开发而成。Java 和 C/C++ 属于两种不同架构的语言,各有自己的使用规范。为了 APP 正常运行,它俩之间需要互通有无,这个互通有无的接口就是 JNI。在数据访问、函数调用、生命周期维护、异常处理等方面都需要这两种代码互相调用。这就意味着手机硬件资源要分配一部分给 JNI 去做调度——这一机制本身的效率就不高,而且占用了硬件资源。3、Android 虚拟机的编译器受限于手机硬件和代码优化模板单一,代码优化空间有限。 编译器包含三个部分:前端 Front End,主要负责将源代码翻译成 IR(Intermediate Representation);中端的 Optimizer 主要负责代码优化,将前端翻译过来的 IR 代码优化得更高效;后端 Back End 则将优化后的 IR 编译成 101010 的机器码——为了防止生态过于碎片化,Android 只为第三方开放了简单的编译代码优化模板,代码优化空间有限。4、Java 现有的内存回收机制容易造成 “间歇性” 卡顿。 当手机内存资源不够用的时候,Android 虚拟机就会召唤 GC(Garbage Collection,垃圾回收) 让所有手机运行的 Java 线程全部暂停,等待它回收内存空间,避免过载超载。这个 GC 机制,无法精确控制和干预,用户也无法把它去掉,所以性能比较差的手机还存在 “间歇性” 卡顿。这四个问题,也是华为试图通过方舟编译器解决的问题。华为方舟编译器是如何解决问题的?在回答这个问题之前,先看一下华为从事方舟编译器工作的时间线:2009 年,华为启动 5G 基础技术研究的同时,开始创建编译组,第一批海内外研究人员加入。2013 年,华为推出面向基站领域的自研编译器 HCC,并正式提出编译器框架构想。2014 年,众多海内外专家加入华为,方舟项目正式启动。2016 年,成立编译器与编程语言实验室。2017 年,方舟编译器上的第一个 Java 程序 “HelloWorld” 跑通。2018 年春节前一周,方舟编译器跑通 Android 系统所有后台服务,并成功移植到手机。2019 年 4 月,华为方舟编译器在 P30 系列的国内发布会上对外宣布。那么,方舟编译器的原理究竟是如何实现的?实际上,华为所谓的 “方舟编译器” 与其说是一个编译器,不如说是一个编译运行系统;这个系统的运行需要开发环境和终端(也就是智能手机)的配合,其目的是绕过 Android 操作系统中 App 的运行所必须依赖的虚拟机,将 Java/C/C++ 等混合代码一次编译成机器码直接在手机上运行,彻底告别 Java 的 JNI 额外开销,也彻底告别了虚拟机的 GC 内存回收带来的应用进程掉线——从而最终实现 Android 操作系统的流畅度。正如上文所言,在方舟编译器的这一实现过程中,需要解决四个方面的问题。第一:将 Java 代码直接编译成机器码就目前的情况来看,Java 编译成机器码的过程中,要面临的难题是 Java 中的动态语义(与之对应的是静态语义,它是通过提前翻译能够解决的),静态语义指的是确定的语言和意思,而动态语义指的是需要结合上下文来理解的内容——这其中,如果要像编译静态语义一样去编译动态语义,很多知乎大神认为是根本就不可能的。而这个不可能,正是华为在开发方舟编译器过程中解决的问题。具体来说,方舟编译器通过编译阶段和运行阶段的双向加持,将静态编译动态语义最大的两大难点解决:一是设计数据模型,二是如何在运行时高效获得动态信息。方舟编译器团队基本遍历了 Java 的动态语义,进行了大规模的数据建模。同时,大大提高了编译时动态语义分析的精度,特别是涉及跨语言调用时;另外,华为设计了一套具有核心专利的动态语义匹配机制,有效降低了运行时动态语义的开销。由此,方舟编译器能够将 Java 代码编译成机器能直接执行的语言。华为方面表示,经过华为方舟编译器的 App,再也不需要在手机上编译了,彻底告别了虚拟机,从而带来了媲美甚至超越 iOS 的 Android 体验。 第二:解决混合语言的 JNI 开销由于 95% 的 Top 应用都是 Java/C/C++ 等混合语言编写而成;因此方舟编译器还需要干掉混合语言互相调用带来的 JNI 开销。这里就涉及到上文提到的一个名词 IR,它是用来表示代码的数据结构,它是编译器的各模块以及相关工具之间用来传递信息的“协议和通用语言”,也是程序变换和编译优化各种算法的承载体。它是编译器的“大脑”,直接决定了编译器的最终效果——因此,它的难度是最高的。华为方舟编译器团队对 IR 进行了长达五年的精雕细琢,逐渐摸索出 “大脑” 里每一条神经、每一个神经元的信号规律,并在此基础上发明了一套核心专利,使得不同语言代码在开发者环境中能够统一编译成同一套可直接执行的机器码,从而彻底消除了混合语言互相调用的开销。也就是说华为方舟编译器可以将混合语言实现统一的中间表示 IR,这就相当于同一个人能够理解全世界的语言——当然,这背后是华为方舟编译器团队基于多个编程语言的深刻理解和大量研发积累。第三:在统一 IR 之外进行代码优化华为方舟编译器,直接将代码优化从手机环节搬到了开发者环境,未来还可能搬到云端。利用开发者环境更强大的算力,可以实现更先进和精细的优化算法,来达到更佳的优化效果——华为表示,在很多特定场景代码优化的提升甚至是颠覆性的。值得一提的是,开发者使用方舟编译器,并不需要改变原来的编码习惯。开发者可以自行开发代码优化算法,也可以仅通过方舟编译器预置的算法进行代码优化。未来,华为还将提供代码调优工具,开发者可以选择根据工具的优化建议来调整代码,和方舟编译器配合获得更优的执行效果。第四:解决 Android 内存回收带来的卡顿问题为了解决这个问题,方舟编译器采用了引用计数法(RC,Reference Counting)来进行内存的实时回收,并且配合使用了专门的消除环算法(消除对象互相引用带来的无法回收问题),来避免 GC 集中式回收带来的系统卡顿。相比 GC,方舟的内存回收是实时的而非集中式的,且不需要暂停应用进程,这样便大大消除了卡顿。另外,软件有一个大家都很熟悉的死循环,就是电脑被一个无限循环的运行程序把计算机资源占光。这种 “死循环” 在软件中叫 “环引用”。为了从机制避免手机内存被环引用 “吃掉”,方舟编译器引入 annotation 的“告警”标示,对基础类的环进行标注。当然,Java 程序员也可以对业务代码中的环进行标注。经过丰富的实践验证,方舟这种机制可以减少大部分程序中环的出现。另外一方面,方舟编译器在运行状态下引入了高效的环回收机制,允许有选择的智能回收某个 APP 的内存占用,这对传统的环回收算法是一个改进。总结来看,面对现有的 Android 系统在代码编译、运行、IR、内存回收等四个层面的问题,华为方舟编译器分别给出了自己的解决方案,这其中的核心创新点是混合语言的统一中间表示和完全静态编译,但更重要的是华为在解决 Android 操作系统 App 运行问题的崭新思路,以及为了实现这种思路而敢于大力投入的勇气。记者总结正如记者所言,方舟本质上不仅仅是一个编译器,而是一个编译系统,它需要通过用户终端和开发者的共同支持。对于华为手机用户来说,华为在手机终端中已经用方舟编译器替代了 Android system-server 的所有后台服务,这一项就已经足够让华为 EMUI 比其他 Android 系统更快一步——根据华为官方测试,方舟编译器提升手机系统操作流畅度高达 24%,系统响应性能提升 44%。当然,华为要想充分发挥方舟这个编译系统的实力,还离不开开发者在开发层面对方舟编译器的大力支持,这本质上是华为在现有 Android 开发生态之外另辟蹊径打造的一个全新开发环境——它究竟能否得到开发者的支持,还需要等华为将其开源之后才能有答案。记者按:本文参考资料《华为新贵!方舟编译器的荣光和使命》,点此查看。

    时间:2019-09-04 关键词: 华为 Android 汇编语言 方舟编译器

  • 10S计时汇编语言程序设计

    辛辛苦苦编了一个10s循环计时的程序,原理图和程序如下:   ORG 0000H AJMP MAIN ORG 000BH AJMP INTT0 ORG 0030H MAIN:CLR P2.7 CLR P2.6 MOV DPTR,#TAB CLR A MOV R2,#0H MOV R3,#0H MOV TMOD,#01H MOV TH0,#4CH MOV TL0,#00H SETB EA SETB ET0 SETB TR0 HERE: CJNE R2,#14H,HERE MOV R2,#0H PUSH ACC MOVC A,@A+DPTR MOV P0,A POP ACC INC A INC R3 CJNE R3,#0AH,HERE MOV R3,#00H ;此处用DJNZ 更方便,只不过R3的初始值要设置为0AH,同时取消INC R3指令(此行上面第二行) CLR A AJMP HERE ORG 80H INTT0:MOV TH0,#4CH MOV TL0,#00H INC R2 RETI TAB: DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H END

    时间:2019-08-13 关键词: 程序设计 汇编语言 10s计时

  • 80x86汇编语言编程:显示杨辉三角形

    看到一个要求输出“杨辉三角形”的题目:循着给出的链接,找到了百度文库,看了一篇又一篇文章、程序,感觉好像是一个赛着一个的罗嗦。杨辉三角形,大家都知道,排列形状如下:1 11 2 11 3 3 11 4 6 4 11 5 10 10 5 11 6 15 20 15 6 1… … … … 各个元素的数值,其排列的规律也很简单,就是上一行的两个相邻元素之和。按照这个规律,最左边和最右边,还应该各有一列零。当然,零就不显示了。有人总结的规律,则要高深的多,竟然用上了排列组合的公式,呵呵,这样一来,编程,还能简单得了吗?计算任意一行,都要把上一行的两个相邻数据,相加、保存。相加的和如果为零,这一行,就计算完毕了。比如,上一行是 1 2 1,就可以这样算:1.先用 0 加上 1,这里的 0,就是不显示的《左边元素》,1,就是《右边元素》,即第一个元素。和为 1,应该存入第一个元素的位置。但是,别忙,这第一个元素,将来还要和它右边的相加,所以要先保存它之后,再存放刚才的和。2.再用刚保存的 1,当做《左边元素》,用 2 当做《右边元素》,相加为 3;在预先保存了 2 之后,把 3 存入 2 的位置。3.再用刚保存的 2,当做《左边元素》,用 1 当做《右边元素》,相加为 3;在预先保存了 1 之后,把 3 存入 1 的位置。4.再用刚保存的 1,当做《左边元素》,用 0 当做《右边元素》,相加为 1;在预先保存了 0 之后,把 1 存入 0 的位置。5.再用刚保存的 0,当做《左边元素》,其《右边元素》显然也是 0,相加为 0;结束运算。每一行,都这样计算,算出来的结果,可以当场输出。想要输出多少行,就这样算多少遍。经过推算,第 19 行,其最大的元素,就超过了 65535。大于 65535 的数字,用 16 位机来计算,难度就明显加大了。那么,用 8088 CPU 汇编语言编程来计算杨辉三角形,最大的行数,做而论道认为还是以 18 行为好。;做而论道用汇编语言编写的输出《杨辉三角形》的程序如下:;=====================================DATAS    SEGMENT  tmp1 DW  1, 20  DUP(0)  ;定义空间用于运行过程中临时存储数据     TITL  DB  0AH, 0DH, '------------------------------------------'       DB  0AH, 0DH, '          YangHui   triangel'       DB  0AH, 0DH, '------------------------------------------', 0AH, 0DH       DB  'Please input the output LineNumber [1~18]: $'    X  DW  ?DATAS ENDS;--------------------------------CODES   SEGMENT    ASSUME   CS:CODES, DS:DATASSTART:    MOV   AX, DATAS    MOV   DS, AX;--------------------------------    LEA   DX, TITL    MOV   AH, 9    INT   21H    CALL  IN_NUM        ;输入行数;------------------------    MOV   CX, X         ;取来刚输入的数字    CMP   CX, 0    JZ    EXIT          ;判断是否符合范围要求    CMP   CX, 18    JA    EXIT    CALL  CR_LF         ;回车换行    CALL  CR_LFM_LOP:                  ;CX=1~18    LEA   SI, tmp1    MOV   BX, 0    CALL  YangHui       ;输出一行    CALL  CR_LF    LOOP  M_LOP         ;循环1~18次;--------------------------------EXIT:    MOV   AH, 4CH    INT   21H;=====================================YangHui:                ;计算杨辉三角形    MOV   AX, [SI]      ;取出数据    ADD   AX, BX        ;加上《左边数据》    MOV   BX, [SI]      ;再次取出数据,当做下次的《左边数据》    MOV   [SI], AX      ;保存和    JZ    END_YH        ;为零就停止    ADD   SI, 2    CALL  PRINT_AX      ;输出    CALL  SPACE    JMP   YangHui       ;循环END_YH:    RET      ;一行,计算完毕。 这个算法,是不是很简单 ? ;=====================================IN_NUM:                 ;输入数字    MOV   X,  0         ;先清零    MOV   CX, 2         ;输入2位IN_X:    MOV   AH, 7         ;输入单个字符    INT   21H    CMP   AL, 13    JE    END_IN        ;结束    CMP   AL, '0'    JB    IN_X          ;小于'0',不是数字    CMP   AL, '9'    JA    IN_X    MOV   DL, AL    MOV   AH, 2         ;显示单个字符    INT   21H    MOV   AL, DL       SUB   AL, '0'       ;还原为数字    MOV   AH, 0    MOV   SI, AX        ;暂存新数据.;    MOV   AX, X    MOV   BX, 10        ;老数据乘以10    MUL   BX    ADD   AX, SI        ;加上新数据    MOV   X,  AX        ;保存    LOOP  IN_X          ;继续输入END_IN:    RET;=====================================PRINT_AX:    PUSH  BX    PUSH  CX    PUSH  DX    MOV   BX, 10    MOV   CX, 0P_LOP1:    MOV   DX, 0    DIV   BX    INC   CX    PUSH  DX    CMP   AX, 0    JNZ   P_LOP1    MOV   AH, 2P_LOP2:    POP   DX    ADD   DL, '0'    INT   21H    LOOP  P_LOP2    POP   DX    POP   CX    POP   BXRET;=====================================CR_LF:                  ;显示回车换行    PUSH  AX    PUSH  DX    MOV   AH, 2    MOV   DL, 13    INT   21H    MOV   DL, 10    INT   21H    POP   DX    POP   AX    RET;=====================================SPACE:                  ;显示空格    PUSH  AX    PUSH  DX    MOV   AH, 2    MOV   DL, ' '    INT   21H    POP   DX    POP   AX    RET;=====================================CODES   ENDS    END   START程序执行的结果:c:masm510> M1------------------------------------------          YangHui   triangel------------------------------------------Please input the output LineNumber [1~18]: 181 11 2 11 3 3 11 4 6 4 11 5 10 10 5 11 6 15 20 15 6 11 7 21 35 35 21 7 11 8 28 56 70 56 28 8 11 9 36 84 126 126 84 36 9 11 10 45 120 210 252 210 120 45 10 11 11 55 165 330 462 462 330 165 55 11 11 12 66 220 495 792 924 792 495 220 66 12 11 13 78 286 715 1287 1716 1716 1287 715 286 78 13 11 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 11 15 105 455 1365 3003 5005 6435 6435 5005 3003 1365 455 105 15 11 16 120 560 1820 4368 8008 11440 12870 11440 8008 4368 1820 560 120 16 11 17 136 680 2380 6188 12376 19448 24310 24310 19448 12376 6188 2380 680 136 17 11 18 153 816 3060 8568 18564 31824 43758 48620 43758 31824 18564 8568 3060 816 153 18 1c:masm510>不知道能否有人来验算一下这些数据是否正确。

    时间:2019-07-10 关键词: 汇编语言

  • 处理器体系结构·四

    第4章 处理器体系结构·四关键词:处理器体系结构,汇编语言,指令集,硬件控制语言,寄存器和存储器 一个处理器支持的指令和指令的字节级编码成为它的ISA(instruction-set architecture,指令集体系结构)。 ISA在编译器编写者和处理器设计人员之间提供了一个概念抽象层,编译器编写者只需要知道允许哪些指令,以及它们是如何编码的;而处理器设计者必须建造出执行这些指令的处理器。 4.1 处理器设计的特点 1 从智力方面来说,处理器设计是非常有趣的。它需要完成复杂的人物,而结构又要尽可能简单。 2 理解处理器是如何工作的能帮助理解整个计算机系统是如何工作的。 3 虽然很少有人设计处理器,但是许多人设计包含处理器的硬件系统。 4 你的工作可能就是处理器设计。 4.2 Y86指令集体系结构 Y86的处理器状态类似于IA32。有八个寄存器(program register):%eax、%ecx、%edx、%ebx、%esi、%edi、%esp、%ebp。处理器每个程序寄存器储存一个字。寄存器%esp被入栈、出栈、调用和返回指令作为栈指针。而其它寄存器没有固定的含义或固定值。有三个一位的条件码(condition code):ZF、SF、OF,它们保存着最近的算术或逻辑指令造成影响的信息。程序计数器(PC)里存放着当前正在执行执行的地址。存储器从概念上来说就是一个很大的字节数组,保存着程序和数据。Y86用虚拟地址来引用存储器位置。硬件和操作系统如眼见联合起来将虚拟地址翻译成指明数据实际存在存储器中哪个地方的实际或物理地址。 1 Y86的指令细节 (1)IA32的movl指令分成了四个不同的指令:irmovl、rrmovl、mrmovl、rmmovl,分别显式地指明源和目的的格式。源可以是立即数(i)、寄存器(r)或存储器(m)。指令名字的第一个字母指明了目的的类型。两个存储器传送指令中的存储器引用方式是简单的基址加位移形式。在地址计算中,我们不支持第二变址寄存器(second index register)和任何寄存器值的伸缩(scaling)。同IA32一样,我们不允许从一个存储器地址直接传送到另一个存储器地址。另外我们也不允许将立即数传送到存储器。 (2)有四个整数操作指令,就是OPI。它们是addl、subl、andl、xorl。它们只对寄存器数据进行操作,而IA32还允许对存储数据进行这些操作。这些指令会设置三个条件ZF、SF、OF(零、符号、溢出)。 (3)七个跳转指令。是jmp、jle、jl、je、jne、jge、jg。根据转移指令的类型和条件代码的设置来选择转移。转移条件和IA32的一样。 (4)call指令返回地址入栈,然后跳到目的地址。ret指令从这样的过程中返回。 (5)pushl和popl指令实现了入栈和出栈,就像在IA32中一样。 (6)halt指令停止指令的执行。IA32中有一个与之相当的指令叫hlt。IA32的应用程序不允许使用这条指令,因为他会导致整个系统停止。在Y86程序中用halt指令来停止模拟器。 指令集的一个重要性质就是字节解释必须有唯一的解释。任意一个字节序列要么是一个唯一的指令蓄力的编码,要目就不是一个合法的字节序列。这个性质保证了处理器可以无二义性地执行目标代码程序。 2 IA32HE Y86的指令编码的比较 同IA32中的指令编码相比,Y86的编码简单的多,但是也没有那么简洁。在所有的Y86指令中,寄存器字段的位置都是固定的,而在不同的IA32指令中,它们的位置是不一样的。即使最多只有8个寄存器,我们也对寄存器采用了4位编码。IA32只用了3位编码。所以IA32能将入栈或出栈指令放在一个自接力,5位字段表明指令类型,剩下的3位是寄存器指示符。IA32可以将常数值编码成1、2或4个字节,而Y86总是将常熟之编码成4个字节。 4.3 逻辑设计和硬件控制语言HCL 要实现一个数字系统需要三个主要部分:计算位的函数的组合逻辑、存储位的存储器元素,以及控制存储器元素更新的时钟信号。 HCL:(hardware control language),硬件控制语言。 1 HCL和C语言的区别 (1)因为组合电路是由一些逻辑门组成的,它有两个属性就是输出会持续地响应输入的变化。相比之下,C表达式只会在程序执行过程中被遇到时才进行求值。 (2)C的逻辑表达式允许参数是任意整数,0表示FALSE,其它任何值都表示TRUE。而我们的逻辑门只对位值0和1进行操作。 (3)C的逻辑表达式有个属性就是它们可能只被部分求值。如果一个AND或OR操作的结果只用第一个参数求值就能确定,那么就不用对第二个参数求值了。而组合逻辑没有部分求值这条规则,逻辑门只是简单地响应它们输入的变化。 2 存储器和时钟控制 组合电路从本质上讲,不存储任何信息,相反,它们只是简单地响应输入信号,产生等于输入的某个函数输出。为了产生时序电路,也就是有状态并且在这个状态上进行计算的系统,我们必须引入按位存储信息的设备。 时钟寄存器:(简称寄存器)存储单个位或字。时钟信号控制寄存器加载输入值。 随机访问存储器:(简称存储器),存储多个字,用地址来选择该读或写哪个字。 4.4 Y86的顺序实现 处理一条指令包括很多操作。我们将他们组织成某个特殊的阶段序列,使即使指令的动作差异很大,但所有的指令都遵循统一的序列。每一步的具体处理取决于正在执行的指令。各个阶段以及各阶段内执行操作的简略描述。 取指(fetch):取指阶段从存储器读入指令,地址为程序计数器(PC)的值。 译码(decode):译码阶段从寄存器堆读入最多两个操作数。 执行(execute):在执行阶段,算术/逻辑单元(ALU)要么执行指令指明的操作,计算存储器引用的有效地址,要么增加或减少栈指针。 访存(memory)访存阶段可以将数据写入存储器,或者从存储器读出数据。 写回(write back):写回阶段最多可以写两个结果到寄存器堆。 更新PC(PC update):将PC设置成下一条指令的地址。 处理器无限制地循环执行这些阶段,只有在遇到halt指令或一些错误情况时,才会停下来。我们处理的错误情况包括非法存储器地址(程序地址或数据地址),以及非法指令。 参考文献 布赖恩特, O'Hallaron D, et al. 深入理解计算机系统[M]. 中国电力出版社, 2004.

    时间:2019-07-09 关键词: 汇编语言 处理器体系结构

  • 浅谈单片机中C语言与汇编语言的转换

    做了一单片机设计,要用C语言与汇编语言同时实现,现将这次设计的感受和收获,还有遇到的问题写下,欢迎感兴趣的朋友交流想法,提出建议。 单片机设计:基于51单片机的99码表设计 软件环境:Proteus8.0 + Keil4 要求:1,开关按一下,数码管开始计时。2,按两下,数码管显示静止。3,按三下,数码管数值清零。 C语言程序如下: #include #define uint unsigned int #define uchar unsigned char uchar shi,ge,aa,keycount=0,temp; sbit anjian=P1^7; uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; void display(shi,ge); void key (); void init(); void delay(uint z); /*-----主程序-----*/ void main() { init(); //初始化 while(1) { key (); if(keycount==1) TR0=1; //开中断 if(keycount==2) TR0=0; if(keycount==3) { temp=0; keycount=0; } if(aa==10){aa=0; if(temp<=99) { temp++;display(shi,ge); } else temp=0;} } } /*------初始化程序-------*/ void init() { keycount=0; temp=0; TMOD=0x01; TH0=(65536-50000)/256; TL0=(65536-50000)%256; EA=1; ET0=1; //TR0=0; } /*-----定时器中断-----*/ void timer0() interrupt 1 { TH0=(65536-50000)/256; TL0=(65536-50000)%256; aa++; } /*-----显示子程序-----*/ void display(shi,ge) { shi=temp/10; ge=temp%10; P0=table[shi];;delay(70); P2=table[ge]; ;delay(70); } /*-----按键检测子程序-----*/ void key () { if(anjian==0) { delay(5); //消抖 if(anjian==0) keycount++; } //while(anjian==0); //display(shi,ge); //等待按键弹起 } /*-----延时子程序-----*/ void delay(uint z) //延时约1ms { uint x,y; for(x=z;x>0;x--) for(y=100;y>0;y--); } 电路仿真结果如下:   好了,那么接下来我们就开始C语言——>汇编语言之旅^_^ (1)C语言1-10行改为 ORG 0000H //汇编起始伪指令,功能是规定程序存储器中源程序或数据块存放的起始地址 ajmp STAR //ajmp无条件跳转指令 ORG 000bh ajmp timer0 anjian equ P1.7 //位定义 keycount equ 40h shi equ 41h gewei equ 42h aa equ 43h temp equ 44h tab: db 3fh,6h,5bh,4fh,66h //建表 db 6dh,7dh,7h,7fh,6fh (2)C语言中的初始化函数 12-14行和39-49行改为 1 STAR: 2 acall init //子程序近程调用指令,功能是主程序调用子程序,调用子程序的范围为2kb init: mov keycount,#0 //keycount=0 mov temp,#0 //temp=1 mov tmod,#01h //TMOD=0x01 mov TH0,#60 mov TL0,#176 setb EA //位置位指令,对操作数所指出的位进行置1操作 setb ET0 setb TR0 ret acall为子程序近程调用指令,返回用ret。 (3)C语言中15-35行是个while循环,逻辑比较繁琐,注意了! START: acall display inc temp //加1指令,将操作数所指定的单元或寄存器中的内容加1 acall delay70 //近程调用delay70 x8: mov r0,keycount cjne r0,#2,F1 //cjne比较跳转指令,若r0=2则跳转到x8,否则跳转到F1。 ajmp x8 F1: mov r0,temp cjne r0,#99,START //若r0<99时,重复循环,否则temp=0 mov temp,#0 ajmp START F9: acall key mov r0,keycount cjne r0,#0,F2 //keycount=0顺序执行,否则跳转到F1 CLR P1.3 //清0 SETB TR0 F2: mov r0,keycount //第二次按键 cjne r0,#2,F2 clr TR0 reti mov r0,keycount //第三次按键 cjne r0,#3,F3 mov temp,#0 mov keycount,#0 inc增量指令,功能是将操作数所指定的单元或寄存器中的内容加1,其结果返还回原操作数单元中。 clr位复位,功能是对操作数所指出的位进行清“0”操作。 或者在中断函数中 timer0: w1: acall key mov TH0,#60 mov TL0,#176 cpl p1.0 JB keycount,x2 ajmp x3 x2: ajmp START clr p1.0 ajmp w1 ajmp w1 x3: mov r0,keycount cjne r0,#3,w1 //若r0=3则顺序执行,否则跳转到w1 mov temp,#0 mov keycount,#0 ret (4)C语言58-64行display函数改为 display: mov a,temp mov b,#10 div ab //除法指令,实现两个八位无符号数的除法操作。 mov r2,A mov r3,B mov dptr,#tab //16位数据传送使用方式 mov a,r2 movc a,@a+dptr //查表,先将累加器A的内容与数据指针寄存器DPTR的内容相加,再以其结果为地址,将该地址的结果送入A中 mov P0,a acall delay70 nop //空指令 mov a,r3 movc a,@a+dptr mov P2,a nop acall delay70 ret div为除法指令,功能是实现两个8位无符号数的除法操作,一般被除数放在累加器A中,除数放在寄存器B中。指令执行后,商放在A中,余数放在B中。 movc为查表指令,先将累加器A的内容与数据指针寄存器DPTR的内容相加,再以其结果为地址,将该地址的内容送入A中。 nop为空操作指令,它不作任何操作,但要占用一个机器周期(即12个振荡周期)的时间,常用于延时或等待。(有些程序执行的效果由于延时时间太短,在人眼视觉暂时作用下无法辨认清楚) 此段程序的作用在于将一个两位数分别分在一个十位上的数码管和一个个位上的数码管显示。 (5)C语言66-76行key函数改为 1 key:2 jb anjian,F6 //若anjian=0则顺序执行,否则跳转到F63 ACALL delay54 inc keycount //keycount++5 F6: 6 ret jb为位条件转移指令,功能是若直接寻址的位bit=1,则程序转移到指定的目标地址去执行,若bit=0,则程序顺序执行。 (6)C语言78-83行delay函数改为 delay70: mov r6,#70 D2: mov R7,#248 d1: djnz R7,d1 //248*70次 djnz R6,D2 ret delay5: mov r6,#5 //消抖。 F7: mov R7,#248 F8: djnz r7,F8 //248*5次 djnz r6,F7 ret 注意:248=2 8 ,约等于1ms。delay为延时程序。 温馨提示:在汇编中程序代码的大小写不受影响,但在C语言中就有影响了。 思考1:ret和 reti都是程序返回指令,有什么区别? 我的回答:ret是子程序返回指令,reti是中断子程序返回指令。区别在于如果是acall、lcall指令调用的子程序,返回指令就用ret;如果地址是0003,0013,000B,001B,0023调用的子程序,返回指令就用reti。 思考2:mov 20h,#0h和 setb 20h都是加1,用什么区别? 我的回答:mov指令中的20h指字节,setb中的20h是位。 旅途结束! 还记得前段时间我一直纠结于汇编语言中的各种指令的语法和功能,直到一个阳光明媚的中午,我一手拿着已经写好的两页半的C语言代码,一手拿着一本单片机的汇编指令查询手册,开始一行一行的翻译,可能汇编代码会在调试中有所错误,但基本逻辑是对的。而且这次C——>汇编,使我更加深入地理解了数据在计算机中的存储与调用。在此期间班主任和同学也给我答疑解惑,相信在以后的道路上,我会更加更深入地理解计算机。越努力,越幸运!

    时间:2019-07-03 关键词: 汇编语言 C语言 单片机中

  • 汇编语言与C51语言实现跑马灯实验的比较

    当前开发单片机应用系统程序主要应用汇编语言和C51语言,采用汇编语言编写可直接操纵系统的硬件资源,能编写出高效运行的程序代码,程序运行速度快。而采用C51语言编写可改善程序的可读性和可移植性,利于产品的更新换代,大大加快了单片机应用程序的开发速度。下面通过一个简单的实验--跑马灯实验来分析一下这两种语言的差别。用AT89C5l实现的跑马灯实验的原理图如xia 图所示。   跑马灯实验的原理图用汇编语言编写程序来实现,程序如下: ORG 0 000H LJP START//转入主程序 ORG 0040H START:MOV SP,#60H//设置 堆栈指针 OV A,# 0 F EH / /送A 11111110 ROTATE = MOV P1,A//写 P1 SJMP ROTATE//循环 DELAY:MOV RO,们AH//延 时子程序( 1秒) DELAY 1 : 40V R1 , 110 OH DELAY2 , DOV R2 , # OB 3H DJNZ R2 , $ DJNZ R1 , DELAY2 DJNZ RO , Dl; LAYI RET//子程序返回 END 用C51语言编写程序实现跑马灯实验,程序如下: # include < r eg5 1 . h> void main (void)//主函 数 ( unsigned int n; uns igned char code I e d p 1 8 1 = ( Oxf e , Oxfd , Oxf b , Oxf 7 , Oxef,Oxdf,Oxbf,Ox7f};//定义 数组 unsigned char LEDi ; while(1)//无限循环 { P1= ledp [leDIL;//数值送 P1 口 for (n= 0 ; n< 4 0 0 0 0 ; n++ ) ; //延时 Ledi++;//力(x 1 i f ( ledi== 8 ) ledi= 0 ; } ) 通过这个实现同一功能的两个程序可以发现,采用汇编语言编写单片机应用系统程序必须对单片机的内部资源和存储器的结构了如指掌,而且必须记住单片机指令系统的固定格式,按实际地址处理端口数据。而采用C51语言编写单片机应用程序对单片机的指令系统不要求了解,不必考虑单片机的硬件特性与接口结构,采用自然语言,以近似人的思维过程方式使用,改善了程序的可读性,而且可以使程序结构化,易于移植,提高开发程序的效率。另外,由于51系列单片机资源非常有限,在使用C51时尽量使用无符号数和字节变量,尽量使用局部变量,编译器可自动将某些局部变量声明为寄存器变量。 用 C语言编写的程序在KeilμVision3仿真软件中经汇编后产生的汇编代码如下: C : OXO 8 0 0 ESO 8 P10V A, OXO 8 C;OXO802 90084F MOV DPTR, 教 OxO84F C: OX 0805 93 MO vC A, @A+ DPTR C : OXO 8 0 6 F59 0 DOv Pl (Ox90 ( , A C:OxO808 900000 MOV DPTR, { 10xO 0 0 0 C : OXO 8 OB AF 82 MOV R7 , DPL (Ox82) C : OXO 8 OD AE 83 MO v R6 , DPH ( Ox83 ) C : Ox O8OF E4 CLR A C:OxO810 FC MOV R4,A C = Ox O8l1 FD I4OV R5 , A C : Ox0812 7B40 MOV R3 11 OX 4 0 C : OX 0814 7A9C MOV' R2 , 井 Ox9C C : OX 0816 F9 MO v R1 , A C : OX 0817 F8 MOV RO , A C ; Ox0818 D3 SETB C C : Ox0819 12 082D LCALL (C : 082D) C : OXO 81C 4003 JC C : 0821 C = Ox O81E A3 INC DPTR C : Ox081 F 80EA SJMP C : 08 OB C:OxO821 0508 工NC OXO8 C : Ox O 82 3 E5 0 8 MOV A , Ox0 8 C= Ox0825 B408D8 CJNE A, 1} Ox O 8 , main ( C : 0 8 0 0 ) C : OX 0828 E4 CLR A C = Ox0 8 2 9 F5 0 8 MOV OXO 8 , A C : Ox082 B 80D3 SJMP main (C: 0800) C = Ox O 82D EB MOV A , R3 C : OX 082E 9F SUBB A, R7 C : Ox082 F FSF 0 MOV B (OXFO) , A C : Ox0 83 1 EA MOV A, R2 C : Ox0832 9E SUBB A, R6 c: OX 0833 42F0 ORL B ( OXF 0 ) , A C : Ox083 5 E9 MOV A, R1 C : Ox083 6 9D SUBB A, R5 C: Ox0837 42F0 ORL B ( OXFO ) , A C : Ox0 83 9 EC DOV A , R4 C = Ox0 8 3A 64 8 0 XRL A , {} PO ( Ox80 ) C : OX 083C C8 XCH A, R0 C : Ox O 8 3 D 6 4 8 0 XRL A , { f PO ( Ox80 ) C : OX 0 83F 9 8 SUBB A, R0 C : Ox0840 45F0 ORL A, B ( OXFO ) C : OX 0842 22 RET C : Ox0 8 4 3 7 87F MO v R0 井 OX7F C : OX 0845 E4 CLR A C : Ox0846 F6 MOV 6; RO , A C = Ox0847 D8FD DJNZ RO , C 0846 C ; OX 0849 758108 MOV SP ( Ox8 1 ) , l10x0 8 C:OxO84C 020800 LJ址P main (C: 0800) C : OX 0 8 4F FE 10V R6 , A C : OXO 8 5 0 FD OV R5 , A C : OX 0851 FB MOV R3 , A C : OX 0852 F7 MOV OR I , A C : Ox O 8 53 EF MO v A , R7 C ; Ox0 85 4 DFBF DJNZ R7 , C : 0815 C : Ox O 8 5 6 7 F0 0 MOV R7 , 甘σxOO 通过把C51程序经过 KeilμVi-sion3软件编译后生成的汇编程序与直接用汇编语言编写的程序比较,C51语言经编译后有54条指令,而直接用汇编语言编写只需要 17条指令。可以看出;直接用汇编语言编写的单片机的代码效率高。此外,我们还可以观察编译连接后产生的列表.MAP或. M51文件,在该文件中详细列出了分配给变量和代码的地址和生成代码的大小等信息,我们可以了解代码是否优化,变量分配是否合理,堆栈是否溢出等。 无论是汇编语言还是C51语言编写的程序都不是单片机直接运行的程序,只有机器码程序单片机才能直接运行,对于汇编语言程序需要通过汇编程序汇编成机器码程序,对于 C51程序需要通过编译器程序编译成机器码程序。 可以在一个应用程序中,按模块用不同的编程语言编写源程序,最后通过编译器 /连接器生成一个可执行的完整程序,这种编程方式称为混合编程,在编写单片机应用程序时可采用 C51和汇编语言混合编程,一般是用汇编语言编写与硬件有关的程序,用 C51 编写主程序以及数据处理程序。

    时间:2019-06-16 关键词: C51 汇编语言 跑马灯

  • 51单片机汇编语言-延时程序的延时时间

    请高手帮我分析以下延时程序所占的时钟周期。 求解释: DELAY: MOV R6, #13 DELAY1: MOV R5, #250 DELAY2: NOP DJNZ R5, DELAY2 DJNZ R6, DELAY1 RET 问题补充:晶振为12MHz,机器周期即是1us。 ;----------------------------------------------------- 最佳答案: DELAY: MOV R6,#13 ;1 DELAY1: MOV R5,#250 ;1 DELAY2: NOP ;1 DJNZ R5,DELAY2 ;2 250 * (1 + 2) = 750 DJNZ R6,DELAY1 ;2 13 * (1 + 750 + 2) = 9789 RET ;2 1 + 9789 + 2 = 9792 加上调用指令,共用 9794 个机器周期。 当晶振频率为 12MHz,则延时时间为 9794 us。

    时间:2019-06-10 关键词: 51单片机 汇编语言 延时程序

  • 实例学习 Keil 软件的使用

    单片机开发中除必要的硬件外,同样离不开软件,我们写的汇编语言源程序要变为 CPU 可以执行的机器码有两种方法,一种是手工汇编,另一种是机器汇编,目前已极少使用手工 汇编的方法了。机器汇编是通过汇编软件将源程序变为机器码,用于 MCS-51 单片机的汇编 软件有早期的 A51,随着单片机开发技术的不断发展,从普遍使用汇编语言到逐渐使用高级 语言开发,单片机的开发软件也在不断发展,Keil 软件是目前最流行开发 MCS-51 系列单片 机的软件,这从近年来各仿真机厂商纷纷宣布全面支持 Keil 即可看出。Keil 提供了包括 C 编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通 过一个集成开发环境(uVision)将这些部份组合在一起。运行 Keil 软件需要 Pentium 或以 上的 CPU,16MB 或更多 RAM、20M 以上空闲的硬盘空间、WIN98、NT、WIN2000、WINXP 等操作系统。掌握这一软件的使用对于使用 51 系列单片机的爱好者来说是十分必要的,如 果你使用 C 语言编程,那么 Keil 几乎就是你的不二之选(目前在国内你只能买到该软件、 而你买的仿真机也很可能只支持该软件),即使不使用 C 语言而仅用汇编语言编程,其方便 易用的集成环境、强大的软件仿真调试工具也会令你事半功倍。 我们将通过一些实例来学习 Keil 软件的使用,在这一部份我们将学习如何输入源程序, 建立工程、对工程进行详细的设置,以及如何将源程序变为目标代码。图 1 所示电路图使用 89C51 单片机作为主芯片,这种单片机性属于 MCS-51 系列,其内部有 4K 的 FLASH ROM,可以反复擦写,非常适于做实验。89C51 的 P1 引脚上接 8 个发光二极管,P3.2~P3.4 引脚上接 4 个按钮开关,我们的第一个任务是让接在 P1 引脚上的发光二极管依次循环点亮。 一、Keil 工程的建立 首先启动 Keil 软件的集成开发环境,这里假设读者已正确安装了该软件,可以从桌面 上直接双击 uVision 的图标以启动该软件。 UVison 启动后,程序窗口的左边有一个工程管理窗口,该窗口有 3 个标签,分别是Files、Regs、和 Books,这三个标签页分别显示当前项目的文件结构、CPU 的寄存器及部份特殊 功能寄存器的值(调试时才出现)和所选 CPU 的附加说明文件,如果是第一次启动 Keil, 那么这三个标签页全是空的。 1、源文件的建立     ? 使用菜单“File->New ”或者点击工具栏的新建文件按 钮,即可在项目窗口的右侧打开一个新的文本编缉窗口, 在该窗口中输入以下汇编语言源程序,例 1: MOV A,#0FEH MAIN: MOV P1,A RL A LCALL DELAY AJMP MAIN DELAY: MOV R7,#255 D1: MOV R6,#255 DJNZ R6,$ 图 1 简单的键盘、显示板 END DJNZ R7,D1 RET 保存该文件,注意必须加上扩展名(汇编语言源程序一般用 asm 或 a51 为扩展名),这里假定将文件保存为 exam1.asm。 需要说明的是,源文件就是一般的文本文件,不一定使用 Keil 软件编写,可以使用任意 文本编缉器编写,而且,Keil 的编缉器对汉字的支持不好,建议使用 UltraEdit 之类的编缉 软件进行源程序的输入。 2、建立工程文件 在项目开发中,并不是仅有一个源程序就行了,还要为这个项目选择 CPU(Keil 支持数 百种 CPU,而这些 CPU 的特性并不完全相同),确定编译、汇编、连接的参数,指定调试 的方式,有一些项目还会有多个文件组成等,为管理和使用方便,Keil 使用工程(Project) 这一概念,将这些参数设置和所需的所有文件都加在一个工程中,只能对工程而不能对单一 的源程序进行编译(汇编)和连接等操作,下面我们就一步一步地来建立工程。     ? 点击“Project->New Project… ”菜单,出现一个对话框,要求给将要建立的工程起一个 名字,你可以在编缉框中输入一个名字 (设为 exam1),不需要扩展名。点击“保 存”按钮,出现第二个对话框,如图 2 所示,这个对话框要求选择目标 CPU(即 你所用芯片的型号),Keil 支持的 CPU 很多,我们选择 Atmel 公司的 89C51 芯 片。点击 ATMEL 前面的“+”号,展开 该层,点击其中的 89C51,然后再点击 “确定”按钮,回到主界面,此时,在 工程窗口的文件页中,出现了“Target 1”,前面有“+”号,点击“+”号展开, 可以看到下一层的“ Source Group1”,这 时的工程还是一个空的工程,里面什么 文件也没有,需要手动把刚才编写好的 源程序加入,点击“Source Group1”使 其反白显示,然后,点击鼠标右键,出现一个下 拉菜单,如图 3 所示。选中其中的“Add file to Group”Source Group1”,出现一个对话框,要求 寻找源文件,注意,该对话框下面的“文件类型” 默认为 C source file(*.c),也就是以 C 为扩展名 的文件,而我们的文件是以 asm 为扩展名的, 所以在列表框中找不到 exam1.asm,要将文件类 型改掉,点击对话框中“文件类型”后的下拉列 表,找到并选中“Asm Source File(*.a51,*.asm), 这样,在列表框中就可以找到 exam1.asm 文件 了。 双击 exam1.asm 文件,将文件加入项目,注 图 2 选择目标 CPU     图 3 加入文件 意,在文件加入项目后,该对话框并不消 失,等待继续加入其它文件,但初学时常 会误认为操作没有成功而再次双击同一文 件,这时会出现如图 4 所示的对话框,提 示你所选文件已在列表中,此时应点击“确 定”,返回前一对话框,然后点击“Close” 即可返回主界面,返回后,点击“Source Group 1”前的加号,会发现 exam1.asm 文 件已在其中。双击文件名,即打开该源程 序。 二、工程的详细设置     图 4 重复加入文件的错误 工程建立好以后,还要对工程进行进一步的设置,以满足要求。 首先点击左边 Project 窗口的 Target 1,然后使用菜单“Project->Option for target ‘target1’” 即出现对工程设置的对话框,这个对话框可谓非常复杂,共有 8 个页面,要全部搞清可不容 易,好在绝大部份设置项取默认值就行了。     ? 设置对话框中的 Target 页面,如 图 5 所示,Xtal 后面的数值是晶振频 率值,默认值是所选目标 CPU 的最高 可用频率值,对于我们所选的 AT89C51 而言是 24M,该数值与最终 产生的目标代码无关,仅用于软件模 拟调试时显示程序执行时间。正确设 置该数值可使显示时间与实际所用时间一致,一般将其设置成与你的硬件 图 5 对目标进行设置 所用晶振频率相同,如果没必要了解程序执行的时间,也可以不设,这里设置为 12。 Memory Model 用于设置 RAM 使用情况,有三个选择项,Small 是所有变量都在单片 机的内部 RAM 中;Compact 是可以使用一页外部扩展 RAM,而 Larget 则是可以使用全部 外部的扩展 RAM。Code Model 用于设置 ROM 空间的使用,同样也有三个选择项,即 Small 模式,只用低于 2K 的程序空间;Compact 模式,单个函数的代码量不能超过 2K,整个程序 可以使用 64K 程序空间;Larget 模式,可用全部 64K 空间。Use on-chip ROM 选择项,确认 是否仅使用片内 ROM(注意:选中该项并不会影响最终生成的目标代码量);Operating 项 是操作系统选择,Keil 提供了两种操作系统:Rtx tiny 和 Rtx full,关于操作系统是另外一个 很大的话题了,通常我们不使用任何操作系统,即使用该项的默认值:None(不使用任何 操作系统);Off Chip Code memory 用以确定系统扩展 ROM 的地址范围,Off Chip xData memory 组用于确定系统扩展 RAM 的地址范围,这些选择项必须根据所用硬件来决定,由 于该例是单片应用,未进行任何扩展,所以均不重新选择,按默认值设置。 设置对话框中的 OutPut 页面,如图 6 所示,这里面也有多个选择项,其中 Creat Hex file 用于生成可执行代码文件(可以用编程器写入单片机芯片的 HEX 格式文件,文件的扩展名 为.HEX),默认情况下该项未被选中,如果要写片做硬件实验,就必须选中该项,这一点是 初学者易疏忽的,在此特别提醒注意。选中 Debug information 将会产生调试信息,这些信 息用于调试,如果需要对程序进行调试,应当选中该项。Browse information 是产生浏览信 息,该信息可以用菜单 view->Browse 来查看,这里取默认值。按钮“ Select Folder for objects ” 是用来选择最终的目标文件所在的 文件夹,默认是与工程文件在同一 个文件夹中。Name of Executable 用 于指定最终生成的目标文件的名 字,默认与工程的名字相同,这两 项一般不需要更改。 工程设置对话框中的其它各页 面与 C51 编译选项、A51 的汇编选 项、BL51 连接器的连接选项等用法 有关,这里均取默认值,不作任何     图 6 对输出进行控制 修改。以下仅对一些有关页面中常用的选项作一个简单介绍。 Listing 标签页用于调整生成的列表文件选项。在汇编或编译完成后将产生(*.lst)的列 表文件,在连接完成后也将产生(*.m51)的列表文件,该页用于对列表文件的内容和形式 进行细致的调节,其中比较常用的选项是“C Compile Listing”下的“Assamble Code”项, 选中该项可以在列表文件中生成 C 语言源程序所对应的汇编代码。     ? C51 标签页用于对 Keil 的 C51 编译器的编译过程进行控制,其中比较常用的是“Code Optimization”组,如图 7 所示,该组中 Level 是优化等级,C51 在对源程序进行编译时,可 以对代码多至 9 级优化,默认使用 第 8 级,一般不必修改,如果在编 译中出现一些问题,可以降低优化 级别试一试。Emphasis 是选择编 译优先方式,第一项是代码量优化 (最终生成的代码量小);第二项 是速度优先(最终生成的代码速度快);第三项是缺省。默认的是速 度优先,可根据需要更改。 图 7 代码生成控制 设置完成后按确认返回主界面,工程文件建立、设置完毕。 三、编译、连接     ? 在设置好工程后,即可进行编译、连接。选择菜单 Project->Build target,对当前工程进 行连接,如果当前文件已修改,软件会先对该文件进行编译,然后再连接以产生目标代码; 如果选择 Rebuild All target files 将会 对当前工程中的所有文件重新进行编 译然后再连接,确保最终生产的目标 代码是最新的,而 Translate … .项则仅 对该文件进行编译,不进行连接。 以上操作也可以通过工具栏按钮直 接进行。图 8 是有关编译、设置的工具 栏按钮,从左到右分别是:编译、编译 连接、全部重建、停止编译和对工程进 行设置。 编译过程中的信息将出现在输出窗 口中的 Build 页中,如果源程序中有语 图 8 有关编译、连接、项目设置的工具条     图 9 正确编译、连接之后的结果 法错误,会有错误报告出现,双击该行,可以定位到出错的位置,对源程序反复修改之后, 最终会得到如图 9 所示的结果,提示获得了名为 exam1.hex 的文件,该文件即可被编程器读 入并写到芯片中,同时还产生了一些其它相关的文件,可被用于 Keil 的仿真与调试,这时 可以进入下一步调试的工作。

    时间:2019-04-15 关键词: 汇编语言 单片机开发 keil单片机

  • 如何在C中嵌入汇编语言

    两种方法在c语言中嵌入汇编:(1) __asm(" 字符串序列"); 例如: __asm(" movn a,#1"); /*第一个双引号右边有一个空格*/(2) #pragram asm 汇编语句 #pragram endasm例如: #pragram asm movn a,#1 movw _temp,a #pragram endasm

    时间:2019-04-05 关键词: 嵌入式开发 汇编语言 如何在

  • 教你用masm32 制作一个汇编语言IDE

    masm32  制作一个汇编语言IDE一、用现成的scintilla文件制作格式化输入二、用CRectTrack类处理控件布局三、用Ollydbg处理调式功能四、调用编绎功能 常见编译选项如下: /c   仅编译不链接  常用 /coff   产生obj文件为coff格式   必用 /Cp  源代码区分大小写 /Fo filename 指定obj文件名 /Fe filename  指定exe文件名 /Fl 【filename】 产生lst列表文件 /Gz 函数调用stdcall形式 /I path 指定include文件路径

    时间:2019-03-06 关键词: ide 汇编语言 masm32

  • vc++ 中开发汇编语言

    vc++ 中开发汇编语言

    vc++ 中开发汇编语言 汇编程序结构 一个显示字符串的汇编程序程序格式 一、模式定义二、includelib语句三、函数声明语句四、数据和代码部分Visual C/C++环境 建立工程汇编程序的调试 一、设置断点二、内存窗口三、寄存器窗口四、监视窗口常用调试命令字符串输入、输出 printfsprintfscanf常用Windows API调用 MessageBox确定函数的声明语句和库文件读取CPU标识WinDbg调试工具实验题:用MessageBox函数显示CPU信息Windows、Linux等现代操作系统都运行于CPU的保护模式下。学习保护模式的汇编语言编程,要选用合适的编译、调试工具,编译工具决定了汇编程序的语法、结构,而调试工具则能够帮助我们迅速查找程序中的错误,提高调试效率。本实验指导书采用Microsoft公司的MASM 6.14作为编译工具,Microsoft Visual C/C++作为开发调试环境。1.1 汇编程序结构和其他语言一样,汇编语言的源程序也要符合一定的格式,才能被编译程序所识别和处理。学习和掌握这些格式,是进行汇编编程的第一步。1.1.1 一个显示字符串的汇编程序       下面是一个简单的汇编程序。;程序清单:test.asm(在控制台上显示一个字符串).386.model flat, stdcalloption casemap:none; 说明程序中用到的库、函数原型和常量includelib      msvcrt.libprintf          PROTO C :ptr sbyte, :vararg; 数据区.dataszMsg           byte    “Hello World!”, 0ah, 0; 代码区.codestart:                mov    eax, OFFSET szMsg                invoke printf, eax                retend             start1.1.2 程序格式在源程序test.asm中,以分号(;)开始的行是注释行。注释行对程序的编译和执行没有影响。一、模式定义程序的第一部分是有关模式定义的3条语句:.386.model flat, stdcalloption casemap:none这些语句定义了程序使用的指令集、工作模式。(1)指令集.386语句是汇编语言的伪指令,说明本程序使用的指令集是哪一种CPU的。还可以使用:.8086、.186、.286、.386、.386p、.486、.486p、.586、.586p等。后面带p的伪指令则表示程序中可以使用特权指令。(2)工作模式.model语句用来定义程序工作的模式,它的格式是:.model 内存模式[, 调用规则][, 其他模式]内存模式的定义影响最后生成的可执行文件,可执行文件的规模可以有很多种类型,在Windows环境下,内存模式为flat,可执行文件最大可以用4 GB内存。在test.asm中,.model语句指明使用stdcall调用规则。调用规则就是子程序的调用方式,即调用子程序时参数传递的次序和堆栈平衡的方法。(3). option语句option语句有许多选项,这里介绍一种:option casemap:none这条语句说明程序中的变量和子程序名是否对大小写敏感。对大小写敏感表示区分大写、小写形式,例如变量XYZ和xyz是两个不同的变量。对大小写不敏感则不区分大写、小写形式,变量XYZ和xyz是同一个变量。由于Windows API函数中的函数名称是区分大小写的,所以应该指定这个选项“casemap:none”,否则在调用函数的时候会出现问题。二、includelib语句和C程序一样,在汇编程序中也需要调用一些外部模块(子程序/函数)来完成部分功能。例如,在hello.asm中,就需要调用printf函数将字符串显示在屏幕上。printf函数属于C语言的库函数。它的执行代码放在一个动态链接库DLL(dynamic-load library)中,这个动态库的名字叫msvcrt.dll。在汇编源程序中,需要用includelib语句指出库文件的名称,链接时LINK就从库文件中找出了函数的位置,避免出现上面的错误提示。这种库文件也叫导入库(import library)。例如:includelib      msvcrt.lib一个DLL文件对应一个导入库,如msvcrt.dll的导入库是msvcrt.lib;kernel32.dll的导入库是kernel32.lib;user32.dll的导入库是user32.lib等。导入库文件在Visual C/C++的库文件目录中,在链接生成可执行文件时使用。可执行文件执行时,只需要DLL文件,不需要导入库。三、函数声明语句对于所有要用到的库函数(或Windows API函数),在程序的开始部分必须预先声明。包括函数的名称、参数的类型等,如:在汇编语言程序中,函数声明为:函数名称            PROTO [调用规则] :[第一个参数类型] [,:后续参数类型]其中,PROTO后的调用规则是可选项。如果不写,则使用model语句中指定的调用规则。如果函数使用C调用规则,则PROTO后跟一个C。接下来是参数的说明。如果参数个数、类型不定,则用VARARG说明(varible argument)。先看在C语言头文件stdio.h中printf的函数声明:_CRTIMP int __cdecl printf(const char *, ...);可知printf函数的调用规则为C调用规则(__cdecl, 即c declare),第一个参数是字符串指针,后面的参数数量及类型不定。这里,用ptr sbyte代表const char *。printf          PROTO C :ptr sbyte,:vararg四、数据和代码部分程序中的数据部分和代码部分是分开定义的,数据部分从这一行开始:.data代码部分从这一行开始:.code遇到end语句时,代码部分结束。end语句一般是整个程序的最后一条语句。end语句后面跟的是起始标号。它指出了程序执行的第一条指令的位置。在例子中,使用start作为起始标号,程序从start处开始执行。注意,程序并不一定要从代码部分的第一行开始执行。例如,start前面可以写一些子程序等。end             起始标号如果要定义堆栈部分,可以使用堆栈定义语句:.stack          [堆栈大小]1.2 Visual C/C++环境Microsoft Visual C/C++(简称VC)是一个典型的集成开发环境(IDE,integrated development environment),在国内外十分流行。集成开发环境大大地提高了程序开发过程的效率,而且它还能够动态地调试程序。除了可以编写调试C/C++程序外,VC还可以用来编辑、修改、编译、调试汇编程序。本书使用的版本是Microsoft Visual C/C++ 6.0。1.2.1 建立工程首先,按照以下步骤建立一个能编译、调试汇编程序的工程:(1)    启动VC后,从菜单中选择“File”→“New”。(2)    如图1-1所示,在打开的“New”对话框顶部,单击“Projects”,再选中“Win32 Console Application”。在Location编辑框中输入“c:"asm”,再在“Project name”中输入“test”。输入“test”时,它自动地添加到Location编辑框中“c:"asm”的后面。图1-1 建立汇编程序工程之一(3)    单击“OK”键后,出现一个新的对话框,单击“Finish”。(4)    接下来,VC的窗口的左边显示出“test classes”,下面有“ClassView”和“FileView”两种视图,如图1-2所示。(5)    这时,可将hellow.asm(或其他的一个.asm源程序文件)复制到c:"asm"test中,并改名为test.asm;也可以将其他的汇编程序源文件复制到c:"asm"test"test.asm。图1-2 建立汇编程序工程之二(6)    接下来,再从菜单中选择“Project”→“Add to Projects”→“Files”,在该对话框中的文件名处输入“c:"asm"test"test.asm”,如图1-3所示。图1-3 建立汇编程序工程之三(7)    在VC窗口左边的视图中,展开“FileView”中的“Source Files”,显示出“test.asm”。在“test.asm”上,单击鼠标右键,出现如图1-4所示的菜单。图1-4 建立汇编程序工程之四(8)    在菜单中选择“Setting”。弹出另一个对话框,如图1-5所示。在“Commands”编辑框中输入“ml /c /coff /Zi test.asm”,在“Outputs”编辑框中输入“test.obj”。再单击“OK”。图1-5 建立汇编程序工程之五(9)    最后,再将“ML.EXE”和“ML.ERR”两个文件复制到“c:"windows”。如果Windows安装到其他目录,则需要把这两个文件复制到相应的目录。可用“set windir”命令显示出Windows的安装目录。(10)最后,验证是否能在VC中编译test.asm。在VC中按F7键,应该自动编译生成test.exe。如果源程序中有错误,编译后将错误信息显示在“Output”的“Build”视图中。点击该错误信息,光标自动定位到出现错误的程序行(也可以按F4键定位到错误的程序行)。为了使VC适合于汇编语言的调试,可对它进行如下设置,如图1-6所示。(11)从“Tools”菜单中选择“Options…”,再选择“Debug”页,选中“Disassembly window”中的“Code bytes”(前面打上对勾)。(12)在“Memory window”中,选中“Fixed width”,在后面填入数字16。(13)在“General”中,选中“Hexdecimal display”。(14)不选“View floating point registers”。图1-6 VC的调试设置选项程序编译成功后,按Ctrl+F5可以运行已编译好的程序。1.2.2 汇编程序的调试 一、设置断点如果程序运行的结果不正确,可以在VC中调试。单击“FileView”视图中的test.asm,这个源程序就会自动地进入VC的编辑窗口。将光标移动到程序入口所在的程序行上,按F9键。就在该行设置了一个断点。断点的程序行前有一个红色的小圆点,如图1-7所示。按F5键在Debug状态下执行程序,或者从菜单中选择“Build”→“Start Debug”→“Go”。这时,当前窗口显示出程序中的指令序列,有一个黄色箭头,它就是程序要执行的下一条指令,如图1-8所示。二、内存窗口从菜单中选择“View”→“Debug Windows”→“Memory”,打开内存窗口,在地址“Address:”后面的编辑框中可以输入内存变量的名称,这里输入szTitle。内存窗口中就显示出该变量所在内存单元的值。前面的部分是以十六进制的形式显示出来的,后面是以ASCII字符的形式显示出来的。在内存窗口上单击鼠标右键,可以选择:按字节、字、双字显示内存单元的值。三、寄存器窗口从菜单中选择“View”→“Debug Windows”→“Registers”,打开寄存器窗口。在寄存器窗口中,显示了各个32位寄存器和段寄存器的值。在调试程序时,如果某一个寄存器或内存单元的值被改变,则它的值用红色显示出来。在寄存器窗口中的最后一行,显示的内存单元就是当前指令要读或写的操作数。EFLAGS状态寄存器的值是按位显示的。但是,VC并没有使用我们所熟悉的OF、DF、IF、SF、ZF、AF、PF、CF名称,而是用它自己的一套名称,如表1-1所示。表1-1 VC中的EFLAGS标志位VC格式OVUPEIPLZRACPECYFLAGS位OFDFIFSFZFAFPFCF含义溢出方向中断允许符号为零辅助进位奇偶进位例如UP=0表示DF=0。四、监视窗口从菜单中选择“View”→“Debug Windows”→“Watch”,打开监视窗口。在“Name”一栏下面,可以输入想要监视的变量或寄存器名称。监视窗口会随时将这些变量的值显示出来。要在调试过程中改动寄存器或内存变量的值,可以在Watch窗口的该寄存器或变量的内容(在Value列)用鼠标左键单击,修改其值后,按回车键即可。也可以在内存窗口中修改变量的值。在要修改的内存单元上点击,直接输入新的内容即可。另外一种方法是按Shift+F9。弹出对话框后,在“Expression”处输入寄存器或内存变量的名称,再在下面的Value一列处修改其内容。最后,按“OK”。图1-7 编辑、编译汇编源程序并设置断点图1-8中为打开内存窗口、监视窗口和寄存器窗口后的屏幕显示。调试过程中,编辑窗口中显示出汇编源程序。如果要查看程序的实际执行代码,从菜单中选择“View”→“Debug Windows”→“Disassmebly”。在运行过程中,实际上运行的是机器代码,而不是汇编源程序。机器代码及其反汇编的指令和源程序混合显示在编辑窗口中。反汇编中的程序地址和指令中的数据都是用十六进制显示的。在调试过程中,使用十六进制来表示地址和(变量或寄存器的)数值更方便。按F10键可一步一步地执行程序。执行过程中,可以在内存窗口中观察变量的变化;在寄存器窗口中可以看到寄存器的变化;更加方便的是,可以把鼠标移动到编辑窗口中的寄存器或变量上,停留几秒钟后,VC会自动地显示它们的值。按Shift+F5键,可结束调试。图1-8 VC调试环境:编辑窗口、内存窗口、监视窗口和寄存器窗口1.2.3 常用调试命令常用的调试命令如表1-2所示。表1-2 VC的常用调试命令功能键作  用描  述F11单步执行Step IntoF10执行Step OverCtrl+F10执行到当前光标的位置的指令Run to CursorF9在当前光标的位置的指令上设置/清除断点Set/Clear Breakpoint at CursorF5执行程序GoShift+F5终止程序,退出程序Stop Debugging设置当前指令将光标处的指令设为当前指令Set Next StatementShift+F11当前子程序执行结束Step Outl         F11:单步执行当前指令。当前指令在反汇编窗口中用一个黄色箭头指示,CS:EIP指向当前指令。按F11键后,当前指令执行,黄色箭头和EIP随之变化,指向新的当前指令。l         F10:执行当前进程指令。F10和F11在执行一般指令时没有区别。在当前指令是一条CALL、INT指令的情况下有所区别。如果当前指令是CALL指令,按F11后,进入到子程序的第一条指令,子程序执行前就进入调试状态,可调试子程序的执行过程;按F10后,子程序执行完毕后才回到调试状态,不需要调试子程序的执行过程。l         Ctrl+F10:先把光标移动到一条指令上,可以用键盘上的上、下箭头移动光标,或者在某一行上点击。再按Ctrl+F10,程序就从当前指令处开始执行,一直到光标处的指令再停下来。l         F9:先把光标移动到一条指令上,按F9,就在该指令上设置了一个断点。再按F9,这个断点就清除了。设置断点后,指令的前面标有一个红色的圆点。程序运行到断点时,会停下来,这时就可以检查各个变量、寄存器的内容以及程序的执行流程是否正确,以查找程序中的错误。l         F5:从当前指令开始执行程序,直到遇到断点或程序结束时为止。l         Shift+F5:终止程序,不再执行后面的程序。终止后,可以再按F11键(或Ctrl+Shift+F5)重新开始调试过程。l         设置当前指令:在调试时,可能希望跳过一部分程序不执行,也可能想将已执行过的一段程序再执行一遍。这可以通过改变当前指令来实现。在新的当前指令上按下鼠标右键,弹出一个菜单,在其中选择“Set Next Statement”。这时,黄色箭头就指到新设置的当前指令上。l         Shift+F11:先按住Shift键,再按下F11。当前指令在子程序中时,如果想使整个子程序执行完毕,返回到主程序,则使用Shift+F11。某些功能也可以从“Debug”菜单中选择。如图1-9所示。图1-9 VC的部分Debug菜单项1.3 字符串输入、输出在C语言中,常用printf、scanf、sprintf等函数来实现字符串的的输入输出,在汇编语言中,可以调用这些函数。1. printf在前面的程序例子中已经用到过printf。在程序中,要指明printf的调用规则,以及它的参数类型。printf          PROTO C :dword,:varargprintf使用C调用规则(参数自右至左入栈,由主程序平衡堆栈)。第1个参数是一个双字(:dword),即字符串的地址,后面的其他参数个数可变,可以1个没有,也可以跟多个参数。以下C语句输出3个整数A、B、R和一个字符Op:printf ("%d %c %d = %d"n" , A, Op, B, R);在汇编语言中,在数据区中要定义szOutputFmtStr:szOutputFmtStr       byte    '%d %c %d = %d', 0ah, 0使用invoke语句调用printf。Printf后面跟的第1个参数是格式字符串的地址;第2、3、4个参数分别是要输出的整数。invoke printf, offset szOutputFmtStr, A, Op, B, R在程序中,还需要包括以下语句,指示链接程序在msvcrt.lib库文件寻找链接信息。includelib      msvcrt.lib2. sprintfsprintf与printf相似,它将输出保存在第1个字符串szStr中。invoke sprintf, offset szStr, offset szOutputFmtStr, A, Op, B, R3. scanfscanf是从控制台将用户的输入读入到程序的变量中,变量的类型可以是整数、字符、字符串等。scanf的调用规则和参数类型说明为:scanf           PROTO C :dword,:varargscanf的链接信息也包括在msvcrt.lib库文件中。程序中需要输入A、Op、B时,A、B是整数,OP是字符。它的第1个参数是格式字符串的地址;第2、3、4个参数分别是A、Op、B的地址。szInputFmtStr   byte    '%d %c %d', 0invoke          scanf,offset szInputFmtStr,offset A,offset Op,offset B其效果等价于:scanf("%d %c %d", &A, &Op, &B);下面的程序首先调用printf显示字符串,提示用户输入要计算的表达式,再调用scanf接收用户的输入。根据输入的运算符Op,通过条件跳转指令实现对加、减、乘、除的判断和处理。最后,调用printf输出计算结果。其执行结果为:input (a Op b, Op=+-/*, ex: 28-2): 4*54 * 5 = 20;程序清单:equation.asm(四则运算).386.model flat,stdcallOption casemap:noneincludelib      msvcrt.libscanf           PROTO C :dword,:varargprintf          PROTO C :dword,:vararg.dataszInPmt         byte    'input (a Op b, Op=+-/*, ex: 28-2): ', 0 ;szInputFmtStr   byte    '%d %c %d', 0szOutputFmtStr byte    '%d %c %d = %d', 0ah, 0szErrMsg        byte    'invalid Operation. ', 0ah, 0A               sdword ?B               sdword ?Op              dword   ?R               sdword ?.codestart:                invoke printf, offset szInPmt                invoke scanf, offset szInputFmtStr,                        offset A,                        offset Op,                        offset B                mov     eax, A                mov     ebx, B                cmp     Op, '+'                jz      lab_add                cmp     Op, '-'                jz      lab_sub                cmp     Op, '*'                jz      lab_mul                cmp     Op, '/'                jz      lab_divlab_err:                              invoke printf, offset szErrMsg                jmp     lab_exitlab_add:                      add     eax, ebx                mov     R, eax                jmp     lab_outputlab_sub:                      sub     eax, ebx                mov     R, eax                jmp     lab_outputlab_mul:                      imul    eax, ebx                mov     R, eax                jmp     lab_outputlab_div:                      cdq                idiv    ebx                mov     R, eax                jmp     lab_outputlab_output:                   invoke printf, offset szOutputFmtStr, A, Op, B, Rlab_exit:                     retend             startequation.asm在C:"asm"sample"chap-01目录中,编译连接的步骤为:(1) 进入C:"asm"sample"chap-01目录cd C:"asm"sample"chap-01(2) 设置编译环境c:"asm"bin"asmvars.bat(3) 编译连接ml /coff equation.asm /link /subsystem:console1.4 常用Windows API调用API是application programming interface的缩写,代表应用程序编程接口。API一般使用stdcall调用规则。1. MessageBoxprintf和scanf适用于控制台程序(链接选项为/subsystem:console),而带窗口的Windows程序(链接选项为/subsystem:windows)不能使用printf和scanf。这里介绍一个输出信息用的API-MessageBox。它的调用规则和参数类型说明为:MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORDMessageBoxA的链接信息包括在user32.lib库文件中。MessageBoxA的C语言原型在VC附带的"winuser.h"中提供。2. 确定函数的声明语句和库文件在编程中,应尽可能地利用已有的C的库函数和Windows API函数,以减少编程的工作量。通过查阅在MSDN(或VC等工具)资料和帮助文件、阅读示例程序等方法,弄清函数的功能以及入口、出口参数,以及每一个参数的用法。根据函数的名称、参数的个数、类型、调用规则等,写出这样的声明语句:printf          PROTO C :dword,:vararg再确定它属于哪一个库文件。常用的库文件有:msvcrt.lib、kernel32.lib、user32.lib等。函数可能返回的是一个整数、指针或其他类型。无论如何,返回值都在EAX中。要注意有些函数是通过传递地址指针的方式来改变参数的值,如scanf。1.5 读取CPU标识CPUID指令是获得CPU信息的汇编指令,它可以返回CPU类型、型号、制造商信息、商标信息、序列号、缓存等CPU相关信息。CPUID指令使用eax作为输入参数,eax、ebx、ecx、edx作为输出参数。例如:                mov     eax, 0                cpuid执行结果为:EAX = 00000002 EBX = 756E6547 ECX = 6C65746E EDX = 49656E69。结果以十六进制显示。EBX、ECX、EDX中各存储4个字符,全部12个字符为:GenuineIntel。使用eax=3作为输入参数时,在ECX、EDX中返回CPU序列号的第0~31位、第32~63位。                mov     eax, 0                cpuid;程序清单:cpuid.asm(读取CPU标识).586.model flat,stdcallOption casemap:noneincludelib      msvcrt.libprintf          PROTO C :dword,:vararg.dataszVendorID      byte 13 dup (0)szFormatStr     byte 'VendorID = %s; Processor SN = %08X%08X', 0ah.codestart:                mov     eax, 0                cpuid                mov     dword ptr szVendorID, ebx                mov     dword ptr szVendorID+4, edx                mov     dword ptr szVendorID+8, ecx                               mov     eax, 3                cpuid                invoke printf, offset szFormatStr,                        offset szVendorID, ecx, edx                retend             start程序运行结果如下所示:VendorID = GenuineIntel; Processor SN = 00000000007B70401.6 WinDbg调试工具WinDbg是微软公司发布的免费源码级调试工具。Windbg可以用于Kernel模式调试和用户模式调试,还可以调试Dump文件。使用WinDbg调试汇编程序的主要步骤为:1.首先,使用下面的命令编译、链接,产生.EXE文件。/coff选项要求MASM生成链接器所需要的COFF格式的.obj文件,/Zi则指定编译生成的目标文件中含有调试信息,/link表示要生成.EXE文件,而/subsystem:console则表示生成控制台程序。ml /coff /Zi cpuid.asm /link /subsystem:console2.启动WinDbg,从菜单File→Open Executable装入.EXE文件。3.在WinDbg命令窗口的最下方,可输入命令,按回车键执行。如:x cpuid!在窗口内显示出cpuid.exe内的所有数据变量:0:000> x cpuid!*** WARNING: Unable to verify checksum for cpuid.exe00404000 cpuid!szVendorID = 0x00 ''0040400d cpuid!szFormatStr = 0x56 'V'4.输入u命令,可以查看汇编指令:0:000> u start l ecpuid!start [cpuid.asm @ 11]:00401010 b800000000      mov     eax,000401015 0fa2            cpuid00401017 891d00404000 mov     dword ptr [cpuid!szVendorID (00404000)],ebx0040101d 891504404000 mov     dword ptr [cpuid!szVendorID+0x4 (00404004)],edx00401023 890d08404000 mov     dword ptr [cpuid!szVendorID+0x8 (00404008)],ecx00401029 b803000000      mov     eax,30040102e 0fa2            cpuid00401030 52              push    edx00401031 51              push    ecx00401032 6800404000      push    offset cpuid!szVendorID (00404000)00401037 680d404000      push    offset cpuid!szFormatStr (0040400d)0040103c e811000000      call    cpuid!printf (00401052)00401041 83c410          add     esp,10h00401044 c3              ret5.输入bp命令,可以设置断点,例如:bp start6.从菜单中选择Debug→Go,或者按F5键,可以执行到断点处。7.从菜单中选择View→Disassembly,可以看到断点处的指令以高亮方式显示。8.从菜单中选择View→Register,打开一个窗口,显示寄存器的当前值。9.在WinDbg命令窗口输入r命令,也可以显示寄存器的当前值。还可以修改寄存器的值,如“r eax=5”。10.在WinDbg命令窗口输入输入d命令,可以查看内存内容,如:“d szVendorID L c”。将d换为db、dw、dd,则指定用字节、字、双字的格式查看。L后面跟的数字则表示查看的单元个数。11.按F11、F10、Shift+F11、Ctrl+F10分别表示单步执行当前指令、执行完毕当前指令、执行完当前函数、执行到光标处,其用法与表1-2相同。1.7 实验题:用MessageBox函数显示CPU信息cpuid.asm采用的是控制台模式(链接选项为/subsystem:console),调用printf输出信息。要求:1.    使用VC 6.0建立工程文件;2.    采用带窗口的Windows程序(链接选项为/subsystem:windows);3.    使用sprintf 、MessageBoxA函数;4.    输出制造商信息、序列号;5.    输出CPU商标信息,执行CPUID的输入参数为80000002H、80000003H、80000004H,具体格式可查阅CPU指令手册。运行结果如图1-10所示:图1-10 在对话框中显示CPUID执行结果

    时间:2019-01-28 关键词: 汇编语言 vc++

  • PIC 8位单片机的汇编语言

    http://  要单片机完成一项基本任务,必须将任务分解成一些具体步骤,再要求它去逐项执行每个步骤,还要对它下命令。该命令在单片机术语中称为“指令”(inetruction)。完成一项任务所需的所有指令的有序集合就称为“程序”(programm)。这些指令要预先一条一条顺序地放到单片机的程序存贮器中,单片机在运行时,片中的cpu从程序存贮器中逐条有序取出指令,执行指令,并将有关指令执行完毕,即可完成既定任务。  不同种类的单片机有不同的一套命令(即所谓“指令系统”)。pic单片机其指令系统与51系列的完全不同。pic16f84单片机有30余条指令构成的指令系统。每条指令由14位(bit)构成,这些位是二进制码的0和1,如果要使16f84单片机端口b的b0位输出高电平,以点亮一只发光二极管led,而b口的其余各位仍保持低电平,则需要使单片机执行下列各条指令(机器码):    11000000000000    00000001100110    11000000000001    00000010000110    10100000000100   早先的技术人员就是用这样的二进制码来编写程序的。上列程序,看起来像天书,很费解,但它完全能指挥单片机的运作。因为单片机实际上是一种复杂的数字逻辑电路。我们都知道,要数字电路运作,必须相应输入高、低电平,对正逻辑而言,高电平为1,低电平为0。上述指令顺序在不同的数位上出现的0和1,经译码后,即可完成各种不同的运作,逐步完成单片机所要执行的任务,如点亮一个led。   上述各条指令的写法,虽然是完全面向单片机,是用来直接指示单片机该如何运作的。因此,这种由0、1组成的指令称为机器语言。   实际上,这种由二进码构成的指令集不但难读懂,而且用来编程也有困难。因为程序往往不是从头到尾顺序执行,有时还需中途转移到其它单元执行一段程序后再返回来。而指令是一条一条顺序存放在存贮器各个单元内的。因此,如果要转移,需指明具体转到哪个单元,即要写出该单元的地址。但在编写程序时,该程序有多长,具体要放到哪些单元中,都是未知数,又怎能具体指明要转到哪个单元呢?   由于用机器语言会使程序难写、难读,后来一种新型的语言形式——汇编语言就问世了。使用这种语言写程序较方便,也比较容易读懂。不过,和机器语言一样,不同类型的单片机有完全不同的汇编语言。就如不同地区的人有不同的方言一样。在汇编语言中,转移地址是用符号来表示的。现在,我们把上面由机器语言写成的程序改写成由汇编语言构成的程序:    movlw b‘00000000’    tris port b    movlw b‘00000001’    movwf port b    fin: goto   fin  上列各条指令实际上是英语缩写和一些数组成的。如第一条中的movlw就是move literal to w的缩写,其意义为照原样移入工作寄存器w,而“原样”就是后接引号内的数字‘00000000’。引号前的b表示后续的是二进制数。第二句是将w内的数复制到b口的三态(tri-state)控制寄存器中,以设定b口为输出,然后将00000001送入w中,再复制到b口;最后执行一条无限循环语句以保持b口的状态不变。从单片机外部看去,16f84单片机的第6脚(即b0)维持为高电平,以点亮led。   由上例可知,汇编语言较之机器语言要好懂得多。同时,最后一句自身循环也是一种转移语句,转移目的地就是此句所在单元地址,如用机器语言,就难以标出具体地址,而用汇编语言助记符fin即可替代。

    时间:2019-01-10 关键词: pic 单片机 汇编语言 嵌入式处理器

  • 51单片机汇编语言子程序调用指令RET RETI

    控制转移指令用于控制程序的流向,所控制的范围即为程序存储器区间,MCS-51系列单片机的控制转移指令相对丰富,有可对64kB程序空间地址单元进行访问的长调用、长转移指令,也有可对2kB字节进行访问的绝对调用和绝对转移指令,还有在一页范围内短相对转移及其它无条件转移指令,这些指令的执行一般都不会对标志位有影响。[3].子程序调用指令(1条)子程序是为了便于程序编写,减少那些需反复执行的程序占用多余的地址空间而引入的程序分支,从而有了主程序和子程序的概念,需要反复执行的一些程序,我们在编程时一般都把它们编写成子程序,当需要用它们时,就用一个调用命令使程序按调用的地址去执行,这就需要子程序的调用指令和返回指令。LCALL addr16;长调用指令,可在64kB空间调用子程序。此时(PC)+ 3→(PC),(SP)+ 1→(SP),(PC7-0)→(SP),(SP)+ 1→(SP),(PC15-8)→(SP),addr16→(PC),即分别从堆栈中弹出调用子程序时压入的返回地址ACALL addr11;绝对调用指令,可在2kB空间调用子程序,此时(PC)+ 2→(PC),(SP)+ 1→(SP),(PC7-0)→(SP),(SP)+ 1→(SP),(PC15-8)→(SP),addr11→(PC10-0)上面这两条指令就是在主程序中调用子程序的。RET;子程序返回指令。此时(SP)→(PC15-8),(SP)- 1→(SP),(SP)→(PC7-0),(SP)- 1→(SP)子程序返回指令子程序执行完后必须回到主程序,如何返回呢?只要执行一条返回指令就可以了,即执行RET。RETI;中断返回指令,除具有RET功能外,还具有恢复中断逻辑的功能,需注意的是,RETI指令不能用RET代替

    时间:2019-01-10 关键词: 51单片机 汇编语言 reti 调用指令 ret

  • 16位数据传送指令(1条)——mcs51单片机汇编语言

    16位数据传送指令(1条)这是89C51单片机唯一的一条16位立即数传递指令,其功能是将一个16位的立即数送入数据指针DPTR中去。其中高8位送入DPH,低8位送入DPL。MOV DPTR,#data16;#dataH→(DPH),#dataL→(DPL)16位常数的高8位送到DPH,低8位送到DPL例如:MOV DPTR,#2345则执行完程序后,DPL中的值为23,DPL中的值为45。

    时间:2019-01-09 关键词: 单片机 汇编语言 mcs51 16位数据传送指令

  • MCS-51汇编语言程序的一般格式

    与8086不同,没有代码段、数据段等区分,统一编址。程序由指令行或注释行组成,指令行每行只能写一条指令。指令前可用“标号:”表示指令地址,以便在指令中引用;标号是符号名,以字母开头。注释行应以“;”号开头;指令后也可用“;”号分隔,附加注释。程序由伪指令ORG XXXXH定位,ORG中的16位地址就是将来写入程序存储器的绝对地址。程序中的ORG应按地址从小到大排列。由ORG定位的程序段可以不连续,汇编程序将会在段间的空地址上填00H,即NOP。因此,每个ORG段的最后一条指令一般应是转移指令。数据由伪指令DB(字节)或DW(双字节)说明。数值应以数码0-9开头;尾缀说明:B-二进制,D-十进制,H-十六进制。十进制D可缺省。伪指令EQU可定义等价字段,以便用符号名代表某个操作数,例如:aa EQU 30Hbb EQU #30HMOV A,aa; aa等价于“30H”,该指令即MOV A, 30HMOV R0,bb ; bb等价于“#30H”,该指令即MOV R0,#30H

    时间:2019-01-01 关键词: mcs-51 汇编语言 一般格式

  • 两机串行通讯单片机汇编语言编程举例

    A、B两机之间串行通讯(方式1),用‘检验和’校验波特率为2400,发送缓冲区和接收缓冲区都为片内30H开始的16个字节单元。已知:fosc=11.0592MHz。设计A发送,B接收的双方协议如下:1、首先A发送‘AA’信号,B接收到后发送‘BB’应答;2、A方最多只发送20次‘AA’,若无应答,置错误标志,退出。3、A收到‘BB’后,开始发送缓冲区的数据,同时求检验和,共16个字节。4、B接收数据,存入缓冲区,并同时求检验和。5、当一个数据块发送完后,A再发送检验和(一个字节)。6、B接收到A的检验和后,再与本身的检验和比较。7、若接收正确,B方发送‘00’,否则发送‘EE‘,请求重发。8、若A方接收到‘00’,结束发送,接收到‘EE’则重发。A机的通讯程序:ASTA: MOV TMOD,#20H ;设T1方式2MOV TH1,#0F4H ;计数初值,波特率=2400MOV PCON,#0 ;SMOD=0SETB TR1 ;启动T1MOV SCON,#50H ;串口方式1,REN=1ATT0: MOV R6,#200MOV R7,#20CLR F0 ;线路故障标志=0ATT1:MOV SBUF,#0AAH ;发‘AA’联络AWA1:JBC TI,ARR1 ;查询发送中断标志位SJMP AWA1ARR1:JBC RI,ARR2 ;等待接收DJNZ R6,ARR1DJNZ R7,ATT1 ;SETB F0 ;线路故障QUIT: AJMP EXIT ;退出ARR2:MOV A,SBUF ;接收对方回应‘BB’XRL A,#0BBH ;比较应答信号是否正确?JNZ QUIT ;不正确,退出ATT2:MOV R0,#30H ;准备发送数据MOV R7,#16MOV R6,#0 ;检验和单元ATT3:MOV SBUF,@R0 ;发送一个字节MOV A,R6ADD A,@R0 ;求检验和MOV R6,AINC R0AWA2:JBC TI,ATT4SJMP AWA2 ;查询发送中断标志ATT4:DJNZ R7,ATT3 ;计数循环MOV SBUF,R6 ;数据块发送完,发送检验和AWA3:JBC TI,ARR3SJMP AWA3ARR3:JBC RI,ARR4 ;等待接收对方回应SJMP ARR3ARR4:MOV A,SBUF ;接收到对方回应JNZ ATT2 ;若是‘00’则成功,否则重发。EXIT: RETB机通讯程序:(用中断方式开始)ORG 0000HLJMP MAINORG 0023HLJMP BRR1 ;串行中断入口ORG 0030HMAIN: 。。。。。 ;主程序BSTA: MOV TMOD,#20H ;设T2方式2MOV TH1,#0F4H ;计数初值,波特率=2400MOV PCON,#0 ;SMOD=0SETB TR1 ;启动T1MOV SCON,#50H ;串口方式1,REN=1SETB ESSETB EA ;允许中断。。。。。。。。BRR1: CLR ES ;串行口中断服务程序JBC RI,BRR2 ;SJMP BRR1BRR2: MOV A,SBUF ;接收A机联络信号XRL A,#0AAHJZ BTT1 ;正确AJMP EXIT ;错误,退出BTT1: MOV SBUF,#0BBH ;发送应答BWA1:JBC TI,BRR3SJMP BWA1BRR3: MOV R0,#30H ;准备接收数据MOV R7,#10HMOV R6,#0BRR4:JBC RI,BRR5SJMP BRR4BRR5:MOV A,SBUF ;接收一个字节MOV @R0,A ;存入缓冲区INC R0ADD A,R6 ;MOV R6,A ;求检验和DJNZ R7,BRR4 ;数据块计数BWA2:JBC RI,BRR6SJMP BWA2BRR6:MOV A,SBUF ;接收对方检验和XRL A,R6 ;与本机的比较JZ BTT2MOV SBUF,#0FFH ;不同,发送‘FF’BWA3:JBC TI,BRR3 ;准备接收重发SJMP BWA3BTT2:MOV SBUF,#0 ;正确,发送‘00’EXIT: SETB ESRETI例3、 两机通讯在方式2或3,用第9位作奇偶校验。发送方:,,,,,,TTT: MOV SCON,#80H ;方式2MOV A,#data ;data为一字节数据MOV C,PSW.0 ;取奇偶位MOV TB8,C ;奇偶位送到TB8位MOV SBUF,A ;发送一个字节LOOP:JBC TI,NEXT内容来自单片机之家www.dpj100.comSJMP LOOPNEXT: ,,,,接收方:,,,,,,RRR: MOV SCON,#90H ;方式2,允许接收LOOP: JBC RI,RECESJMP LOOPRECE: MOV A,SBUF ;取出接收到的字节JB PSW。0,ONE ;判断接收方的奇偶值JB RB8,ERR ;判断发送方的奇偶值SJMP RIGHTONE : JNB RB8,ERRRIGHT: ,,,,,, ;接收正确ERR: ,,,,,,, ;接收有错

    时间:2018-12-26 关键词: 单片机 串行通讯 汇编语言

  • 判布尔累加器转移的汇编语言程序举例

    JCrel;(C)= 1,转移,否则顺序执行。JNCrel;(C)= 0,转移,否则顺序执行。不影响标志。转移地址 :(PC)(PC)+ rel例、比较内部RAM的30H和40H单元中的二个无符号数的大小,将大数存入20H单元,小数存入21H单元,若二数相等,则使内RAM的第127位置1。解:MOVA,30HCJNEA,40H,LOOPSETB7FHSJMP$LOOP1:JCLOOP2MOV20H,AMOV21H,40HSJMP$LOOP2:MOV20H,40HMOV21H,ASJMP$

    时间:2018-12-14 关键词: 汇编语言 判布尔累加器转移

  • 51单片机汇编语言带借位减法指令(4条)

    这组指令包含立即数、直接地址、间接地址及工作寄存器与累加器A连同借位位C内容相减,结果送回累加器A中。这里我们对借位位C的状态作出说明,在进行减法运算中,CY=1表示有借位,CY=0则无借位。OV=1声明带符号数相减时,从一个正数减去一个负数结果为负数,或者从一个负数中减去一个正数结果为正数的错误情况。在进行减法运算前,如果不知道借位标志位C的状态,则应先对CY进行清零操作。SUBB A,data;(A)-(data)-(C)→(A) 累加器A中的内容与直接地址单元中的内容、连同借位位相减,结果存在A中SUBB A,#data;(A)-#data -(C)→(A) 累加器A中的内容与立即数、连同借位位相减,结果存在A中SUBB A,Rn;(A)-(Rn)-(C)→(A) 累加器A中的内容与工作寄存器中的内容、连同借位位相减,结果存在A中SUBB A,@Ri;(A)-((Ri))-(C)→(A) 累加器A中的内容与工作寄存器Ri指向的地址单元中的内容、连同借位位相减,结果存在A中

    时间:2018-12-10 关键词: 51单片机 汇编语言 带借位减法指令

首页  上一页  1 2 3 4 5 6 7 下一页 尾页
发布文章

技术子站

更多

项目外包