浅谈单⽚机中C语⾔与汇编语⾔的转换
⼀、单⽚机课设题⽬要求与软件环境介绍
做了⼀单⽚机设计,要⽤C语⾔与汇编语⾔同时实现,现将这次设计的感受和收获,还有遇到的问题写下,欢迎感兴趣的朋友交流想法,提出建议。单⽚机设计:基于51单⽚机的99码表设计
软件环境:Proteus8.0 + Keil4
要求:1,开关按⼀下,数码管开始计时。2,按两下,数码管显⽰静⽌。3,按三下,数码管数值清零。
⼆、C语⾔程序
1 #include<reg51.h>
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};
7void display(shi,ge);
8void key ();
9void init();
10void delay(uint z);
11/*-----主程序-----*/
12void main()
13 {
14 init(); //初始化
15while(1)
16 {
17 key ();
18if(keycount==1)
19 TR0=1; //开中断
20if(keycount==2)
21 TR0=0;
22if(keycount==3)
23 {
24 temp=0;
25 keycount=0;
26 }
27if(aa==10){aa=0;
28if(temp<=99)
29 {
30 temp++;display(shi,ge);
31 }
32else
33 temp=0;}
34 }
35 }
36
37
38/*------初始化程序-------*/
39void init()
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/*-----定时器中断-----*/
51void timer0() interrupt 1
52 {
53 TH0=(65536-50000)/256;
54 TL0=(65536-50000)%256;
55 aa++;
56 }
57/*-----显⽰⼦程序-----*/
58void display(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/*-----按键检测⼦程序-----*/
66void key ()
67 {
68if(anjian==0)
69 {
70 delay(5); //消抖
71if(anjian==0)
72 keycount++;
73 }
74//while(anjian==0);
75//display(shi,ge); //等待按键弹起
76 }
77/*-----延时⼦程序-----*/
78void delay(uint z) //延时约1ms
79 {
80uint x,y;
81for(x=z;x>0;x--)
82for(y=100;y>0;y--);
83 }
电路仿真结果如下:
三、C语⾔转汇编语⾔步骤
好了,那么接下来我们就开始C语⾔——>汇编语⾔之旅
(1)C语⾔1-10⾏改为
1 ORG 0000H //汇编起始伪指令,功能是规定程序存储器中源程序或数据块存放的起始地址
2 ajmp STAR //ajmp⽆条件跳转指令
3 ORG 000bh
4 ajmp timer0
5 anjian equ P1.7 //位定义
6 keycount equ 40h
7 shi equ 41h
8 gewei equ 42h
9 aa equ 43h
10 temp equ 44h
11tab: db 3fh,6h,5bh,4fh,66h //建表
12 db 6dh,7dh,7h,7fh,6fh
(2)C语⾔中的初始化函数 12-14⾏和39-49⾏改为
1STAR:
2 acall init //⼦程序近程调⽤指令,功能是主程序调⽤⼦程序,调⽤⼦程序的范围为2kb
1init:
2mov keycount,#0 //keycount=0
3mov temp,#0 //temp=1
4mov tmod,#01h //TMOD=0x01
5mov TH0,#60
6mov TL0,#176
7setb EA //位置位指令,对操作数所指出的位进⾏置1操作
8setb ET0
9setb TR0
10ret
acall为⼦程序近程调⽤指令,返回⽤ret。
(3)C语⾔中15-35⾏是个while循环,逻辑⽐较繁琐,注意了!
1START:
2 acall display
3inc temp //加1指令,将操作数所指定的单元或寄存器中的内容加1
4 acall delay70 //近程调⽤delay70
5x8:mov r0,keycount
6 cjne r0,#2,F1 //cjne⽐较跳转指令,若r0=2则跳转到x8,否则跳转到F1。
7 ajmp x8
8F1:mov r0,temp
9 cjne r0,#99,START //若r0<99时,重复循环,否则temp=0
10mov temp,#0
11 ajmp START
12F9:
13 acall key
14mov r0,keycount
15 cjne r0,#0,F2 //keycount=0顺序执⾏,否则跳转到F1
16 CLR P1.3 //清0
17SETB TR0
18
19F2:mov r0,keycount //第⼆次按键
20 cjne r0,#2,F2
21 clr TR0
22 reti汇编table指令什么意思
23mov r0,keycount //第三次按键
24 cjne r0,#3,F3
25mov temp,#0
26mov keycount,#0
inc 增量指令,功能是将操作数所指定的单元或寄存器中的内容加1,其结果返还回原操作数单元中。
clr 位复位,功能是对操作数所指出的位进⾏清“0”操作。
或者在中断函数中
1timer0:
2w1:
3 acall key
4mov TH0,#60
5mov TL0,#176
6 cpl p1.0
7JB keycount,x2
8 ajmp x3
9x2:
10 ajmp START
11 clr p1.0
12 ajmp w1
13 ajmp w1
14
15x3:mov r0,keycount
16 cjne r0,#3,w1 //若r0=3则顺序执⾏,否则跳转到w1
17mov temp,#0
18mov keycount,#0
19ret
(4)C语⾔58-64⾏display函数改为
1display:
2mov a,temp
3mov b,#10
4div ab //除法指令,实现两个⼋位⽆符号数的除法操作。
5mov r2,A
6mov r3,B
7mov dptr,#tab //16位数据传送使⽤⽅式
8mov a,r2
9 movc a,@a+dptr //查表,先将累加器A的内容与数据指针寄存器DPTR的内容相加,再以其结果为地址,将该地址的结果送⼊A中10mov P0,a
11 acall delay70
12nop //空指令
13mov a,r3
14 movc a,@a+dptr
15mov P2,a
16nop
17 acall delay70
18ret
div为除法指令,功能是实现两个8位⽆符号数的除法操作,⼀般被除数放在累加器A中,除数放在寄存器B中。指令执⾏后,商放在A中,余数放在B中。
movc为查表指令,先将累加器A的内容与数据指针寄存器DPTR的内容相加,再以其结果为地址,将该地址的内容送⼊A中。
nop为空操作指令,它不作任何操作,但要占⽤⼀个机器周期(即12个振荡周期)的时间,常⽤于延时或等待。(有些程序执⾏的效果由于延时时间太短,在⼈眼视觉暂时作⽤下⽆法辨认清楚)
此段程序的作⽤在于将⼀个两位数分别分在⼀个⼗位上的数码管和⼀个个位上的数码管显⽰。
(5)C语⾔66-76⾏key函数改为
1key:
2jb anjian,F6 //若anjian=0则顺序执⾏,否则跳转到F6
3 ACALL delay5
4inc keycount //keycount++
5F6:
6ret
jb为位条件转移指令,功能是若直接寻址的位bit=1,则程序转移到指定的⽬标地址去执⾏,若bit=0,则程序顺序执⾏。
(6)C语⾔78-83⾏delay函数改为
1delay70:
2mov r6,#70
3D2:mov R7,#248
4d1: djnz R7,d1 //248*70次
5 djnz R6,D2
6ret
7
8delay5:
9mov r6,#5 //消抖。
10F7:mov R7,#248
11F8: djnz r7,F8 //248*5次
12 djnz r6,F7
13ret
注意: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语⾔转汇编,是让你们体会数据在底层的存储过程,这样在以后你们⽤⾼级语⾔写程序时,不会犯看似低级但⼜⽆法避免的错误(⼤概意思就是这样)。
感谢我的⽼师,如果没有他的指引,我估计就⽆法体会计算机底层蕴含的神奇之处。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论