




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第4章单片机程序设计方法4.1
汇编程序设计方法
4.1.1程序编制的方法和技巧
4.1.2源程序的编辑和汇编
4.1.3
基本程序结构
4.1.4
常用程序举例4.2C51程序设计方法
4.2.1C语言的特点及程序结构
4.2.2C51的数据类型
4.2.351的运算量
4.2.4C51的运算符及表达式
4.2.5表达式语句及复合语句
4.2.6C51的输入输出
4.2.7C51程序基本结构与相关语句
4.2.8函数●基本要求:
1.掌握汇编语言程序设计方法.
2.具备较复杂程序设计能力.3.掌握C语言结构和编程方法
●学习重点:
1.汇编语言程序设计方法
.
2.循环结构程序的编写.
4.1.1
程序编制的方法和技巧
1.程序编制的步骤1)预完成任务的分析首先,要对单片机应用系统预完成的任务进行深入的分析,明确系统的设计任务、功能要求和技术指标。其次,要对系统的硬件资源和工作环境进行分析。这是单片机应用系统程序设计的基础和条件。2)进行算法的优化算法是解决具体问题的方法。应用系统经过分析、研究和明确规定后,对应实现的功能和技术指标可以利用严密的数学方法或数学模型来描述,从而把实际问题转化成由计算机进行处理的问题。
同一个问题的算法可以有多种,结果也可能不尽相同,所以,应对各种算法进行分析比较,并进行合理的优化。比如,用迭代法解微分方程,需要考虑收敛速度的快慢(即在一定的时间里能否达到精度要求)。而有的问题则受内存容量的限制而对时间要求并不苛刻。对于后一种情况,速度不快但节省内存的算法则应是首选。3)程序总体设计及流程图绘制经过任务分析、算法优化后,就可以进行程序的总体构思,确定程序的结构和数据形式,并考虑资源的分配和参数的计算等。然后根据程序运行的过程,勾画出程序执行的逻辑顺序,用图形符号将总体设计思路及程序流向绘制在平面图上,从而使程序的结构关系直观明了,便于检查和修改。清晰正确的流程图是编制正确无误的应用程序的基础和条件。所以,绘制一个好的流程图,是程序设计的一项重要内容。流程图可以分为总流程图和局部流程图。总流程图侧重反映程序的逻辑结构和各程序模块之间的相互关系。局部流程图反映程序模块的具体实施细节。对于简单的应用程序,可以不画流程图。但是当程序较为复杂时,绘制流程图是一个良好的编程习惯。常用的流程图符号有:开始和结束符号、工作任务符号、判断分支符号、程序连接符号、程序流向符号等
2.编制程序的方法和技巧1)采用模块化程序设计方法应用系统的程序由包含多个模块的主程序和各种子程序组成。各程序模块都要完成一个明确的任务,实现某个具体的功能,如:发送、接收、延时、打印和显示等。模块化的程序设计方法具有明显的优点。把一个多功能的复杂的程序划分为若干个简单的、功能单一的程序模块,有利于程序的设计和调试,有利于程序的优化和分工,提高了程序的阅读性和可靠性,使程序的结构层次一目了然。2.尽量采用循环结构和子程序采用循环结构和子程序可以使程序的长度减少、占用内存空间减少。多重循环,注意各重循环的初值和循环结束条件,避免出现“死循环”现象;通用的子程序,除了用于存放子程序入口参数的寄存器外,子程序中用到的其它寄存器的内容应压入堆栈进行现场保护,并要特别注意堆栈操作的压入和弹出的平衡;中断处理子程序除了要保护程序中用到的寄存器外,还应保护标志寄存器。3.汇编语言的语句格式语句行由四个字段组成:
[标号:]操作码[操作数][;注释]
括号内的部分可以根据实际情况取舍。每个字段之间要用分隔符分隔,可以用作分隔符的符号有空格、冒号、逗号、分号等。如:LOOP:MOVA,#7FH;A←7FH1)标号标号是语句地址的标志符号,用于引导对该语句的非顺序访问。有关标号的规定为:2)操作码操作码用于规定语句执行的操作。它是汇编语句中唯一不能空缺的部分。它由指令助记符表示。
由1~8个ASCII字符组成。第一个字符必须是字母,其余字符可以是字母、数字或其他特定字符;不能使用已经定义了的符号作为标号。如指令助记符、寄存器符号名称等;后边必须跟冒号。3)操作数操作数用于给指令的操作提供数据或地址。在一条汇编语句中操作数可能是空缺的,也可能包括一项,还可能包括两项或三项。各操作数间以逗号分隔。操作数字段的内容可能包括以下几种情况:(1)工作寄存器名;(2)特殊功能寄存器名;(3)标号名;(4)常数;(5)符号“$”,表示程序计数器PC的当前值;(6)表达式。4)注释
注释只是对语句的说明。注释字段可以增加程序的可读性,有助于编程人员的阅读和维护。注释字段必须以分号“;”开头,长度不限,当一行书写不下时,可以换行接着书写,但换行时应注意要在开头使用分号“;”。5)数据的表示形式数据可以有以下几种表示形式:二进制数,末尾以字母B标识。如:10001111B;十进制数,末尾以字母D标识或将字母D省略。如:88D,66;十六进制数,末尾以字母H标识。如:78H,0A8H(但应注意的是,十六进制数以字母A~F开头时应在其前面加上数字“0”。);ASCII码,以单引号括起来标识。如:‘AB’,‘1245’
4.1.2源程序的编辑和汇编
1)源程序的编辑源程序的编写要依据80C51汇编语言的基本规则,特别要用好常用的汇编命令(即伪指令),例如下面的程序段:
ORG0040HMOVA,#7FHMOVR1,#44HEND
这里的ORG和END是两条伪指令,其作用是告诉汇编程序此汇编源程序的起止位置。编辑好的源程序应以“.ASM”扩展名存盘,以备汇编程序调用。
1.源程序的编辑与汇编2)源程序的汇编
将汇编语言源程序转换为单片机能执行的机器码形式的目标程序的过程叫汇编。常用的方法有两种:手工汇编时,把程序用助记符指令写出后,通过手工方式查指令编码表,逐个把助记符指令翻译成机器码,然后把得到的机器码程序(以十六进制形式)键入到单片机开发机中,并进行调试。机器汇编是在常用的个人计算机PC上,使用交叉汇编程序将汇编语言源程序转换为机器码形式的目标程序。生成的目标程序由PC机传送到开发机上,经调试无误后,再固化到单片机的程序存储器ROM中。源程序经过机器汇编后,形成的若干文件中含有两个主要文件,一是列表文件,另一个是目标码文件。因汇编软件的不同,文件的格式及信息会有一些不同。但主要信息如下:列表文件:地址目标码汇编程序
ORG0040H0040H747FMOVA,#7FH0042H7944MOVR1,#44HEND目标码文件:首地址末地址目标码0040H0044H747F7944
伪指令是汇编程序能够识别并对汇编过程进行某种控制的汇编命令。它不是单片机执行的指令,所以没有对应的可执行目标码,汇编后产生的目标程序中不会再出现伪指令。2.伪指令1)起始地址设定伪指令ORG格式为:
ORG表达式该指令的功能是向汇编程序说明下面紧接的程序段或数据段存放的起始地址。表达式通常为16进制地址,也可以是已定义的标号地址。
ORG8000HSTART:MOVA,#30H……
此时规定该段程序的机器码从地址8000H单元开始存放。在每一个汇编语言源程序的开始,都要设置一条ORG伪指令来指定该程序在存储器中存放的起始位置。若省略ORG伪指令,则该程序段从0000H单元开始存放。在一个源程序中,可以多次使用ORG伪指令规定不同程序段或数据段存放的起始地址,但要求地址值由小到大依序排列,不允许空间重叠。
2)汇编结束伪指令END格式为:
END
该指令的功能是结束汇编。汇编程序遇到END伪指令后即结束汇编。处于END之后的程序,汇编程序将不处理。3)字节数据定义伪指令DB[标号:]DB字节数据表
功能是从标号指定的地址开始,在ROM中定义字节数据。该伪指令将字节数据表中的数据根据从左到右的顺序依次存放在指定的存储单元中。一个数据占一个存储单元。例如:DB“howareyou?”把字符串中的字符以ASCII码的形式存放在连续的ROM单元中。又如:DB-2,-4,-6,8,10,18把6个数转换为十六进制表示(FEH,FCH,FAH,08H,0AH,12H),并连续地存放在6个ROM。
该伪指令常用于存放数据表格。如要存放显示用的十六进制的字形码,可以用多条DB指令完成:
DB0C0H,0F9H,0A4H,0B0HDB99H,92H,82H,0F8HDB80H,90H,88H,83HDB0C6H,0A1H,86H,84H4)字数据定义伪指令DW[标号:]DW字数据表功能是从标号指定的地址单元开始,在程序存储器中定义字数据。该伪指令将字或字表中的数据根据从左到右的顺序依次存放在指定的存储单元中。应特别注意:16位的二进制数,高8位存放在低地址单元,低8位存放在高地址单元。例如:
ORG1400HDATA:DW324AH,3CH……
汇编后,(1400H)=32H,(1401H)=4AH,(1402H)=00H,(1403H)=3CH。5)空间定义伪指令DS[标号:]DS表达式功能是从标号指定的地址单元开始,在程序存储器中保留由表达式所指定的个数的存储单元作为备用的空间,并都填以零值。例如:
ORG3000HBUF:DS50……
汇编后,从地址3000H开始保留50个存储单元作为备用单元。
6)赋值伪指令EQU符号名EQU表达式功能是将表达式的值(一个8位或16位的数)或特定的某个汇编符号定义为一个指定的符号名。例如:A09EQUR1
LENEQU10SUMEQU21HBLOCKEQU22HCLRAMOVR7,#LENMOVR0,#BLOCKLOOP:ADDA,@R0INCR0DJNZR7,LOOPMOVSUM,AEND
该程序的功能是,把BLOCK单元开始存放的10个无符号数进行求和,并将结果存入SUM单元中。
7)数据地址赋值伪指令:字符名DATAnnDATA指令与EQU指令功能类似,它是将16位地址赋值所定义的字符名。DATA指令与EQU指令主要的区别是:EQU定义的名必须先定义后使用,而DATA定义的字符名没有这种限制,故DATA伪指令通常用在原程序的开头或末尾。8)位地址符号定义伪指令BIT格式为:符号名BIT位地址表达式功能是将位地址赋给指定的符号名。其中,位地址表达式可以是绝对地址,也可以是符号地址。例如:
STBITP1.0将P1.0的位地址赋给符号名ST,在其后的编程中就可以用ST来代替P1.0。4.1.3基本程序结构程序的基本算法结构有3种:顺序结构、分支(选择)结构和循环结构。
循环结构(a)当型循环;(b)直到型循环1.顺序程序顺序程序是指无分支、无循环结构的程序。其执行流程是依指令在存储器中的存放顺序进行的。一、数据传送例内部RAM的2AH~2EH单元中存储的数据如图所示。试编写程序实现图示的数据传送结果。方法一:MOVA,2EH;2字节,1个机器周期MOV2EH,2DH;3字节,2个机器周期MOV2DH,2CH;3字节,2个机器周期MOV2CH,2BH;3字节,2个机器周期MOV2BH,#00H;3字节,2个机器周期方法二:CLRA;1字节,1个机器周期XCHA,2BH;2字节,1个机器周期XCHA,2CH;2字节,1个机器周期XCHA,2DH;2字节,1个机器周期XCHA,2EH;2字节,1个机器周期以上两种方法均可以实现所要求的传送任务。方法一使用14个字节的指令代码,执行时间为9个机器周期;方法二仅用了9个字节的代码,执行时间也减少到了5个机器周期。实际应用中应尽量采用指令代码字节数少、执行时间短的高效率程序,即注意程序的优化。
例有一变量存放在片内RAM的20H单元,其取值范围为:00H~05H。要求编制一段程序,根据变量值求其平方值,并存入片内RAM的21H单元。程序如下:
ORG1000HSTART:MOVDPTR,#2000HMOVA,20HMOVCA,@A+DPTRMOV21H,ASJMP$ORG2000HTABLE:DB00,01,04,09,16,25END。
在程序存储器的一片存储单元中建立起该变量的平方表。用数据指针DPTR指向平方表的首址,则变量与数据指针之和的地址单元中的内容就是变量的平方值。采样MOVCA,@A+PC指令也可以实现查表功能,且不破坏DPTR的内容,从而可以减少保护DPTR的内容所需的开销。但表格只能存放在MOVCA,@A+PC指令后的256字节内,即表格存放的地点和空间有一定限制。
简单运算由于80C51指令系统中只有单字节加法指令,因此对于多字节的相加运算必须从低位字节开始分字节进行。除最低字节可以使用ADD指令外,其他字节相加时要把低字节的进位考虑进去,这时就应该使用ADDC指令。例双字节无符号数加法。设被加数存放在内部RAM的51H、50H单元,加数存放在内部RAM的61H、60H单元,相加的结果存放在内部RAM的51H、50H单元,进位存放在位寻址区的00H位中。
程序段如下:MOVR0,#50H;被加数的低字节地址 MOVR1,#60H;加数的低字节地址 MOVA,@R0;取被加数低字节ADDA,@R1;加上加数低字节MOV@R0,A;保存低字节相加结果INCR0;指向被加数高字节INCR1;指向加数高字节MOVA,@R0;取被加数高字节ADDCA,@R1;加上加数高字节(带进位加)MOV@R0,A;存高字节相加结果MOV00H,C;保存进位。
2.分支程序分支结构可以分成单分支、双分支和多分支几种情况:1)单分支程序例求单字节有符号数的二进制补码。设有一个单字节二进制数存于A中,编写程序求起补码。程序如下:START:JNBACC.7,OK;(A)>0,MOVC,ACC.7WOVA,@R0CPLAADDA,#1MOVACC.7COK:RET
例求双字节补码。设在内部RAM的addr1和addr+1单元存有一个双字节数(高位字节存于高地址单元)。编写程序将其读出取补后再存入addr2和addr2+1单元。首先对低字节取补,然后判其结果是否为全“0”。若是,则高字节取补,否则高字节取反。
START:MOVR0,#addr1;原码低字节地址送R0 MOVR1,#addr2;补码低字节地址送R1 MOVA,@R0;原码低字节送A CPLA;A内容取补
INCAMOV@R1,A;存补码低字节
INCR0;调整地址,指向下一单元
INCR1JZZERO;(A)=0时转ZEROMOVA,@R0;原码高字节送A CPLAMOV@R1,A;高字节反码存入addr2+1单元
SJMPLOOP1ZERO:MOVA,@R0;高字节取补存入addr2+1单元
CPLAINCAMOV@R1,ALOOP1:RET2)双分支程序例设变量x以补码的形式存放在片内RAM的30H单元,变量y与x的关系是:当x大于0时,y=x;当x=0时,y=20H;当x小于0时,y=x+5。编制程序,根据x的大小求y并送回原单元。程序段如下:START:MOVA,30HJZNEXTANLA,#80H;判断符号位
JZLPMOVA,#05HADDA,30HMOV30H,ASJMPLPNEXT:MOV30H,#20HLP:SJMP$
3)多分支程序例:根据R7的内容转向相应的处理程序。设R7的内容为0~N,对应的处理程序的入口地址分别为PP0~PPN。程序段如下:START:MOVDPTR,#TAB;置分支入口地址表首址
MOVA,R7;分支转移序号送AADDA,R7;分支转移序号乘以2MOVR3,A;暂存于R3MOVCA,@A+DPTR;取高位地址
XCHA,R3INCAMOVCA,@A+DPTR;取低位地址
MOVDPL,A;处理程序入口地址低8位送DPLMOVDPH,R3;处理程序入口地址高8位送DPHCLRAJMP@A+DPTRTAB:DWPP0DWPP1………DWPPN
3.循环程序按某种控制规律重复执行的程序称为循环程序。循环程序有先执行后判断和先判断后执行两种基本结构:1)先执行后判断例50ms延时程序。若晶振频率为12MHz,则一个机器周期为1μs。执行一条DJNZ指令需要2个机器周期,即2μs。采用循环计数法实现延时,循环次数可以通过计算获得,并选择先执行后判断的循环结构。程序段如下:
DEL:MOVR7,#200;1μsDEL1:MOVR6,#123;1μsNOP ;1μsDEL2:DJNZR6,DEL2;2μs,计(2×123)μsDJNZR7,DEL1;2μs,
RET
共计[(2×123+2+2)×200+1]μs,即50.001ms
例:无符号数排序程序。在片内RAM中,起始地址为30H的8个单元中存放有8个无符号数。试对这些无符号数进行升序排序。数据排序常用的方法是冒泡排序法。执行时从前向后进行相邻数的比较,如数据的大小次序与要求的顺序不符就将这两个数互换,否则不互换。对于升序排序,通过这种相邻数的互换,使小数向前移动,大数向后移动。从前向后进行一次冒泡(相邻数的互换),就会把最大的数换到最后。再进行一次冒泡,就会把次大的数排在倒数第二的位置。设R7为比较次数计数器,初始值为07H,位地址00H为数据互换标志位。
START:CLR00H;互换标志清0 MOVR7,#07H;各次冒泡比较次数
MOVR0,#30H;数据区首址
LOOP:MOVA,@R0;取前数
MOV2BH,A;暂存
INCR0MOV2AH,@R0;取后数
CLRCSUBBA,@R0;前数减后数
JCNEXT;前数小于后数,不互换
MOV@R0,2BHDECR0MOV@R0,2AH;两数交换
INCR0;准备下一次比较
SETB00H;置互换标志
NEXT:DJNZR7,LOOP;进行下一次比较
JB00H,START;进行下一轮冒泡
SJMP$2)先判断后执行
例将内部RAM中起始地址为data的数据串传送到外部RAM中起始地址为buffer的存储区域内,直到发现‘$’字符停止传送。由于循环次数事先不知道,但循环条件可以测试到。所以,采用先判断后执行的结构比较适宜。程序段如下:
MOVR0,#dataMOVDPTR,#bufferLOOP0:MOVA,@R0CJNEA,#24H,LOOP1;判断是否为‘$’字符
SJMPLOOP2;是‘$’字符,转结束LOOP1:MOVX@DPTR,A;不是‘$’字符,执行传送
INCR0INCDPTRSJMPLOOP0;传送下一数据
LOOP2:……4.子程序及其调用1)子程序的调用在实际应用中,经常会遇到一些带有通用性的问题,例如:数值转换、数值计算等,在一个程序中可能要使用多次。这时可以将其设计成通用的子程序供随时调用。
子程序主要特点是,在执行过程中需要由其它程序来调用,执行完后又需要把执行流程返回到调用该子程序的主程序。
子程序调用时要注意两点:一是现场的保护和恢复;二是主程序与子程序的参数传递。2)现场保护与恢复
在子程序执行过程中常常要用到单片机的一些通用单元,如工作寄存器R0~R7、累加器A、数据指针DPTR,以及有关标志和状态等。而这些单元中的内容在调用结束后的主程序中仍有用,所以需要进行保护,称为现场保护。在执行完子程序,返回继续执行主程序前恢复其原内容,称为现场恢复。保护与恢复的方法有以下两种:在主程序中实现;在子程序中实现。
在主程序中实现示例如下:
PUSHPSW;保护现场
PUSHACC;
PUSHB;
MOVPSW,#10H;换当前工作寄存器组
LCALLaddr16;子程序调用
POPB;恢复现场
POPACC;
POPPSW;
……
其特点是结构灵活。
在子程序中实现示例如下:SUB1:PUSHPSW;保护现场
PUSHACC;
PUSHB;
……MOVPSW,#10H;换当前工作寄存器组
……POPB;恢复现场
POPACC;
POPPSW;
RET其特点是程序规范、清晰。注意,无论哪种方法保护与恢复的顺序要对应。3)参数传递
由于子程序是主程序的一部分,所以,在程序的执行时必然要发生数据上的联系。在调用子程序时,主程序应通过某种方式把有关参数(即子程序的入口参数)传给子程序,当子程序执行完毕后,又需要通过某种方式把有关参数(即子程序的出口参数)传给主程序。在80C51单片机中,传递参数的方法有三种:
利用累加器或寄存器在这种方式中,要把预传递的参数存放在累加器A或工作寄存器R0~R7中。即在主程序调用子程序时,应事先把子程序需要的数据送入累加器A或指定的工作寄存器中,当子程序执行时,可以从指定的单元中取得数据,执行运算。反之,子程序也可以用同样的方法把结果传送给主程序。
例编写程序,实现c=a2+b2。设a,b,c分别存于内部RAM的30H,31H,32H三个单元中。程序段如下:START:MOVA,30H;取aACALLSQR;调用查平方表
MOVR1,A;a2暂存于R1中
MOVA,31H;取bACALLSQR;调用查平方表
ADDA,R1;a2+b2存于A中
MOV32H,A;存结果
SJMP$SQR:MOVDPTR,#TAB;子程序
MOVCA,@A+DPTR;
RETTAB:DB0,1,4,9,16,25,36,49,64,81
利用存储器当传送的数据量比较大时,可以利用存储器实现参数的传递。在这种方式中,事先要建立一个参数表,用指针指示参数表所在的位置。当参数表建立在内部RAM时,用R0或R1作参数表的指针。当参数表建立在外部RAM时,用DPTR作参数表的指针。例将R0和R1指向的内部RAM中两个3字节无符号整数相加,结果送到由R0指向的内部RAM中。入口时,R0和R1分别指向加数和被加数的低位字节;出口时,R0指向结果的高位字节。低字节在高地址,高字节在低地址。
实现程序:NADD:MOVR7,#3;三字节加法
CLRC;NADD1:MOVA,@R0;取加数低字节
ADDCA,@R1;被加数低字节加AMOV@R0,A;
DECR0DECR1DJNZR7,NADD1INCR0RET
利用堆栈利用堆栈传递参数是在子程序嵌套中常采用的一种方法。在调用子程序前,用PUSH指令将子程序中所需数据压入堆栈,进入执行子程序时,再用POP指令从堆栈中弹出数据。
例把内部RAM中20H单元中的1个字节十六进制数转换为2位ASCII码,存放在R0指示的两个单元中。
MAIN:MOVA,20H;
SWAPAPUSHACC;参数入栈
ACALLHEASCPOPACCMOV@R0,A;存高位十六进制数转换结果
INCR0;修改指针
PUSH20H;参数入栈
ACALLHEASCPOPACCMOV@R0,A;存低位十六进制数转换结果
SJMP$
HEASC:MOVR1,SP;借用R1为堆栈指针
DECR1DECR1;R1指向被转换数据
XCHA,@R1;取被转换数据
ANLA,#0FH;取一位十六进制数
ADDA,#2;所加值为MOVC与DB间字节数
MOVCA,@A+PC;查表
XCHA,@R1;1字节指令,存结果于堆栈
RET;1字节指令ASCTAB:DB30H,31H,32H,33H,34H,35H,36H,37HDB38H,39H,41H,42H,43H,44H,45H,46H
一般说来:当相互传递的数据较少时,采用寄存器传递方式可以获得较快的传递速度;当相互传递的数据较多时,宜采用存储器或堆栈方式传递;如果是子程序嵌套时,最好是采用堆栈方式。4.1.4常用程序举例1.算术运算程序
1)多字节数的加、减运算
80C51单片机的指令系统提供的是字节运算指令,所以在处理多字节数的加减运算时,要合理地运用进位(借位)标志。例:多字节无符号数的加法。设两个N字节的无符号数分别存放在内部RAM中以DATA1和DATA2开始的单元中。相加后的结果要求存放在DATA2数据区。
MOVR0,#DATA1;
MOVR1,#DATA2;
MOVR7,#N; 置字节数
CLRC;LOOP:MOVA,@R0;
ADDCA,@R1;求和
MOV@R1,A;存结果
INCR0;修改指针
INCR1;
DJNZR7,LOOP;例:多字节无符号数的减法。
设两个N字节的无符号数分别存放在内部RAM中以DATA1和DATA2开始的单元中。相减后的结果要求存放在DATA2数据区。
MOVR0,#DATA1;
MOVR1,#DATA2;
MOVR7,#N;置字节数
CLRC;LOOP:MOVA,@R0;
SUBBA,@R1;求差
MOV@R1,A;存结果
INCR0;修改指针
INCR1;
DJNZR7,LOOP;2)多字节数乘法运算例双字节无符号数的乘法。设双字节的无符号被乘数存放在R3、R2中,乘数存放在R5、R4中,R0指向积的高位。
主程序段如下:MULTB:MOVR7,#04;结果单元清0LOOP:MOV@R0,#00H;
DJNZR7,LOOP;
DECR0ACALLBMUL;
SJMP$另有2段子程序:
BMULRADD(在BMUL中被调用)先看子程序段:
RADD:ADDA,@R0;
MOV@R0,A;
MOVA,B;
INCR0;
ADDCA,@R0;
MOV@R0,A;
INCR0;
MOVA,@R0;
ADDCA,#00H;加进位
MOV@R0,A;
RETBMUL:MOVA,R2;
MOVB,R4;
MULAB;低位乘
ACALLRADD;
MOVA,R2;
MOVB,R5;
MULAB;交叉乘
DECR0;
ACALLRADD;
MOVA,R4;
MOVB,R3;
MULAB;交叉乘
DECR0;
DECR0;
ACALLRADD;
MOVA,R5;
MOVB,R3;
MULAB;高字节乘
DECR0;
ACALLRADD;
DECR0RET1)十六进制数与ASCII码间的转换
十六进制数与ASCII码的对应关系如表所示。当十六进制数在0~9之间时,其对应的ASCII码值为该十六进制数加30H;当十六进制数在A~F之间时,其对应的ASCII码值为该十六进制数加37H。2.码型转换
例将1位十六进制数转换成相应的ASCII码。设十六进制数存放在R0中,转换后的ASCII码存放于R2中。实现程序如下:HASC:MOVA,R0;取4位二进制数
ANLA,#0FH;屏蔽掉高4位
PUSHACC;4位二进制数入栈
CLRC;清进(借)位位
SUBBA,#0AH;用借位位的状态判断该数在0~9还是A~F之间
POPACC;弹出原4位二进制数
JCLOOP;借位位为1,跳转至LOOPADDA,#07H;借位位为0,该数在A~F之间,加37HLOOP:ADDA,#30H;该数在0~9之间,加30HMOVR2,A;ASCII码存于R2RET
例将多位十六进制数转换成ASCII码。设地址指针R0指向十六进制数低位,R2中存放字节数,转换后地址指针R0指向十六进制数的高位。R1指向要存放的ASCII码的高位地址。实现程序如下:HTASC:MOVA,@R0;取低4位二进制数
ANLA,#0FH;
ADDA,#15;偏移量修正
MOVCA,@A+PC;查表
MOV@R1,A;存ASCII码
INCR1;
MOVA,@R0;取十六进制高4位
SWAPAANLA,#0FH;
ADDA,#06H;偏移值修正
MOVCA,@A+PC;
MOV@R1,AINCR0;指向下一单元
INCR1;
DJNZR2,HTASC;字节数存于R2RETASCTAB:DB30H,31H,32H,33H,34H,35H,36H,37HDB38H,39H,41H,42H,43H,44H,45H,46H2)BCD码与二进制数之间的转换在计算机中,十进制数要用BCD码来表示。通常,用四位二进制数表示一位BCD码,用1个字节表示2位BCD码(称为压缩型BCD码)。例双字节二进制数转换成BCD码。设(R2R3)为双字节二进制数,(R4R5R6)为转换完的压缩型BCD码。十进制数B与一个8位的二进制数的关系可以表示为:
只要依十进制运算法则,将bi(i=7,6,……,1,0)按权相加,就可以得到对应的十进制数B。(逐次得到:b7×20;b7×21+b6×20;b7×22+b6×21+b5×20;…)。DCDTH:CLRA;
MOVR4,A;R4清0MOVR5,A;R5清0MOVR6,A;R6清0MOVR7,#16;计数初值LOOP:CLRC;
MOVA,R3;
RLCA;
MOVR3,A;R3左移一位并送回
MOVA,R2;
RLCA;
MOVR2,A;R2左移一位并送回
MOVA,R6;
ADDCA,R6;
DAA;
MOVR6,A;(R6)乘2并调整后送回
MOVA,R5;
ADDCA,R5;
DAA;
MOVR5,A;(R5)乘2并调整后送回
MOVA,R4;
ADDCA,R4;
DAA;
MOVR4,A;(R4)乘2并调整后送回
DJNZR7,LOOP;4.2C51程序设计方法4.2.1C语言的特点及程序结构
1.C语言的特点语言简洁、紧凑,使用方便、灵活。运算符丰富。数据结构丰富。具有现代化语言的各种数据结构。可进行结构化程序设计。可以直接对计算机硬件进行操作。生成的目标代码质量高,程序执行效率高。可移植性好。2.C语言的程序结构C语言程序采用函数结构,每个C语言程序由一个或多个函数组成,在这些函数中至少应包含一个主函数main(),也可以包含一个main()函数和若干个其它的功能函数。不管main()函数放于何处,程序总是从main()
函数开始执行,执行到main()函数结束则结束。在main()函数中调用其它函数,其它函数也可以相互调用,但main()函数只能调用其它的功能函数,而不能被其它的函数所调用。功能函数可以是C语言编译器提供的库函数,也可以是由用户定义的自定义函数。在编制C程序时,程序的开始部分一般是预处理命令、函数说明和变量定义等。3.C语言程序结构一般如下:预处理命令include<>函数说明longfun1()floatfun2();
int
x,y;floatz;功能函数主函数功能函数功能函数1fun1(){
函数体…}主函数
main(){
主函数体…}功能函数2fun2(){
函数体…}4.2.2C51的数据类型
C51的数据类型分为基本数据类型和组合数据类型,情况与标准C中的数据类型基本相同,但其中char型与short型相同,float型与double型相同,另外,C51中还有专门针对于MCS-51单片机的特殊功能寄存器型和位类型。1.字符型char
有signedchar和unsignedchar之分,默认为signedchar。它们的长度均为一个字节,用于存放一个单字节的数据。对于signedchar,它用于定义带符号字节数据,其字节的最高位为符号位,“0”表示正数,“1”表示负数,补码表示,所能表示的数值范围是-128~+127;对于unsignedchar,它用于定义无符号字节数据或字符,可以存放一个字节的无符号数,其取值范围为0~255。unsignedchar可以用来存放无符号数,也可以存放西文字符,一个西文字符占一个字节,在计算机内部用ASCII码存放。2.int整型分singedint和unsignedint。默认为signedint。它们的长度均为两个字节,用于存放一个双字节数据。对于signedint,用于存放两字节带符号数,补码表示,数的范畴为-32768~+32767。对于unsignedint,用于存放两字节无符号数,数的范围为0~65535。3.long长整型分singedlong和unsignedlong。默认为signedlong。它们的长度均为四个字节,用于存放一个四字节数据。对于signedlong,用于存放四字节带符号数,补码表示,数的范畴为-2147483648~+2147483647。对于unsignedlong,用于存放四字节无符号数,数的范围为0~4294967295。4.float浮点型
float型数据的长度为四个字节,格式符合IEEE-754标准的单精度浮点型数据,包含指数和尾数两部分,最高位为符号位,“1”表示负数,“0”表示正数,其次的8位为阶码,最后的23位为尾数的有效数位,由于尾数的整数部分隐含为“1”,所以尾数的精度为24位。5.指针型指针型本身就是一个变量,在这个变量中存放的指向另一个数据的地址。这个指针变量要占用一定的内存单元,对不同的处理器其长度不一样,在C51中它的长度一般为1~3个字节。6.特殊功能寄存器型这是C51扩充的数据类型,用于访问MCS-51单片机中的特殊功能寄存器数据,它分sfr和sfr16两种类型,其中sfr为字节型特殊功能寄存器类型,占一个内存单元,利用它可以访问MCS-51内部的所有特殊功能寄存器;sfr16为双字节型特殊功能寄存器类型,占用两个字节单元,利用它可以访问MCS-51内部的所有两个字节的特殊功能寄存器。在C51中对特殊功能寄存器的访问必须先用sfr或sfr16进行声明。7.位类型这也是C51中扩充的数据类型,用于访问MCS-51单片机中的可寻址的位单元。在C51中,支持两种位类型:bit型和sbit型。它们在内存中都只占一个二进制位,其值可以是“1”或“0”。其中用bit定义的位变量在C51编译器编译时,在不同的时候位地址是可以变化的,而用sbit定义的位变量必须与MCS-51单片机的一个可以寻址位单元或可位寻址的字节单元中的某一位联系在一起,在C51编译器编译时,其对应的位地址是不可变化的。基本数据类型长度取值范围unsignedchar1字节0~255signedchar1字节-128~+127unsignedint2字节0~65535signedint2字节-32768~+32767unsignedlong4字节0~4294967295signedlong4字节-2147483648~+2147483647float4字节1.175494E-38~3.402823E+38bit1位0或1Sbit1位0或1sfr1字节0~255sfr162字节0~65535在C51语言程序中,有可能会出现在运算中数据类型不一致的情况。C51允许任何标准数据类型的隐式转换,隐式转换的优先级顺序如下:bitcharintlongfloatsignedunsigned也就是说,当char型与int型进行运算时,先自动对char型扩展为int型,然后与int型进行运算,运算结果为int型。C51除了支持隐式类型转换外,还可以通过强制类型转换符“()”对数据类型进行人为的强制转换。C5l编译器除了能支持以上这些基本数据类型之外,还能支持一些复杂的组合型数据类型,如数组类型、指针类型、结构类型、联合类型等这些复杂的数据类型,在本书的后面将相继介绍。4.2.351的运算量
1.常量常量是指在程序执行过程中其值不能改变的量。在C51中支持整型常量、浮点型常量、字符型常量和字符串型常量。
整型常量:整型常量也就是整型常数,根据其值范围在计算机中分配不同的字节数来存放。在C51中它可以表示成以下几种形式:十进制整数。如234、-56、0等。十六进制整数。以0x开头表示,如0x12表示十六进制数12H。长整数。在C51中当一个整数的值达到长整型的范围,则该数按长整型存放,在存储器中占四个字节,另外,如一个整数后面加一个字母L,这个数在存储器中也按长整型存放。如123L在存储器中占四个字节。浮点型常量:浮点型常量也就是实型常数。有十进制表示形式和指数表示形式。十进制表示形式又称定点表示形式,由数字和小数点组成。如0.123、34.645等都是十进制数表示形式的浮点型常量。指数表示形式为:[]数字[.数字]e[]数字例如:123.456e-3、-3.123e2等都是指数形式的浮点型常量。字符型常量:字符型常量是用单引号引起的字符,如‘a’、‘1’、‘F’等。可以是可显示的ASCII字符,也可以是不可显示的控制字符。对不可显示的控制字符须在前面加上反斜杠“\”组成转义字符。利用它可以完成一些特殊功能和输出时的格式控制。常用的转义字符如表4-2所示。转义字符含
义ASCII码(十六进制数)\o空字符(null)00H\n换行符(LF)0AH\r回车符(CR)0DH\t水平制表符(HT)09H\b退格符(BS)08H\f换页符(FF)0CH\‘单引号27H\”双引号22H\\反斜杠5CH字符串型常量:字符串型常量由双引号“”括起的字符组成。如“D”、“1234”、“ABCD”等。注意字符串常量与字符常量是不一样,一个字符常量在计算机内只用一个字节存放,而一个字符串常量在内存中存放时不仅双引号内的字符一个占一个字节,而且系统会自动的在后面加一个转义字符“\o”作为字符串结束符。因此不要将字符常量和字符串常量混淆,如字符常量‘A’和字符串常量“A”是不一样的。2变量变量是在程序运行过程中其值可以改变的量。一个变量由两部分组成:变量名和变量值。在C51中,变量在使用前必须对变量进行定义,指出变量的数据类型和存储模式。以便编译系统为它分配相应的存储单元。定义的格式如下:
[存储种类]数据类型说明符[存储器类型]变量名1[=初值],变量名2[初值]…;数据类型说明符:在定义变量时,必须通过数据类型说明符指明变量的数据类型,指明变量在存储器中占用的字节数。可以是基本数据类型说明符,也可以是组合数据类型说明符,还可以是用typedef定义的类型别名。在C51中,为了增加程序的可读性,允许用户为系统固有的数据类型说明符用typedef起别名,格式如下:
typedefc51固有的数据类型说明符别名;定义别名后,就可以用别名代替数据类型说明符对变量进行定义。别名可以用大写,也可以用小写,为了区别一般用大写字母表示。【例4-1】
typedef的使用。typedefunsignedintWORD;typedefunsignedcharBYTE;BYTEa1=0x12;WORDa2=0x1234;变量名:变量名是C51区分不同变量,为不同变量取的名称。在C51中规定变量名可以由字母、数字和下划线三种字符组成,且第一个字母必须为字母或下划线。变量名有两种:普通变量名和指针变量名。它们的区别是指针变量名前面要带“*”号。存储种类:存储种类是指变量在程序执行过程中的作用范围。C51变量的存储种类有四种,分别是自动(auto)、外部(extern)、静态(static)和寄存器(register)。auto:使用auto定义的变量称为自动变量,其作用范围在定义它的函数体或复合语句内部,当定义它的函数体或复合语句执行时,C51才为该变量分配内存空间,结束时占用的内存空间释放。自动变量一般分配在内存的堆栈空间中。定义变量时,如果省略存储种类,则该变量默认为自动(auto)变量。extern:使用extern定义的变量称为外部变量。在一个函数体内,要使用一个已在该函数体外或别的程序中定义过的外部变量时,该变量在该函数体内要用extern说明。外部变量被定义后分配固定的内存空间,在程序整个执行时间内都有效,直到程序结束才释放。static:使用static定义的变量称为静态变量。它又分为内部静态变量和外部静态变量。在函数体内部定义的静态变量为内部静态变量,它在对应的函数体内有效,一直存在,但在函数体外不可见,这样不仅使变量在定义它的函数体外被保护,还可以实现当离开函数时值不被改变。外部静态变量上在函数外部定义的静态变量。它在程序中一直存在,但在定义的范围之外是不可见的。如在多文件或多模块处理中,外部静态变量只在文件内部或模块内部有效。register:使用register定义的变量称为寄存器变量。它定义的变量存放在CPU内部的寄存器中,处理速度快,但数目少。C51编译器编译时能自动识别程序中使用频率最高的变量,并自动将其作为寄存器变量,用户可以无需专门声明。3.存储器类型存储器类型是用于指明变量所处的单片机的存储器区域情况。存储器类型与存储种类完全不同。C51编译器能识别的存储器类型有以下几种,见表所示。存储器类型描
述
data直接寻址的片内RAM低128B,访问速度快
bdata片内RAM的可位寻址区(20H~2FH),允许字节和位混合访问
idata间接寻址访问的片内RAM,允许访问全部片内RAM
pdata用Ri间接访问的片外RAM的低256B
xdata用DPTR间接访问的片外RAM,允许访问全部64k片外RAM
code程序存储器ROM64k空间定义变量时也可以省“存储器类型”,省时C51编译器将按编译模式默认存储器类型,具体编译模式的情况在后面介绍。【例4-2】变量定义存储种类和存储器类型相关情况。
chardatavarl;/*在片内RAM低128B定义用直接寻址方式访问的字符型变量var1*/
int
idatavar2;/*在片内RAM256B定
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 有机化学原料的废弃物处理与资源化考核试卷
- 智能服务机器人技术创新考核试卷
- 机械式停车设备故障预防与诊断技巧考核试卷
- 木材采运的数字化转型与智能化考核试卷
- 中介居间费合同范本
- 房主房子出租合同范本
- 维修农村管道合同范本
- 畜牧产品加工与供应合作协议
- 物联网技术应用研发生产合同书
- 电信运营商合作协议具体内容
- 广东义务教育标准化学校
- 煤质化验员测试题(附参考答案)
- 全电发票样式
- (完整版)供应商审核表
- 馒头工艺流程图
- (二次供水单位)生活饮用水卫生许可证延续申请表
- 钠电池正极材料PPT
- 体能训练概论(NSCA)
- 青岛版三年级数学下册《美丽的街景》教学课件7
- 液压传动全套ppt课件(完整版)
- 内部控制五要素图解
评论
0/150
提交评论