c语言 linux系统 delay,浅谈单片机中C语言与汇编语言的转换

做了一单片机设计,要用C语言与汇编语言同时实现,现将这次设计的感受和收获,还有遇到的问题写下,欢迎感兴趣的朋友交流想法,提出建议。

单片机设计:基于51单片机的99码表设计

软件环境:Proteus8.0 + Keil4

要求:1,开关按一下,数码管开始计时。2,按两下,数码管显示静止。3,按三下,数码管数值清零。

C语言程序如下:

#include

#define uint unsigned int

#define uchar unsigned char

uchar 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--);

}

电路仿真结果如下:

d624db68a2faaae2f85a063f7239ca95.png

好了,那么接下来我们就开始C语言——>汇编语言之旅^_^

(1)C语言1-10行改为

ORG        0000H      //汇编起始伪指令,功能是规定程序存储器中源程序或数据块存放的起始地址

ajmp        STAR    //ajmp无条件跳转指令

ORG        000bh

ajmp      timer0

anjian        equ        P1.7    //位定义

keycount    equ      40h

shi            equ        41h

gewei        equ        42h

aa            equ        43h

temp        equ        44h

tab:        db          3fh,6h,5bh,4fh,66h      //建表

db          6dh,7dh,7h,7fh,6fh

(2)C语言中的初始化函数 12-14行和39-49行改为

1 STAR:

2 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  //近程调用delay70

x8:    mov r0,keycount

cjne r0,#2,F1    //cjne比较跳转指令,若r0=2则跳转到x8,否则跳转到F1。

ajmp x8

F1:    mov r0,temp

cjne r0,#99,START    //若r0<99时,重复循环,否则temp=0

mov temp,#0

ajmp START

F9:

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 x3

x2:

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函数改为

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函数改为

delay70:

mov r6,#70

D2:        mov R7,#248

d1:        djnz R7,d1    //248*70次

djnz R6,D2

ret

delay5:

mov r6,#5  //消抖。

F7:    mov R7,#248

F8:    djnz r7,F8    //248*5次

djnz r6,F7

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

0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值