用51单片机实现时钟功能程序

用51单片机实现时钟功能程序,第1张

duanEQUP0;

weiEQUP2;

keyBITP37;

ORG0000H

AJMPMAIN;绝对转移指令,2kb范围(11位)内跳转LJMP16位64kb范围内跳转

;短转移指令的功能是先使程序计数器PC加1两次(即:取出指令码),然后把加2后的地址和rel相加作为目标转移地址。因此,短转移指令是一条相对转移指令,是一条双字节双周期指令

ORG0030H;指明后面的程序从程序存储器的0030H单元开始存放

DELAY200US:;@110592MHz

NOP

NOP

NOP

PUSH30H

PUSH31H

MOV30H,#2

MOV31H,#179

NEXT:

DJNZ31H,NEXT

DJNZ30H,NEXT

POP31H

POP30H

RET

ORG0060H

;DISPLAY子程序

DISPLAY:

PUSHACC;不能写A,此处ACC代表地址,push后跟地址,代表把地址内的内容压入栈中

PUSH00H;R0

PUSH06H;R6

PUSH07H;R7

PUSH83H;DPH

PUSH82H;DPL

MOVR6,#01H;位选数据,01指的是缓冲区最低位数据

MOVR7,#08H;循环次数

FLAG:

MOVduan,#0x00;消影

MOVA,R6

CPLA;取反

MOVwei,A;位选

MOVA,#disBufDat

ADDA,R7

SUBBA,#0X08

MOVR0,A

MOVA,@R0;读出要显示的数据到A

MOVDPTR,#disTab

MOVCA,@A+DPTR;从rom取数据,取出要显示的数据对应的段码

MOVduan,A;段选

MOVA,R6

RLA

MOVR6,A;更新下一次位选

LCALLDELAY200US

DJNZR7,FLAG

POP82H;DPL

POP83H;DPH

POP07H

POP06H

POP00H

POPACC

RET

ORG0100H

;定时器中断0初始化

T0_INIT:

MOVTMOD,#0X01

MOVTH0,#0X3C

MOVTL0,#0XB0

SETBEA

SETBTR0

SETBET0

RET

ORG0130H

;T0中断处理程序

INT_TIMERE0:

PUSHACC

SETBRS0

MOVTH0,#0X3C

MOVTL0,#0XB0

INCR0

MOVA,R0

SUBBA,#0X14

JBCY,SECFLAG

MOVR0,#0x00

INCsec

SECFLAG:

CLRRS0

POPACC

RETI

ORG000BH;定时器/计数器T0入口地址

LJMPINT_TIMERE0;跳转到定时器/计数器中断服务程序中去

disTab:DB0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00,0x40;0-f,空白,横杠的段选数据

disBufDatEQU47H;定义显示缓冲数据变量区,8个

disBufDatHeadEQU40H//单片机上显示在最左边

secEQU48H

;主程序

ORG0180H

MAIN:

MOVSP,#0X60;将0x60到0x7f设为堆栈区

LCALLT0_INIT

MOVdisBufDatHead,#0X00

MOVdisBufDatHead+1,#0X00

MOVdisBufDatHead+2,#0X11

MOVdisBufDatHead+3,#0X11

MOVdisBufDatHead+4,#0X11

MOVdisBufDatHead+5,#0X11

MOVdisBufDatHead+6,#0X11

MOVdisBufDatHead+7,#0X11

MOVsec,#0X3A

WHILE:

JBkey,KEYSCAN

MOVsec,0x00

KEYSCAN:

MOVA,sec

SUBBA,#3CH;超过60s归零

JBCY,CLEAR

MOVsec,#0X00;clr加ram地址无效

CLEAR:

MOVA,sec

MOVB,#0AH

DIVAB;A/B,商存到A中,余数存B中

MOVdisBufDatHead,A

MOVdisBufDatHead+1,B

LCALLDISPLAY

LJMPWHILE;循环

END;

扩展资料

51机器周期和指令周期

1、机器周期是指单片机完成一个基本 *** 作所花费的时间,一般使用微秒来计量单片机的运行速度,51单片机的一个机器周期包括12个时钟振荡周期,也就是说如果51单片机采用12MHz晶振,那么执行一个机器周期就只需要1μs;如果采用的是6MHz的晶振,那么执行一个机器周期就需要2μs。

2、指令周期是指单片机执行一条指令所需要的时间,一般利用单片机的机器周期来计量指令周期。在51单片机里有单周期指令(执行这条指令只需一个机器周期),双周期指令(执行这条指令只需要两个机器周期),四周期指令(执行这条指令需要四个机器周期)。

除了乘、除两条指令是四周期指令,其余均为单周期或双周期指令。也就是说,如果51单片机采用的是12MHz晶振,那么它执行一条指令一般只需1~2微秒的时间;如果采用的是6MH晶振,执行一条指令一般就需2~4微秒的时间。

;     谁有XONIX手表的说明书(见图)

XONIX电子表怎么设置

XONIX手表 CD的具体使用方法和调整方法

精准xonix CR2016手表按键怎么按

