当前位置:首页 > 单片机 > 单片机
[导读]做了一单片机设计,要用C语言与汇编语言同时实现,现将这次设计的感受和收获,还有遇到的问题写下,欢迎感兴趣的朋友交流想法,提出建议。单片机设计:基于51单片机的99码表设计软件环境:Proteus8.0 + Keil4要求:1

做了一单片机设计,要用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--);

}

电路仿真结果如下:

好了,那么接下来我们就开始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 jb anjian,F6 //若anjian=0则顺序执行,否则跳转到F63 ACALL delay54 inc keycount //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=2 8 ,约等于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——>汇编,使我更加深入地理解了数据在计算机中的存储与调用。在此期间班主任和同学也给我答疑解惑,相信在以后的道路上,我会更加更深入地理解计算机。越努力,越幸运!


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