浅谈单片机中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};
 7 void display(shi,ge);
 8 void key ();
 9 void init();
10 void delay(uint z);
11 /*-----主程序-----*/
12 void main()
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 void 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 /*-----定时器中断-----*/
51 void timer0() interrupt 1
52 {
53     TH0=(65536-50000)/256;
54     TL0=(65536-50000)%256;
55     aa++;    
56 }
57 /*-----显示子程序-----*/
58 void 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 /*-----按键检测子程序-----*/
66 void key ()
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     uint x,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        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
11 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      mov tmod,#01h      //TMOD=0x01
 5      mov TH0,#60
 6      mov TL0,#176
 7      setb EA   //位置位指令,对操作数所指出的位进行置1操作
 8      setb ET0
 9      setb TR0
10      ret

acall为子程序近程调用指令,返回用ret。

 

(3)C语言中15-35行是个while循环,逻辑比较繁琐,注意了!

 1 START:          
 2     acall display  
 3     inc   temp  //加1指令,将操作数所指定的单元或寄存器中的内容加1
 4     acall delay70  //近程调用delay70
 5 x8:     mov r0,keycount
 6      cjne r0,#2,F1     //cjne比较跳转指令,若r0=2则跳转到x8,否则跳转到F1。
 7      ajmp x8
 8 F1:     mov r0,temp
 9      cjne r0,#99,START     //若r0<99时,重复循环,否则temp=0
10       mov temp,#0
11      ajmp START    
12 F9:        
13         acall key                 
14         mov r0,keycount
15         cjne r0,#0,F2  //keycount=0顺序执行,否则跳转到F1
16         CLR P1.3      //清0
17         SETB TR0    
18        
19 F2:      mov r0,keycount     //第二次按键
20       cjne r0,#2,F2
21       clr TR0
22       reti                  
23       mov r0,keycount           //第三次按键
24       cjne r0,#3,F3
25       mov temp,#0
26       mov keycount,#0

inc 增量指令,功能是将操作数所指定的单元或寄存器中的内容加1,其结果返还回原操作数单元中。

clr 位复位,功能是对操作数所指出的位进行清“0”操作。

或者在中断函数中

 1 timer0:
 2 w1:    
 3     acall key
 4     mov TH0,#60
 5     mov TL0,#176
 6     cpl p1.0    
 7     JB keycount,x2
 8     ajmp x3 
 9 x2:     
10      ajmp START
11      clr  p1.0
12      ajmp w1
13      ajmp w1
14 
15 x3:      mov r0,keycount
16       cjne r0,#3,w1     //若r0=3则顺序执行,否则跳转到w1
17       mov temp,#0
18       mov keycount,#0        
19       ret

 

(4)C语言58-64行display函数改为

 1 display:        
 2      mov a,temp
 3      mov b,#10
 4      div ab  //除法指令,实现两个八位无符号数的除法操作。
 5      mov r2,A    
 6      mov r3,B
 7      mov dptr,#tab //16位数据传送使用方式
 8      mov a,r2
 9      movc a,@a+dptr //查表,先将累加器A的内容与数据指针寄存器DPTR的内容相加,再以其结果为地址,将该地址的结果送入A中
10      mov P0,a
11      acall delay70
12      nop  //空指令
13      mov a,r3
14      movc a,@a+dptr
15      mov P2,a
16      nop
17      acall delay70    
18      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则顺序执行,否则跳转到F6
3         ACALL delay5
4         inc keycount  //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,D2
 6         ret
 7         
 8 delay5:    
 9         mov r6,#5  //消抖。
10 F7:     mov R7,#248
11 F8:     djnz r7,F8     //248*5次
12         djnz r6,F7
13         ret

注意:248=2,约等于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语言转汇编,是让你们体会数据在底层的存储过程,这样在以后你们用高级语言写程序时,不会犯看似低级但又无法避免的错误(大概意思就是这样)。

感谢我的老师,如果没有他的指引,我估计就无法体会计算机底层蕴含的神奇之处。

 

转载于:https://www.cnblogs.com/OctoptusLian/p/6224065.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值