xonix手表的闹钟怎么调啊,求解,还有,那个选时区,北京时间是怎么显示的啊,我看不懂啊求解

      谁有XONIX手表的说明书(见图)

      我的说明书也找不到了,简单告诉你这么调吧:

      按M:秒表

      长按M:调闹表时钟,再按S调:闹表分钟;

      长按M,再按一下M:调秒钟,按S:陆续调分钟、时钟、月份、日期和星期;

      按住S,再按M:调整时间显示方式(12小时制/24小时制);

      按住S,再按R:调整日期显示方式(日/月or月/日);

      按住R,再按S:陆续整点报时、闹表、取消整点报时、取消闹表;

      XONIX电子表怎么设置

      1、调整时间

      第一步:长按set/el键3到5秒,听到滴的一声放手。

      第二步:按mode键可以切换时、分、秒、年、月、日、24时区切换,还可以设置时区。比如香港时间,北京时间等。

      第三步:st/stp或reset键对时间进行加减

      第四步:如果调好时间以后,再按一下set/el键就可以显示你需要的时间。

      2、设置跑表

      按一下mode就可以,st/stp键开始,resent归零。

      其它的参照说明书,不清楚的可以问我。

      XONIX手表 CD的具体使用方法和调整方法

      这个的话,很多电子表都是这样的,无法消除的。因为按键直接跟那个小喇叭是挂钩的。

      精准xonix CR2016手表按键怎么按

      先点 RESET选择要调的模块,再按MODE。然后自己看着办

      xonix手表的闹钟怎么调啊,求解,还有,那个选时区,北京时间是怎么显示的啊,我看不懂啊求解

      S1=ST/STP S2=RESET S3=MODE

      1设置闹钟时间

      闹钟BIBI声20秒,按S2键手动停止

      按住S3键3秒,显示闹钟时间

      时钟数闪动,按S2设置

      按S1键 分钟数闪动 按S2设置

      按住S2键可加快设置,按S3返回正常模式

      2闹钟和整点响铃开关

      按住S2键轻按S1设置闹钟和报时开关

      3设置时间和日历

      按住S3键3秒,显示闹钟时间,再轻按S3可以设置时间和日历

      秒钟数闪动,按S2键重置为0

      S1键选择,S2键设置

      S3返回

      4显示日期模式

      按住S1然后轻按S2调整日期模式

      5时间显示模式

      按住S2或S1,再轻按S3调整时间模式

      我的没有时区设置

基于DS1302的日历时钟

#include<reg51h> //包含单片机寄存器的头文件

#include<intrinsh> //包含_nop_()函数定义的头文件

/

以下是DS1302芯片的 *** 作程序

/

unsigned char code digit[10]={"0123456789"}; //定义字符数组显示数字

sbit DATA=P1^1; //位定义1302芯片的接口,数据输出端定义在P11引脚

sbit RST=P1^2; //位定义1302芯片的接口,复位端口定义在P11引脚

sbit SCLK=P1^0; //位定义1302芯片的接口,时钟输出端口定义在P11引脚

/

函数功能:延时若干微秒

入口参数:n

/

void delaynus(unsigned char n)

{

unsigned char i;

for(i=0;i<n;i++)

;

}

/

函数功能:向1302写一个字节数据

入口参数:x

/

void Write1302(unsigned char dat)

{

unsigned char i;

SCLK=0; //拉低SCLK,为脉冲上升沿写入数据做好准备

delaynus(2); //稍微等待,使硬件做好准备

for(i=0;i<8;i++) //连续写8个二进制位数据

{

DATA=dat&0x01; //取出dat的第0位数据写入1302

delaynus(2); //稍微等待,使硬件做好准备

SCLK=1; //上升沿写入数据

delaynus(2); //稍微等待,使硬件做好准备

SCLK=0; //重新拉低SCLK,形成脉冲

dat>>=1; //将dat的各数据位右移1位,准备写入下一个数据位

}

}

/

函数功能:根据命令字,向1302写一个字节数据

入口参数:Cmd,储存命令字;dat,储存待写的数据

/

void WriteSet1302(unsigned char Cmd,unsigned char dat)

{

RST=0; //禁止数据传递

SCLK=0; //确保写数居前SCLK被拉低

RST=1; //启动数据传输

delaynus(2); //稍微等待,使硬件做好准备

Write1302(Cmd); //写入命令字

Write1302(dat); //写数据

SCLK=1; //将时钟电平置于已知状态

RST=0; //禁止数据传递

}

/

函数功能:从1302读一个字节数据

入口参数:x

/

unsigned char Read1302(void)

{

unsigned char i,dat;

delaynus(2); //稍微等待,使硬件做好准备

for(i=0;i<8;i++) //连续读8个二进制位数据

{

dat>>=1; //将dat的各数据位右移1位,因为先读出的是字节的最低位

if(DATA==1) //如果读出的数据是1

dat|=0x80; //将1取出,写在dat的最高位

SCLK=1; //将SCLK置于高电平,为下降沿读出

delaynus(2); //稍微等待

SCLK=0; //拉低SCLK,形成脉冲下降沿

delaynus(2); //稍微等待

}

return dat; //将读出的数据返回

}

/

函数功能:根据命令字,从1302读取一个字节数据

入口参数:Cmd

/

unsigned char ReadSet1302(unsigned char Cmd)

{

unsigned char dat;

RST=0; //拉低RST

SCLK=0; //确保写数居前SCLK被拉低

RST=1; //启动数据传输

Write1302(Cmd); //写入命令字

dat=Read1302(); //读出数据

SCLK=1; //将时钟电平置于已知状态

RST=0; //禁止数据传递

return dat; //将读出的数据返回

}

/

函数功能: 1302进行初始化设置

/

void Init_DS1302(void)

{

WriteSet1302(0x8E,0x00); //根据写状态寄存器命令字,写入不保护指令

WriteSet1302(0x80,((0/10)<<4|(0%10))); //根据写秒寄存器命令字,写入秒的初始值

WriteSet1302(0x82,((0/10)<<4|(0%10))); //根据写分寄存器命令字,写入分的初始值

WriteSet1302(0x84,((12/10)<<4|(12%10))); //根据写小时寄存器命令字,写入小时的初始值

WriteSet1302(0x86,((16/10)<<4|(16%10))); //根据写日寄存器命令字,写入日的初始值

WriteSet1302(0x88,((11/10)<<4|(11%10))); //根据写月寄存器命令字,写入月的初始值

WriteSet1302(0x8c,((8/10)<<4|(8%10))); //根据写小时寄存器命令字,写入小时的初始值

}

/

以下是对液晶模块的 *** 作程序

/

sbit RS=P2^0; //寄存器选择位,将RS位定义为P20引脚

sbit RW=P2^1; //读写选择位,将RW位定义为P21引脚

sbit E=P2^2; //使能信号位,将E位定义为P22引脚

sbit BF=P0^7; //忙碌标志位,,将BF位定义为P07引脚

/

函数功能:延时1ms

(3j+2)i=(3×33+2)×10=1010(微秒),可以认为是1毫秒

