一、单片机课设题目要求与软件环境介绍
做了一单片机设计,要用C语言与汇编语言同时实现,现将这次设计的感受和收获,还有遇到的问题写下,欢迎感兴趣的朋友交流想法,提出建议。
单片机设计:基于51单片机的99码表设计
软件环境:Proteus8.0 + Keil4
要求:1,开关按一下,数码管开始计时。2,按两下,数码管显示静止。3,按三下,数码管数值清零。
二、C语言程序
1 #include
2 #define uint unsigned int
3 #define uchar unsigned char
4 uchar shi,ge,aa,keycount=0,temp;5 sbit anjian=P1^7;6 uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};7 voiddisplay(shi,ge);8 voidkey ();9 voidinit();10 void delay(uintz);11 /*-----主程序-----*/
12 voidmain()13 {14 init(); //初始化
15 while(1)16 {17 key ();18 if(keycount==1)19 TR0=1; //开中断
20 if(keycount==2)21 TR0=0;22 if(keycount==3)23 {24 temp=0;25 keycount=0;26 }27 if(aa==10){aa=0;28 if(temp<=99)29 {30 temp++;display(shi,ge);31 }32 else
33 temp=0;}34 }35 }36
37
38 /*------初始化程序-------*/
39 voidinit()40 {41 keycount=0;42 temp=0;43 TMOD=0x01;44 TH0=(65536-50000)/256;45 TL0=(65536-50000)%256;46 EA=1;47 ET0=1;48 //TR0=0;
49 }50 /*-----定时器中断-----*/
51 void timer0() interrupt 1
52 {53 TH0=(65536-50000)/256;54 TL0=(65536-50000)%256;55 aa++;56 }57 /*-----显示子程序-----*/
58 voiddisplay(shi,ge)59 {60 shi=temp/10;61 ge=temp%10;62 P0=table[shi];;delay(70);63 P2=table[ge]; ;delay(70);64 }65 /*-----按键检测子程序-----*/
66 voidkey ()67 {68 if(anjian==0)69 {70 delay(5); //消抖
71 if(anjian==0)72 keycount++;73 }74 //while(anjian==0);75 //display(shi,ge);//等待按键弹起
76 }77 /*-----延时子程序-----*/
78 void delay(uint z) //延时约1ms
79 {80 uintx,y;81 for(x=z;x>0;x--)82 for(y=100;y>0;y--);83 }
电路仿真结果如下:
三、C语言转汇编语言步骤
好了,那么接下来我们就开始C语言——>汇编语言之旅
(1)C语言1-10行改为
1 ORG 0000H //汇编起始伪指令,功能是规定程序存储器中源程序或数据块存放的起始地址2 ajmp STAR //ajmp无条件跳转指令3 ORG 000bh4 ajmp timer05 anjian equ P1.7//位定义6 keycount equ 40h7 shi equ 41h8 gewei equ 42h9 aa equ 43h10 temp equ 44h11 tab:db 3fh,6h,5bh,4fh,66h //建表12 db 6dh,7dh,7h,7fh,6fh
(2)C语言中的初始化函数 12-14行和39-49行改为
1 STAR:
2 acall init //子程序近程调用指令,功能是主程序调用子程序,调用子程序的范围为2kb
1 init:
2 mov keycount,#0 //keycount=0
3 mov temp,#0 //temp=1
4 movtmod,#01h //TMOD=0x015 mov TH0,#60
6 mov TL0,#176
7 setbEA //位置位指令,对操作数所指出的位进行置1操作8 setbET09 setbTR010 ret
acall为子程序近程调用指令,返回用ret。
(3)C语言中15-35行是个while循环,逻辑比较繁琐,注意了!
1 START:
2 acall display3 inctemp //加1指令,将操作数所指定的单元或寄存器中的内容加14 acall delay70 //近程调用delay705 x8: movr0,keycount6 cjne r0,#2,F1 //cjne比较跳转指令,若r0=2则跳转到x8,否则跳转到F1。7 ajmp x88 F1: movr0,temp9 cjne r0,#99,START //若r0<99时,重复循环,否则temp=0
10 mov temp,#0
11 ajmp START12 F9:
13 acall key14 movr0,keycount15 cjne r0,#0,F2 //keycount=0顺序执行,否则跳转到F116 CLR P1.3//清017 SETBTR018
19 F2: movr0,keycount //第二次按键20 cjne r0,#2,F221 clr TR022 reti23 movr0,keycount //第三次按键24 cjne r0,#3,F325 mov temp,#0
26 mov keycount,#0
inc 增量指令,功能是将操作数所指定的单元或寄存器中的内容加1,其结果返还回原操作数单元中。
clr 位复位,功能是对操作数所指出的位进行清“0”操作。
或者在中断函数中
1 timer0:
2 w1:
3 acall key4 mov TH0,#60
5 mov TL0,#176
6 cpl p1.0
7 JBkeycount,x28 ajmp x39 x2:
10 ajmp START11 clr p1.0
12 ajmp w113 ajmp w114
15 x3: movr0,keycount16 cjne r0,#3,w1 //若r0=3则顺序执行,否则跳转到w117 mov temp,#0
18 mov keycount,#0
19 ret
(4)C语言58-64行display函数改为
1 display:
2 mova,temp3 mov b,#10
4 divab //除法指令,实现两个八位无符号数的除法操作。5 movr2,A6 movr3,B7 movdptr,#tab //16位数据传送使用方式8 mova,r29 movc a,@a+dptr //查表,先将累加器A的内容与数据指针寄存器DPTR的内容相加,再以其结果为地址,将该地址的结果送入A中10 movP0,a11 acall delay7012 nop//空指令13 mova,r314 movc a,@a+dptr15 movP2,a16 nop
17 acall delay7018 ret
div为除法指令,功能是实现两个8位无符号数的除法操作,一般被除数放在累加器A中,除数放在寄存器B中。指令执行后,商放在A中,余数放在B中。
movc为查表指令,先将累加器A的内容与数据指针寄存器DPTR的内容相加,再以其结果为地址,将该地址的内容送入A中。
nop为空操作指令,它不作任何操作,但要占用一个机器周期(即12个振荡周期)的时间,常用于延时或等待。(有些程序执行的效果由于延时时间太短,在人眼视觉暂时作用下无法辨认清楚)
此段程序的作用在于将一个两位数分别分在一个十位上的数码管和一个个位上的数码管显示。
(5)C语言66-76行key函数改为
1 key:
2 jbanjian,F6 //若anjian=0则顺序执行,否则跳转到F63 ACALL delay54 inckeycount //keycount++5 F6:
6 ret
jb为位条件转移指令,功能是若直接寻址的位bit=1,则程序转移到指定的目标地址去执行,若bit=0,则程序顺序执行。
(6)C语言78-83行delay函数改为
1 delay70:
2 mov r6,#70
3 D2: mov R7,#248
4 d1: djnz R7,d1 //248*70次5 djnz R6,D26 ret
7
8 delay5:
9 mov r6,#5//消抖。10 F7: mov R7,#248
11 F8: djnz r7,F8 //248*5次12 djnz r6,F713 ret
注意:248=28,约等于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——>汇编,使我更加深入地理解了数据在计算机中的存储与调用。在此期间班主任和同学也给我答疑解惑,相信在以后的道路上,我会更加更深入地理解计算机。
至今记得班主任对我说的一段话,在此转述如下:这辈子你可能都不会用汇编语言写代码,但我要求你们用C语言转汇编,是让你们体会数据在底层的存储过程,这样在以后你们用高级语言写程序时,不会犯看似低级但又无法避免的错误(大概意思就是这样)。
感谢我的老师,如果没有他的指引,我估计就无法体会计算机底层蕴含的神奇之处。