浅谈单片机中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=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——>汇编,使我更加深入地理解了数据在计算机中的存储与调用。在此期间班主任和同学也给我答疑解惑,相信在以后的道路上,我会更加更深入地理解计算机。越努力,越幸运!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏机器学习实践二三事

Numpy使用1

Numpy介绍 NumPy is the fundamental package for scientific computing with Python. I...

21690
来自专栏用户2442861的专栏

python lmdb使用

学习LMDB的时候不禁想到知乎上的提问“有哪些名人长期生活在其他名人的光环下”,说实话感觉查它的人基本都是为了用Caffe……

85120
来自专栏FreeBuf

kill.exe溢出漏洞分析与EXP讨论

* 本文原创作者:zzz66686,本文属FreeBuf原创奖励计划,未经许可禁止转载 1. 前言 前几日,笔者在exploit-db上发现了一个kill.ex...

25590
来自专栏CSDN技术头条

Go语言实践:从新手入门到上线真实的小型服务所遇到的那些坑

Teamwork团队在去年写了近20万行Go代码,建造了一堆速度奇快的小型HTTP服务,本文列出了他们总结的9条经验教训。 为什么选择Go语言?Go语言,又称G...

23770
来自专栏我是攻城师

浅谈ElasticSearch的嵌套存储模型

42560
来自专栏斑斓

漂亮的with,鱼与熊掌可以兼得

假设要加载磁盘上的一个文件,并以二进制形式读取文件的数据。若要从健壮性的角度考虑,需得考虑两种异常情况: 加载文件失败,例如给定的文件路径并不存在该文件 读取文...

38980
来自专栏java一日一条

Java多线程并发锁和原子操作,你真的了解吗?

对于Java多线程,接触最多的莫过于使用synchronized,这个简单易懂,但是这synchronized并非性能最优的。今天我就简单介绍一...

11630
来自专栏Golang语言社区

Go语言实践:从新手入门到上线真实的小型服务所遇到的那些坑

摘要: Teamwork团队在去年写了近20万行Go代码,建造了一堆速度奇快的小型HTTP服务,本文列出了他们总结的9条经验教训。 为什么选择Go语言?Go...

39660
来自专栏架构之路

追源索骥:透过源码看懂Flink核心框架的执行流程

写在最前:因为这篇博客太长,所以我把它转成了带书签的pdf格式,看起来更方便一点。想要的童鞋可以到我的公众号“老白讲互联网”后台留言flink即可获取。

3.7K60
来自专栏美团技术团队

Android热更新方案Robust

美团•大众点评是中国最大的O2O交易平台,目前已拥有近6亿用户,合作各类商户达432万,订单峰值突破1150万单。美团App是平台主要的入口之一,O2O交易场景...

43490

扫码关注云+社区

领取腾讯云代金券