/

void delay1ms()

{

unsigned char i,j;

for(i=0;i<10;i++)

for(j=0;j<33;j++)

;

}

/

函数功能:延时若干毫秒

入口参数:n

/

void delaynms(unsigned char n)

{

unsigned char i;

for(i=0;i<n;i++)

delay1ms();

}

/

函数功能:判断液晶模块的忙碌状态

返回值:result。result=1,忙碌;result=0,不忙

/

bit BusyTest(void)

{

bit result;

RS=0; //根据规定,RS为低电平,RW为高电平时,可以读状态

RW=1;

E=1; //E=1,才允许读写

_nop_(); //空 *** 作

_nop_();

_nop_();

_nop_(); //空 *** 作四个机器周期,给硬件反应时间

result=BF; //将忙碌标志电平赋给result

E=0; //将E恢复低电平

return result;

}

/

函数功能:将模式设置指令或显示地址写入液晶模块

入口参数:dictate

/

void WriteInstruction (unsigned char dictate)

{

while(BusyTest()==1); //如果忙就等待

RS=0; //根据规定,RS和R/W同时为低电平时,可以写入指令

RW=0;

E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,

// 就是让E从0到1发生正跳变,所以应先置"0"

_nop_();

_nop_(); //空 *** 作两个机器周期,给硬件反应时间

P0=dictate; //将数据送入P0口,即写入指令或地址

_nop_();

_nop_();

_nop_();

_nop_(); //空 *** 作四个机器周期,给硬件反应时间

E=1; //E置高电平

_nop_();

_nop_();

_nop_();

_nop_(); //空 *** 作四个机器周期,给硬件反应时间

E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令

}

/

函数功能:指定字符显示的实际地址

入口参数:x

/

void WriteAddress(unsigned char x)

{

WriteInstruction(x|0x80); //显示位置的确定方法规定为"80H+地址码x"

}

/

函数功能:将数据(字符的标准ASCII码)写入液晶模块

入口参数:y(为字符常量)

/

void WriteData(unsigned char y)

{

while(BusyTest()==1);

RS=1; //RS为高电平,RW为低电平时,可以写入数据

RW=0;

E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,

// 就是让E从0到1发生正跳变,所以应先置"0"

P0=y; //将数据送入P0口,即将数据写入液晶模块

_nop_();

_nop_();

_nop_();

_nop_(); //空 *** 作四个机器周期,给硬件反应时间

E=1; //E置高电平

_nop_();

_nop_();

_nop_();

_nop_(); //空 *** 作四个机器周期,给硬件反应时间

E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令

}

/

函数功能:对LCD的显示模式进行初始化设置

/

void LcdInitiate(void)

{

delaynms(15); //延时15ms,首次写指令时应给LCD一段较长的反应时间

WriteInstruction(0x38); //显示模式设置:16×2显示,5×7点阵,8位数据接口

delaynms(5); //延时5ms ,给硬件一点反应时间

WriteInstruction(0x38);

delaynms(5); //延时5ms ,给硬件一点反应时间

WriteInstruction(0x38); //连续三次,确保初始化成功

delaynms(5); //延时5ms ,给硬件一点反应时间

WriteInstruction(0x0c); //显示模式设置:显示开,无光标,光标不闪烁

delaynms(5); //延时5ms ,给硬件一点反应时间

WriteInstruction(0x06); //显示模式设置:光标右移,字符不移

delaynms(5); //延时5ms ,给硬件一点反应时间

WriteInstruction(0x01); //清屏幕指令,将以前的显示内容清除

delaynms(5); //延时5ms ,给硬件一点反应时间

}

/

以下是1302数据的显示程序

/

/

函数功能:显示秒

入口参数:x

/

void DisplaySecond(unsigned char x)

{

unsigned char i,j; //j,k,l分别储存温度的百位、十位和个位

i=x/10;//取十位

j=x%10;//取个位

WriteAddress(0x49); //写显示地址,将在第2行第7列开始显示

WriteData(digit[i]); //将百位数字的字符常量写入LCD

WriteData(digit[j]); //将十位数字的字符常量写入LCD

delaynms(50); //延时1ms给硬件一点反应时间

}

/

函数功能:显示分钟

入口参数:x

/

void DisplayMinute(unsigned char x)

{

unsigned char i,j; //j,k,l分别储存温度的百位、十位和个位

i=x/10;//取十位

j=x%10;//取个位

WriteAddress(0x46); //写显示地址,将在第2行第7列开始显示

WriteData(digit[i]); //将百位数字的字符常量写入LCD

WriteData(digit[j]); //将十位数字的字符常量写入LCD

delaynms(50); //延时1ms给硬件一点反应时间

}

/

函数功能:显示小时

入口参数:x

/

void DisplayHour(unsigned char x)

{

unsigned char i,j; //j,k,l分别储存温度的百位、十位和个位

i=x/10;//取十位

j=x%10;//取个位

WriteAddress(0x43); //写显示地址,将在第2行第7列开始显示

WriteData(digit[i]); //将百位数字的字符常量写入LCD

WriteData(digit[j]); //将十位数字的字符常量写入LCD

delaynms(50); //延时1ms给硬件一点反应时间

}

/

函数功能:显示日

入口参数:x

/

void DisplayDay(unsigned char x)

{

unsigned char i,j; //j,k,l分别储存温度的百位、十位和个位

i=x/10;//取十位

j=x%10;//取个位

WriteAddress(0x0c); //写显示地址,将在第2行第7列开始显示

WriteData(digit[i]); //将百位数字的字符常量写入LCD

WriteData(digit[j]); //将十位数字的字符常量写入LCD

delaynms(50); //延时1ms给硬件一点反应时间

}

/

函数功能:显示月

入口参数:x

/

void DisplayMonth(unsigned char x)

{

unsigned char i,j; //j,k,l分别储存温度的百位、十位和个位

i=x/10;//取十位

j=x%10;//取个位

WriteAddress(0x09); //写显示地址,将在第2行第7列开始显示

WriteData(digit[i]); //将百位数字的字符常量写入LCD

WriteData(digit[j]); //将十位数字的字符常量写入LCD

delaynms(50); //延时1ms给硬件一点反应时间

}

