浅谈单片机中C语言与汇编语言的转换

admin 2022年5月25日08:53:13评论81 views字数 4001阅读13分20秒阅读模式
阅读目录
  • 一、单片机课设题目要求与软件环境介绍
  • 二、C语言程序
  • 三、C语言转汇编语言步骤
  • 四、思考
  • 五、感受

一、单片机课设题目要求与软件环境介绍

做了一单片机设计,要用C语言与汇编语言同时实现,现将这次设计的感受和收获,还有遇到的问题写下,欢迎感兴趣的朋友交流想法,提出建议。
单片机设计:基于51单片机的99码表设计
软件环境:Proteus8.0 + Keil4
要求:1,开关按一下,数码管开始计时。2,按两下,数码管显示静止。3,按三下,数码管数值清零。
代码片段地址
回到顶部

二、C语言程序

#include<reg51.h>#define uint unsigned int#define uchar unsigned charuchar 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语言与汇编语言的转换

三、C语言转汇编语言步骤

好了,那么接下来我们就开始C语言——>汇编语言之旅
(1)C语言1-10行改为
ORG        0000H      //汇编起始伪指令,功能是规定程序存储器中源程序或数据块存放的起始地址ajmp        STAR     //ajmp无条件跳转指令ORG        000bhajmp       timer0anjian        equ         P1.7     //位定义keycount     equ      40hshi             equ         41hgewei         equ         42haa             equ         43htemp        equ         44htab:         db          3fh,6h,5bh,4fh,66h      //建表            db          6dh,7dh,7h,7fh,6fh
 
(2)C语言中的初始化函数 12-14行和39-49行改为
 STAR:           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  //近程调用delay70x8:     mov r0,keycount     cjne r0,#2,F1     //cjne比较跳转指令,若r0=2则跳转到x8,否则跳转到F1。     ajmp x8F1:     mov r0,temp     cjne r0,#99,START     //若r0<99时,重复循环,否则temp=0      mov temp,#0     ajmp STARTF9:        acall key        mov r0,keycount        cjne r0,#0,F2  //keycount=0顺序执行,否则跳转到F1        CLR P1.3      //清0        SETB TR0
F2: mov r0,keycount //第二次按键 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 x3x2:     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函数改为
key:        jb anjian,F6  //若anjian=0则顺序执行,否则跳转到F6        ACALL delay5        inc keycount  //keycount++F6:        ret
jb为位条件转移指令,功能是若直接寻址的位bit=1,则程序转移到指定的目标地址去执行,若bit=0,则程序顺序执行。
 
(6)C语言78-83行delay函数改为
delay70:        mov r6,#70D2:        mov R7,#248d1:        djnz R7,d1     //248*70次        djnz R6,D2        ret
delay5: mov r6,#5 //消抖。F7: mov R7,#248F8: djnz r7,F8 //248*5次 djnz r6,F7 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语言转汇编,是让你们体会数据在底层的存储过程,这样在以后你们用高级语言写程序时,不会犯看似低级但又无法避免的错误(大概意思就是这样)。
感谢我的老师,如果没有他的指引,我估计就无法体会计算机底层蕴含的神奇之处。
 
作者:Zoctopus_Zhang
    
出处:http://www.cnblogs.com/OctoptusLian/
    
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明。

原文始发于微信公众号(汇编语言):浅谈单片机中C语言与汇编语言的转换

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年5月25日08:53:13
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   浅谈单片机中C语言与汇编语言的转换https://cn-sec.com/archives/1046998.html

发表评论

匿名网友 填写信息