1 数据排序程序
在单片机应用程序中,有时要对数据进行排序。排序有从小到大,从大到小排等。
例3-52:设计一个排序程序,将单片机内RAM中若干单字节无符号的正整数,按从小到大的顺序重新排列。
解:先将不等的11个任意数据置于内RAM的50H~5AH中,设依次为56H、88H、34H、57H、18H、62H、42H、24H、01H、31H、11H。
设计程序如下(俗称冒泡法):
ORG 0000H
SOP:MOV R0,#50H;指针送R0
MOV R7,#0AH;每次冒泡比较的次数
CLR F0;交换标志清0
LOOP:MOV A,@R0;取前数
MOV R2,A;暂存前数于R2
INC R0;取后一个数
MOV 30H,@R0;后数暂存于R3
CLR C;清进位为0
CJNE A,30H,LP1;前后两数相比较
SJMP LP2
LP1:JC LP2;前数≤后数,不交换
MOV A,@R0
DEC R0;前数>后数,则交换
XCH A,@R0
INC R0
MOV @R0,A
SETB F0;置交换标志
LP2:DJNZ R7,LOOP;进行下一次比较
JB F0,SOP;一趟循环中有交换,进行下一趟冒泡
SJMP $;无交换退出
END
结果:RAM从小到大在50H~5AH中的排列依次为01H、11H、18H、24H、31H、34H、42H、56H、57H、62H、88H。
2 算术计算程序
指令系统中有加、减、乘、除、加1、减1等指令,可通过设计程序来处理一般不太复杂的算术运算。设计中要注意程序执行对PSW的影响。
例3-53:设计一个顺序程序,求解Y=(3×X+4)×5÷8-1。X的取值范围为0~15,X值存放于30H中,设(X)=4,计算结果Y存放在31H中。
解:设计程序如下:
ORG 0000H
LJMP STAR
ORG 0100H
STAR:MOV 30H,#4;X=4,(30H)=4
MOV A,30H
CLR C
RLC A,2X
ADD A,30H;(A)=3X
MOV 31H,A;(31H)=(A)=3X
MOV A,#4
ADD A,31H;(A)=3X+4
MOV B,#5
MUL AB;(A)=5(3X+4)
MOV B,#8
DIV AB;(A)=5(3X+4)/8
DEC A;(A)=[5(3X+4)/8]-1
MOV 31H,A;结果在31H中,余数在B中。
SJMP $
END
结果:(31H)=9。
例3-54:用程序实现c=a2+b2。设a、b、c存于片内RAM的3个单元R2、R3、R4中,可用子程序来实现。通过两次调用查平方表的子程序来得到a2和b2,并在主程序中完成相加。(设a、b为0~9之间的数,若a=6,b=4)
解:设计程序如下:
ORG 0000H
MOV R2,#6;赋值(R2)=6
MOV R3,#4;赋值(R3)=4
MOV A,R2;取第一个被加的数据a
ACALL SQR;第一次调用,得a2
MOV R1,A;暂存a2于R1中
MOV A,R3;取第二个被加的数据a
ACALL SQR;第二次调用,得b2
ADD A,R1;完成a2+b2
MOV R4,A;存a2+b2结果到R4
SJMP $
SQR:INC A;查表位置调整
MOVC A,@A+PC;查平方表
RET;子程序返回
TAB:DB 0,1,4,9,16,25,36,49,64,81
END
结果:(R4)=34H=52。
例3-55:设计n个正整数的求和程序。设Xi均为单字节数,并按顺序存放在内RAM以50H为首址的连续的存储单元中。数据长度(个数)n存在R2中,求S=X1+X2+…Xn,并将和数S(双字节)存放在R3、R4中(设和数<65536)。
解:取n=5,程序结构为“计数控制循环结构”。
设计程序如下:
ORG 0000H
MOV 50H,#23H;寄存器50H~54H预置数据
MOV 51H,#05H
MOV 52H,#0FFH
MOV 53H,#44H
MOV 54H,#60H;以下四条指令为置循环初值
MOV R2,#5;数据个数计数器R2置数
MOV R3,#00H;结果高位存储器R3清0
MOV R4,#00H;结果低位存储器R4清0
MOV R0,#50H;寄存器(R0)=50H
LOOP:MOV A,R4
ADD A,@R0
MOV R4,A
CLR A
ADDC A,R3
MOV R3,A;以下三条分别为循环修改、循环控制、退出循环
INC R0;循环修改
DJNZ R2,LOOP;循环控制
SJMP $;退出循环
END
结果:高位(R3)=01H;低位(R4)=CBH。
例3-56:设单片机片内存储区首地址为30H,片外存储区首地址为3000H,存取数据字节个数为16个,并将片内存储区的这16个字节的内容设置为01H~10H,将片内首地址为30H开始的16个单元的内容传送到片外首地址为3000H开始的数据存储区中保存。
解:程序代码如下。
ORG 0000H
DADDR EQU 30H;片内数据区首地址
XADDR EQU 3000H;片外数据区首地址
COUNT EQU 10H;传送数据大小,共16个字节
MAIN:MOV SP,#60H;重置堆栈指针
MOV R0,#DADDR;设置片内数据区首地址
MOV R2,#COUNT;设置传送数据区大小即16个字节
/**********片内数据区初始化**********/
INIT:MOV A,#01H
LOOP1:MOV @R0,A
INC A
INC R0
DJNZ R2,LOOP1
/**********片内外数据传送**********/
DXMOV:MOV R0,#DADDR;设置片内数据区首地址
MOV DPTR,#XADDR;设置片外数据区首地址
MOV R2,#COUNT;设置传送数据区大小即16个字节
LOOP2:MOV A,@R0
MOVX @DPTR,A
INC R0
INC DPTR
DJNZ R2,LOOP2
END
运行结果:内部数据区30H~3FH单元内容为01H~10H,片外数据区3000H~300FH内容
为01H~10H。
3 用累加器A或工作寄存器Rn传递参数
例3-57:把A中一个十六进制数的ASCII字符转换为一位十六进制数。
解:主程序部分如下:
START:
MOV A,#34H;设置入口参数于A中
LCALL ASCH;子程序入口地址为ASCH
⋮
子程序:
ASCH:CLR C
SUBB A,#30H
CJNE A,#10,$+3;$+3为下条指令的首址
JC NEXT;<10,转NEXT
SUBB A,#07H;≥0AH,则再减07H(共减37H)
NEXT:NOP
RET
4 用寄存器作为指针来传递参数
例3-58:在内RAM的40H、50H开始的空间中,分别存有单字节的无符号数据块,长度分别为12和8。编程求这两个数据块中的最大数,存入MAX单元。
思路:用子程序求某数据块的最大值。
入口参数:数据块的首地址存入R0,长度存入R2,出口参数在A中,即最大数。
解:程序如下:
FMAX:MOV A,@R0;取第一个数
LOOP0:INC R0
MOV B,@R0;取下一个数
CJNE A,B,$+3;比较
JNC LOOP1
MOV A,B;把大的数送A
LOOP1:DJNZ R2,LOOP0
RET;出口参数在A中
/***主程序***/
ORG 1000H
MAX EQU 30H
MOV R0,#40H;设置入口参数R0,R2
MOV R2,#12-1
ACALL FMAX(www.xing528.com)
MOV MAX,A;出口参数暂存MAX中
MOV R0,#50H;设置入口参数R0,R2
MOV R2,#8-1
ACALL FMAX
CJNE A,MAX,$+3;比较两个数中较大值
JC NEXT
MOV MAX,A
NEXT:SJMP $
5 非数值运算程序设计举例
例3-59:将8位二进制数据转换为压缩式BCD码。设该数已在A中,转换后存在内RAM的30H、31H单元中。
解:程序如下:
MOV R0,#31H;地址指针
MOV B,#100
DIV AB;把该数据除100,得到A中的商即为BCD码的百位数
MOV @R0,A;存结果的百位数
DEC R0;修改指针
MOV A,#10;把刚才除100所得余数再去除10
XCH A,B
DIV AB;所得商为BCD码的十位数,余数即为BCD码的个位数
SWAP A;为了压缩,先把低4位送到高4位
ADD A,B;A中高字节的十位数与B中低半字节的个位数合成存入A
MOV @R0,A;存放结果的十位数和个位数
SJMP $
6 算术运算程序设计举例
例3-60:多字节数求补运算。注意:在MCS-51系列单片机的指令系统中没有求补指令,通过末位取反加1得到。
解:程序如下:
CMPT:MOV A,@R0
CPL A
ADD A,#01;最低字节采用取反加1
MOV @R0,A
DEC R2
LOOP:INC R0
MOV A,@R0
CPL A
ADDC A,#00;其余字节采用取反加进位
MOV @R0,A
DJNZ R2,LOOP
RET
例3-61:一个双字节与一个单字节无符号数乘法子程序。
入口参数:被乘数R3R4,乘数R2。
出口参数:积有3个字节,按先低后高的顺序放在片内RAM以MULADR为首地址的空间。
解:程序如下:
MUL:PUSH PSW;保护现场
SETB RS0;选择第二组工作寄存器
PUSH ACC
PUSH B
MUL0:MOV R0,#MULADR;首地址→R0
MOV A,R2;取乘数
MOV B,R4
MUL AB
MOV @R0,A;存积的最低字节
INC R0
MOV R1,B;暂存中间值
MUL1:MOV A,R2;取乘数
MOV B,R3
MUL AB
ADD A,R1
MOV @R0,A;存积的次高字节
INC R0
MOV A,B
ADDC A,#00H
MOV @R0,A;存积的高字节
POP B;恢复现场
POP A
POP PSW
RET
7 I/O控制程序设计举例
例3-62:要求在P1.0脚上产生周期为20ms的方波。
解:程序如下:
FB:CPL P1.0;P1.0取反
ACALL DL10MS
SJMP FB
DL10MS:…;延时10ms子程序
RET
例3-63:如图3-19所示,编程实现当按K一次蜂鸣器“嘀、嘀”响两声。解:程序如下:
STA:MOV R2,#2
CLR P1.4
STA1:JB P1.0,STA1
LCALL DL10MS
JB P1.0,STA1
JNB P1.0,$
LOOP:SETB P1.4;产生两个短脉冲
LCALL DL300MS
CLR P1.4
LCALL DL300MS
DJNZ R2,LOOP
LJMP STA
DL10MS:…;延时10ms的子程序
RET
图3-19 蜂鸣器电路
例3-64:如图3-20所示,2个按键开关K1、K2分别与单片机P3.2、P3.3相连,P1端口接有8只发光二极管,编一控制程序实现按K1键,发光二极管从上到下依次点亮;按K2键,发光二极管从下到上依次点亮,点亮间隔时间都为1s。无键按下时,灯全灭。
图3-20 按键控制LED电路
解:程序如下:
START:MOV P1,#0FFH;设置输出口初值,灯全灭
MOV P3,#0FFH;设置输入方式
LOOP:MOV A,P3;读入键盘状态
CJNE A,#0FFH,LP0;是否有键按下
JMP LOOP;无键按下等待
LP0:ACALL DELAY1;调用延时去抖动
MOV A,P3;重新读入键盘状态
CJNE A,#0FFH,LP1;非误读则跳转
JMP LOOP
LP1:JNB P3.2,A1;K1按下则发光点从上到下依次点亮
JNB P3.3,A2;K2按下则发光点从下到上依次点亮
JMP START;无键按下则返回
A1:MOV R0,#8;设置左移位数
MOV A,#0FEH;设置左移初值
LOOP1:MOV P1,A;输出至P1
ACALL DELAY;调用延时1s子程序
RL A
DJNZ R0,LOOP1;判断移动位数
JMP START
A2:MOV R0,#8;设置右移位数
MOV A,#7FH;设置右移初值
LOOP2:MOV P1,A
ACALL DELAY
RR A
DJNZ R0,LOOP2
JMP START
DELAY1:…;消抖延时子程序
…
RET
DELAY:…;延时1s子程序
…
RET
END
8 逻辑运算程序设计举例
例3-65:编写一程序,实现图3-21所示的逻辑运算电路。其中,X、Y、Z代表输入项,F代表输出项。
可以看到,图中运用位与、位或、位非,以及位异或等逻辑运算形式。但单片机指令中只提供了与、或、非等位运算指令,故位异或运算必须由与、或、非指令组合而成。
解:程序如下:
X BIT 01H
Y BIT 02H
Z BIT 03H
F BIT 00H
ORG 0000H
LJMP START
ORG 0030H
START:MOV C,X
ANL C,Y
MOV F,C;实现X和Y的逻辑与运算
MOV C,Z
ANL C,/Y
MOV 10H,C
MOV C,Y
ANL C,/Z
ORL C,10H;实现Y和Z的逻辑异或
CPL C;异或之后,再取反
ORL C,F;逻辑或运算
MOV F,C;输出F
END
图3-21 布尔电路图
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。