/

函数功能:显示年

入口参数:x

/

void DisplayYear(unsigned char x)

{

unsigned char i,j; //j,k,l分别储存温度的百位、十位和个位

i=x/10;//取十位

j=x%10;//取个位

WriteAddress(0x06); //写显示地址,将在第2行第7列开始显示

WriteData(digit[i]); //将百位数字的字符常量写入LCD

WriteData(digit[j]); //将十位数字的字符常量写入LCD

delaynms(50); //延时1ms给硬件一点反应时间

}

/

函数功能:主函数

/

void main(void)

{

unsigned char second,minute,hour,day,month,year; //分别储存苗、分、小时,日,月,年

unsigned char ReadValue; //储存从1302读取的数据

LcdInitiate(); //将液晶初始化

WriteAddress(0x01); //写Date的显示地址,将在第1行第2列开始显示

WriteData('D'); //将字符常量写入LCD

WriteData('a'); //将字符常量写入LCD

WriteData('t'); //将字符常量写入LCD

WriteData('e'); //将字符常量写入LCD

WriteData(':'); //将字符常量写入LCD

WriteAddress(0x08); //写年月分隔符的显示地址, 显示在第1行第9列

WriteData('-'); //将字符常量写入LCD

WriteAddress(0x0b); //写月日分隔符的显示地址, 显示在第1行第12列

WriteData('-'); //将字符常量写入LCD

WriteAddress(0x45); //写小时与分钟分隔符的显示地址, 显示在第2行第6列

WriteData(':'); //将字符常量写入LCD

WriteAddress(0x48); //写分钟与秒分隔符的显示地址, 显示在第2行第9列

WriteData(':'); //将字符常量写入LCD

Init_DS1302(); //将1302初始化

while(1)

{

ReadValue = ReadSet1302(0x81); //从秒寄存器读数据

second=((ReadValue&0x70)>>4)10 + (ReadValue&0x0F);//将读出数据转化

DisplaySecond(second); //显示秒

ReadValue = ReadSet1302(0x83); //从分寄存器读

minute=((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); //将读出数据转化

DisplayMinute(minute); //显示分

ReadValue = ReadSet1302(0x85); //从分寄存器读

hour=((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); //将读出数据转化

DisplayHour(hour); //显示小时

ReadValue = ReadSet1302(0x87); //从分寄存器读

day=((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); //将读出数据转化

DisplayDay(day); //显示日

ReadValue = ReadSet1302(0x89); //从分寄存器读

month=((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); //将读出数据转化

DisplayMonth(month); //显示月

ReadValue = ReadSet1302(0x8d); //从分寄存器读

year=((ReadValue&0x70)>>4)10 + (ReadValue&0x0F); //将读出数据转化

DisplayYear(year); //显示年

}

}

改改 就是你的了

;   这篇文章算是对我前段时间学习的一个学习总结 以及对自己学习过程的一个回顾 本文通过一个简单的例子来尽可能的展示VCL组件开发的各个方面 本文针对即将学习组件开发的初学者 如果你已经熟悉组件开发或认为本文内容过于基础简单 那么本文对你毫无用处 阅读本文 假设你已经熟悉delphi的普通程序设计以及vcl的结构层次 还有一些重要的关键字 published property等 (注 本文内容建立在delphi 及以上版本)

在这篇文章中我们将建立一个和时间有关的组件 这个组件通过设置它的不同状态有以下基本功能 显示系统的当前时间(包括设置闹钟) 跑表 倒计时 这是一个简单的例子 然而我们将在这个例子中尽可能多的用到delphi在组件开发中的多种特性 你可以通过以下列举出的本文涉及特性有选择的阅读

·组件和组件包

·组件的属性类别

·组件的属性编辑器

·组件编辑器

一 组件和组件包 以及一些你应该知道的文件类型

组件和组件包的关系就如同普通工程中unit和工程文件的关系一样 通常你所安装的组件都是以组件包的形式发布的 一个组件包中可以有很多个组件 在组件开发中 组件包就是项目的工程文件 为了开始开发我们的组件(我们把他叫做TClock)并将它包括在我们自己的组件包(ClockPackage)中 我们选择Fileànewàother在d出的窗口中的New页选择Package新建一个组件包 得到一个组件包窗口 查看这个组件包的原文件( dpk) 得到以下代码

package ClockPackage;

{$R res}

{$ALIGN }

{$ASSERTIONS ON}

……

……

{$DESCRIPTION Our Clock Pack }

{$IMPLICITBUILD OFF}

requires

rtl;

end

这个文件其实就是组件开发中的工程文件 requires关键字指示了组件包所需组件包的列表 随着向组件包中加入组件(类似于单元文件) 你还会看到contains关键字 指示了组件包所包含的组件 你可以通过组件包窗口中的add和remove按纽来添加新的组件和删除已有的组件 另外这个代码中所包含的大量的编译器开关大多都可以在组件包窗体上的Options中设置 这里需要补充说明的是组件包的 种重要属性(都在Options中) Designtime Only Runtime Only Designtime and runtime(这 个词的意思有英语基础的朋友应该都知道吧) 对于大多数的组件包我们只要选择最后一个就可以了 然而有些组件包设计为只运行时(这样你用这套组件开发的程序不能脱离组件而单独运行 组件包也不能被安装) 有些组件包被设计为只设计时(这将在后文有更详细的说明)

了解了组件和组件包 我们对组件开发中可能出现的一些你没有见过的文件做一些说明 dpk文件既组件包的原代码 bpl文件 组件包编译后的结果 在没有发布dpk的情况下可以通过bpl来安装组件包到delphi(ProjectàOptionsàPackagesàadd) pas在这里就是组件包中组件的原代码了 dcu为pas编译后的结果 在你选择将组件包含进组件包时(contains关键字) 你可以选择发布原代码或是不发布(dcu文件) dcp如果你将组件作为运行时组件 连接器将使用该文件

二 开始开发组件

了解了上面的知识后 我们就可以开始开发组件了!在组件窗体中单击add 选择NewComponent页 在第一个组合框中选择我们的组件将要继承自哪个类(通常新的组件是通过继承已有的组件来开发的) 由于这个组件的主要作用是要显示时间 跑表 倒计时种的文字信息 所以我们选择继承自TCustomLabel(由于我们并不需要Tlabel的全部功能 我们选择了能够隐藏Tlabel属性并有选择的发布它的属性的TcustomLabel类) 接下来为我们的新组件取一个名字Tclock 然后指定我们想把组件安装到哪一个页中 这里我们自己键入一个ClockAndTime页 这将出现在RegisterComponents过程中(后面会详细说明) 选择好文件保存的路径后(最好把它和组件dpk包放在同一目录)确认 这是组件包窗体中的contains下已经多了我们刚才建立的组件的文件 双击它开始编写代码

在代码中我们需要注意在interface部分的一个新的过程 procedure Register;(注意 delphi规定Register的R必须大写 这是一个保留字) 这个过程是作为每一个组件所必须有的 它完成组件的注册 包括组件本身以及如属性编辑器等多种组件特性的注册)

procedure Register;

begin

RegisterComponents( ClockAndTime [TClock]);

//这个过程注册组件本身 注意到前面定义的ClockAndTime页了吗?

//这里在后面还会出现一些新的过程 包括注册组件的属性类别等等

end;

组件的代码由于假设你已经熟悉delphi开发(它和一般开发没什么不同) 我们就直接贴出来并加上适当的注释

unit Clock;

interface

uses

SysUtils Classes Controls StdCtrls ExtCtrls;

type

TState=(StClock StRunClock StBackClock);//定义枚举类表示控件的 种状态 时钟 跑表 倒计时钟

TClock = class(TCustomLabel)

private

fState:TState;

fTimer:TTimer;//为什么使用这个组件作为我们组件的私有成员就不用说了吧

RCD:array[ ] of integer;//跑表中的各个数位

fBeginTime:string;//到计时时的开始时钟 之所以没用TTime类型是为了在后面演示属性编辑器

fWakeTime:string;//闹钟时间 出于和上面同样的理由

fAllowWake:boolean;//是否开启闹钟功能

fOnWakeUp:TNotifyEvent;//为了使组件更加完美 我们允许组件用户能够响应闹钟到来时的时件

fOnTimeUp:TNotifyEvent;//同上能够响应倒计时种完成时的事件 我们将发布这两个事件

function GetActive:boolean;//控制Timer是否工作以控制 种状态的钟是否工作

procedure SetActive(Value:boolean);

procedure SetState(Value:TState);

procedure SetBeginTime(Value:string);

procedure SetWakeTime(Value:string);

protected

procedure WalkClock(sender:TObject);//作为时钟时走种的事件

procedure RunClock(sender:TObject); //跑表

procedure BackClock(sender:TObject);//倒计时

public

constructor Create(AOwner:TComponent);override;//完成一些初始化工作

procedure ReSetRunClock; //跑表和倒计时都需要一个复位方法给组件使用者调用

procedure ReSetBackClock;

published

property State:TState read fState write SetState default StClock;//默认为时钟状态

property Active:boolean read GetActive write SetActive;//控制 种状态的钟是否工作

property BeginTime:string read fBeginTime write SetBeginTime;

property WakeTime:string read fWakeTime write SetWakeTime;

property AllowWake:boolean read fAllowWake write fAllowWake;

property OnWakeUp:TNotifyEvent read fOnWakeUp write fOnWakeUp;

property OnTimeUp:TNotifyEvent read fOnTimeUp write fOnTimeUp;

//最后我们再发布一些被TCustomLabel所隐藏而我们又需要的属性

property Align;

property Alignment;

property Color;

property Font;

property ParentColor;

property ParentFont;

property ParentShowHint;

property PopupMenu;

property ShowHint;

property Visible;

property Transparent;

property OnClick;

end;

procedure Register;

implementation

procedure Register;

begin

RegisterComponents( ClockAndTime [TClock]);

end;

{ TClock }

constructor TClock Create(AOwner: TComponent);

begin

inherited Create(AOwner);

//设置默认值

fTimer:=TTimer Create(self);

//将它属于我们的组件 这样便不用编写析构函数 而可以自动在释放本组件时释放Timer

Active:=false;

AllowWake:=false;

State:=StClock;

BeginTime:= : : ;

WakeTime:= : : ;

end;

function TClock GetActive: boolean;

begin

result:=fTimer Enabled;

end;

procedure TClock SetActive(Value: boolean);

begin

fTimer Enabled:=Value;

end;

procedure TClock SetState(Value: TState);

var

i:integer;

begin

case Value of

StClock:

begin

Active:=false;

fTimer Interval:= ;

fTimer OnTimer:=WalkClock;

Active:=true;

end;

StRunClock://由于Time类型不好处理微秒 *** 作 我们只有手工模仿这个 *** 作 代码会稍微烦琐

begin

Active:=false;

for i:= to do RCD[i]:= ;

Caption:=IntToStr(RCD[ ])+IntToStr(RCD[ ])+ : +IntToStr(RCD[ ])+IntToStr(RCD[ ])+ : +IntToStr(RCD[ ]);

Caption:=Caption+IntToStr(RCD[ ])+ : +IntToStr(RCD[ ])+IntToStr(RCD[ ]);

fTimer Interval:= ;

//经过测试 这个秒表的效果很好 然而这只是一个技术上的演示

//实际上这么频繁( / 秒)的不断执行RunClock会使CPU的占用一直达到 %

//这并不是一个好注意 事实上要想在跑表中显示微秒级别并做到合理的占用CPU

//这需要更加灵活和复杂的编程

fTimer OnTimer:=RunClock;

end;

StBackClock:

begin

Active:=false;

Caption:=BeginTime;

fTimer Interval:= ;

fTimer OnTimer:=BackClock;

end;

end;

fState:=Value;

end;

procedure TClock SetBeginTime(Value: string);

begin

try

StrToTime(Value);

fBeginTime:=Value;

if State=StBackClock then

begin

Active:=false;

Caption:=Value;

end;

except

on Exception do

begin

fBeginTime:= : : ;

if State=StBackClock then Caption:= : : ;

end;

end;

end;

procedure TClock SetWakeTime(Value: string);

begin

try

StrToTime(Value);

fWakeTime:=Value;

except

on Exception do

begin

fWakeTime:= : : ;

end;

end;

end;

procedure TClock WalkClock(sender: TObject);

begin

Caption:=TimeToStr(Time);

if AllowWake and (StrToTime(Caption)=StrToTime(WakeTime)) then

begin

Beep;//蜂鸣器

if Assigned(fOnWakeUp) then

fOnWakeUp(self);

end;

end;

procedure TClock RunClock(sender: TObject);

begin

RCD[ ]:=RCD[ ]+ ;

if RCD[ ]= then begin RCD[ ]:=RCD[ ]+ ;RCD[ ]:= ; end;

if RCD[ ]= then begin RCD[ ]:=RCD[ ]+ ;RCD[ ]:= ; end;if RCD[ ]= then begin RCD[ ]:=RCD[ ]+ ;RCD[ ]:= ; end;

if RCD[ ]= then begin RCD[ ]:=RCD[ ]+ ;RCD[ ]:= ; end;

if RCD[ ]= then begin RCD[ ]:=RCD[ ]+ ;RCD[ ]:= ; end;

if RCD[ ]= then begin RCD[ ]:=RCD[ ]+ ;RCD[ ]:= ; end;

if RCD[ ]= then begin RCD[ ]:=RCD[ ]+ ;RCD[ ]:= ; end;

if RCD[ ]= then RCD[ ]:= ; //我们的跑表最多可计 个小时;

Caption:=IntToStr(RCD[ ])+IntToStr(RCD[ ])+ : +IntToStr(RCD[ ])+IntToStr(RCD[ ])+ : +IntToStr(RCD[ ]);

Caption:=Caption+IntToStr(RCD[ ])+ : +IntToStr(RCD[ ])+IntToStr(RCD[ ]);

end;

procedure TClock BackClock(sender: TObject);//可以在一天之类的时间倒计时

begin

if StrToTime(Caption)<>StrToTime( : : ) then

Caption:=TimeToStr(StrToTime(Caption) )

else

begin

Active:=false;

Beep;

if Assigned(fOnTimeUp) then

fOnTimeUp(self);

end;

end;

procedure TClock ReSetBackClock;

var

i:integer;

begin

if State=StRunClock then

begin

Active:=false;

for i:= to do RCD[i]:= ;

Caption:= : : : ;

end;

end;

procedure TClock ReSetRunClock;

begin

if State=StBackClock then

begin

Active:=false;Caption:=BeginTime;

end;

end;

end 为了测试我们的组件 现在你就可以安装这个组件包并建立一个应用测试它了 点击组件包窗体中的install即可(注意 一但你安装了组件包 当你想对组件修改时 在修改了原代码以后只用点击组件窗体的pile就可以了更新组件了) 这时delphi的组件页的最后多出了我们定义的页 其中有了我们的组件!

lishixinzhi/Article/program/Delphi/201311/24840

/

ILONG编做

注意P3口输出模拟和在{实验板}上不一样。实验板不用取反

目的:用20次T0定时产生1s进而形成 HH-mm-ss时间

参数说明:

40H~47H :显示管,每位暂存器,存放要显示的数码的地址。可根据地址加1,实现该位数加1;

并且低4位可以代表管子要显示的值(42H、45H除外)。

48H :要显示的位值(0~7,由译码器翻译出)

49H :每位每次刷出时要显示的时间0~256us

4A :20次定时,的次数计数器

4BH,4CH :小时十位进位刷0,时,小时两位数的暂存

4DH :调试时,要调整类型,每次INT0中断自增一次

50H~5FH :0~F 16个数的码值

60H :"-"的码值

61H :"空" 的码值

62H,63H :要闪的两位地址暂存 (好像没用着)

R0 :存放 每位暂存器 的地址,用于 刷新位时 移位

00H(位) :是否有INT0(调整)中断

01H(位) :是闪亮,还是闪空,即:闪烁时的亮暗状态

存在问题:

1,调整时间时,分钟位开始乱码。

2,调整时间时,必须亮的时候才能调

3,时间差:慢于实际时间

20111021 ilong(crazy night)

/

SJMP 0x0030

ORG 0x0030

MAIN:

//启动外部中断

SETB IT0

SETB IE0

SETB EX0

SETB PX0

SETB IT1

SETB IE1

SETB EX1

SETB PX1

SETB EA

CLR 00H //没有调整中断

CLR 01H //闪空

MOV 4DH,#04H //0xFC

MOV P3,#0FH

MOV 62H,46H //从分开始闪

MOV 63H,47H

//十位数

MOV 50H,#3FH

MOV 51H,#06H

MOV 52H,#5BH

MOV 53H,#4FH

MOV 54H,#66H

MOV 55H,#6DH

MOV 56H,#7DH

MOV 57H,#07H

MOV 58H,#7FH

MOV 59H,#6FH

MOV 5AH,#77H

MOV 5BH,#7CH

MOV 5CH,#39H

MOV 5DH,#5EH

MOV 5EH,#79H

MOV 5FH,#71H

MOV 60H,#40H

MOV 61H,#00H

//八位管的暂存 从左到右40-47

MOV 40H,#50H

MOV 41H,#50H

MOV 42H,#60H

MOV 43H,#50H

MOV 44H,#50H

MOV 45H,#60H

MOV 46H,#50H

MOV 47H,#50H

MOV 48H,#00H //扫描位暂存

MOV R0,#40H //扫描值地址

MOV 4AH,00H //20次定时 计数

LCALL TIMER_GO20 //开启并初始定时器

//主函数进程,就是扫描码管值并显示,其他为中断 *** 作

SCAN: //显示器扫描输出

MOV P2,48H //选择显示位(从左到右0-7)

MOV A,@R0 //获取该位的数码值 地址

MOV R1,A

MOV A,@R1 //获取该位码值

//CPL A //根据数码管是共阴、共阳 是否取反

MOV P0,A //从P0输出每位的码值,注意:该端口时下面的“清屏”一起改

LCALL DELAY //进入每位延时

MOV P0,#0FFH //清屏

INC 48H //暂存器后移

INC R0 //位后移

MOV A,48H //通过 (48H)的值+08H 判断是否到了 位尾

ADD A,#08H

JB 0D6H,RER //D6H(位)为AC(辅助进位:半进位)。为1时说明(48H)的值+08H=F,即(48H)=8,此时跳向RER

SJMP SCAN

RER: //扫描重置

CLR 0D6H //重置 AC(辅助进位:半进位)

MOV 48H,#00H

MOV R0,#40H

SJMP SCAN

//End 主函数

DELAY: //延时,用于扫描7段管时,在每一位停留的时间时间太短,回使不该亮的段也有些亮

MOV 49H,#25H //49H的值不可以等于FF,因为FF取反后49H为0,不会延迟了

MOV A,0FEH //用取反设置循环次数,

CPL A

MOV 49H,A

ADD_1:

INC 49H

MOV R1,49H //因为DJNZ判断完后要把判断的地址减去1,所以为了DJNZ不对49H的内容造成影响,把49H的值装到R1中去判断

DJNZ R1,ADD_1

RET

//20次定时

TIMER_GO20:

//用4AH 设置循环次数

MOV 4AH,#15H //20(=0x15)次定时

MOV A,4AH //用取反设置定时次数,

CPL A

MOV 4AH,A

SJMP TIMER_S

TIMER_GO5: //与TIMER_GO20类似,只是这里只让定时5次一循环。用于调整闪烁

MOV 4AH,#05H //5(=0x05)次定时

MOV A,4AH //用取反设置定时次数,

CPL A

MOV 4AH,A

TIMER_S://未重置(4AH)的调用,

//设置启动T0

MOV TMOD,#01H //设置模式:T0模式1

MOV TH0,#3CH //T0初值高8位

MOV TL0,#0AH //T0初值低8位

//CLR TF0 //未知问题

SETB ET0 //T0允许中断

SETB EA //CPU允许中断

SETB TR0 //启动T0

RET

T0_INT: //T0中断程序段

CPL P17 //测试端口:T0重新定时一次发生一次跳转

LCALL TIMER_S //T0重新定时,继续跑。但:不会初始化20次计数

INC 4AH //T0定时次数加1

MOV A,4AH

JNZ CY_20 //50H加到FF再加就到0了。不为0回去接着执行主程序;为0 则20次定时 溢出即:00H(位)为1

CPL P16 //测试端口每秒发生一次跳转

JB 00H,GO_BLINK //如果00H(位)被置1,则不再执行时间系统加1。用于调整时显示闪烁

LCALL CLOCK_GO //时间系统加1秒

LCALL TIMER_GO20 //20次重新开始

SJMP CY_20

GO_BLINK:

LCALL TIMER_GO5 //5次重新开始,

LCALL BLINK

CY_20: RET

//时间系统进位设置

CLOCK_GO:

INC 47H //秒加1

//个位秒 进位 十位

MOV A,#5AH //主要是看"#5A"中的“A”,

SUBB A,47H

JNZ SS_OUT //如果(47H)值 低4 与A中的低4不相同,跳到“SS_OUT”,不进位

MOV 47H,#50H

INC 46H

SS_OUT:

//秒 进位 分

MOV A,#56H //

SUBB A,46H

JNZ SM_OUT //如果(46H)值 低4 与A中的低4不相同,跳到“SS_OUT”,不进位

MOV 46H,#50H

CLOCK_GO_M:INC 44H

//分调整用

SM_OUT:

//分个位 进位 分

MOV A,#5AH //

SUBB A,44H

JNZ MM_OUT //如果(44H)值 低4 与A中的低4不相同,跳到“SS_OUT”,不进位

MOV 44H,#50H

INC 43H

MM_OUT:

//分 进位 时

MOV A,#56H //

SUBB A,43H

JNZ MH_OUT //如果(43H)值 低4 与A中的低4不相同,跳到“SS_OUT”,不进位

MOV 43H,#50H

CLOCK_GO_H:INC 41H

//时调整用

MH_OUT:

//时个位 进位 时

MOV A,#5AH //

CLR CY //排除借位影响

SUBB A,41H

JNZ HH_OUT //如果(41H)值 低4 与A中的低4不相同,跳到“SS_OUT”,不进位

MOV 41H,#50H

INC 40H

HH_OUT:

//时十位置0

MOV 4BH,40H //为了不影响暂存器数据,把40H、41H转到4BH、4CH中进行 *** 作

MOV 4CH,41H

MOV A,4BH

SWAP A //获得小时十位数,并放到A的高4位上

ANL A,#0F0H //清0低4位

ANL 4CH,#0FH //小时个位 高4位清0

ADD A,4CH //小时的十位与个位相加(高4位来自小时的十位暂存器40H,低四位来自小时个位的寄存器41H)

SUBB A,#24H

JNZ HD_OUT //如果(46H)值 低4 与A中的低4不相同,跳到“SS_OUT”,不进位

MOV 41H,#50H //个位 清零

MOV 40H,#50H //十位清零

HD_OUT:

CG_OUT: RET

//END 时间系统进位设置

//INTO中断程序段

INT0_INT:

SETB 00H

CPL P15

CPL P15

CLR 01H //使得在换位闪烁时不会把上位的数带给下一位,

HMS_BACK: //在每次换位时都要把,被放到暂存上的值那回去,使其显示出来

MOV A,4DH

CJNE A,#02H,BSH_S //back second OR hour _select

LCALL LIGHT_M

SJMP B_END

BSH_S: //恢复秒小时选择

JB CY,B_H

SJMP B_S

B_S: LCALL LIGHT_S //把调好的数据装回暂存器

SJMP B_END

B_H: LCALL LIGHT_H

B_END:

// CLR TR0 //定时器0,停止计时

DEC 4DH //调整类型(时、分、秒)改变

MOV A,4DH

JNZ INT0_OUT //是否恢复时钟

CLR 00H //置0,调整中断(ilong 定义)

CLR 01H

MOV 4DH,#04H //初始化调整类型

INT0_OUT:

RET

////闪烁

BLINK:

CPL P11

CPL 01H

MOV A,4DH

CJNE A,#02H,SH_S

SJMP MM_SET

SH_S: //闪烁秒小时选择

JB CY,HH_SET

SJMP SS_SET

SS_SET: //秒钟设置

JB 01H,DACK_S

LIGHT_S:

MOV 46H,4EH

MOV 47H,4FH

SJMP BLINK_OUT

DACK_S:

MOV 4EH,46H

MOV 4FH,47H

MOV 46H,#61H

MOV 47H,#61H

RET

MM_SET: // 分钟设置

JB 01H,DACK_M

LIGHT_M:

MOV 43H,4EH

MOV 44H,4FH

SJMP BLINK_OUT

DACK_M:

MOV 4EH,43H

MOV 4FH,44H

MOV 43H,#61H

MOV 44H,#61H

RET

HH_SET: //小时设置

JB 01H,DACK_H

LIGHT_H:

MOV 40H,4EH

MOV 41H,4FH

SJMP BLINK_OUT

DACK_H:

MOV 4EH,40H

MOV 4FH,41H

MOV 40H,#61H

MOV 41H,#61H

BLINK_OUT:RET

//INT1中断程序段

INT1_INT:

//lcall HMS_BACK

//clr tr0

CPL P14

MOV A,4DH

CJNE A,#02H,ADDSH_S //ADD Hour OR ADD second OR _select

SJMP ADD_M

ADDSH_S: //调整秒小时选择

JB CY,ADD_H

SJMP ADD_S

ADD_S: LCALL CLOCK_GO

SJMP ADD_END

ADD_M: LCALL CLOCK_GO_M

SJMP ADD_END

ADD_H: LCALL CLOCK_GO_H

ADD_END:

// LCALL CLOCK_GO

RET

/

最后放中断保险些

/

//T0中断程序

ORG 000BH

LCALL T0_INT

RETI

//INT0中断

ORG 0003H

LCALL INT0_INT

RETI

//INT1中断

ORG 0013H

LCALL INT1_INT

RETI

END

org 0000h

ajmp main

org 0030h

main:

mov dptr,#tab

mov 30h,#00h

mov 31h,#00h

mov 32h,#00h

mov 33h,#00h

mov 34h,#00h

mov 35h,#00h

loop:

mov r4,#5

tt1:

lcall display

djnz r4,tt1

lcall update

ajmp loop

display: mov p3,#0h

mov r7,#100

dd1:

mov a,30h

movc a,@a+dptr

mov p1,a

CLR P33

CLR P34

CLR P35

lcall delay100us

mov a,31h

movc a,@a+dptr

mov p1,a ;将要显示的数送入P0口

SETB P33

CLR P34

CLR P35

lcall delay100us ;延时100US

mov a,32h ;将显示缓冲区32H中的值送入ACC

movc a,@a+dptr ;查表取要显示的数并把查表的结果送入ACC

mov p1,a ;将要显示的数送入P0口

SETB P33

SETB P34

CLR P35

lcall delay100us ;延时100US

mov a,33h ;将显示缓冲区33H中的值送入ACC

movc a,@a+dptr ;查表取要显示的数并把查表的结果送入ACC

mov p1,a ;将要显示的数送入P0口

CLR P33

CLR P34

SETB P35

lcall delay100us ;延时100US

mov a,34h ;将显示缓冲区别31H中的值送入A

movc a,@a+dptr ;查表取要显示的数并把查表的结果送入ACC

mov p1,a ;将要显示的数送入P0口

CLR P33

SETB P34

SETB P35

lcall delay100us ;延时100US

mov a,35h ;将显示缓冲区别31H中的值送入A

movc a,@a+dptr ;查表取要显示的数并把查表的结果送入ACC

mov p1,a ;将要显示的数送入P0口

SETB P33

SETB P34

SETB P35

lcall delay100us ;延时100US

djnz r7,dd1 ;R7不等于0返回至DD1处

ret ;R7等于0子程序返回

update: ;刷新显示子程序

inc 30h ;个位显示缓冲单元加一

mov a,30h

cjne a,#10,exit ;还没加到十,退出

mov 30h,#00h ;加到十了,个位清零

inc 31h ;十位显示缓冲单元加一

mov a,31h

cjne a,#6,exit ;还没加到十,退出

mov 31h,#00h ;加到十了,十位清零

inc 32h ;百位显示缓冲单元加一

mov a,32h

cjne a,#10,exit ;还没加到十,退出

mov 32h,#00h ;加到十了,百位清零

inc 33h ;千位显示缓冲单元加一

mov a,33h

cjne a,#6,exit ;还没加到十,退出

mov 33h,#00h ;加到十了,千位清零

inc 34h ;十位显示缓冲单元加一

mov a,34h

cjne a,#10,exit ;还没加到十,退出

mov 34h,#00h ;加到十了,十位清零

inc 35h ;十位显示缓冲单元加一

mov a,35h

cjne a,#10,exit ;还没加到十,退出

mov 35h,#00h ;加到十了,十位清零

exit:

ret ;刷新显示子程序返回

delay100us:

mov r5,#147

djnz r5,$

ret

delay10ms:

mov r6,#100

tt2:

mov r5,#147

djnz r5,$

djnz r6,tt2

ret

tab: db 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0D8H,80H,90H

end

以上就是关于用51单片机实现时钟功能程序全部的内容,包括:用51单片机实现时钟功能程序、XONIX电子表怎么设置xonix电子表调时间、单片机做时钟程序等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zz/9638891.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-30
下一篇 2023-04-30

发表评论

登录后才能评论

评论列表(0条)

保存