单片机规划:根据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 //第2次按键
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是位。
责任编辑;zl