用51单片机实现时钟功能程序???
duanEQUP0;
weiEQUP2;
keyBITP3.7;
ORG0000H
AJMPMAIN;绝对转移指令,2kb范围(11位)内跳转LJMP16位64kb范围内跳转
;短转移指令的功能是先使程序计数器PC加1两次(即:取出指令码),然后把加2后的地址和rel相加作为目标转移地址。因此,短转移指令是一条相对转移指令,是一条双字节双周期指令
ORG0030H;指明后面的程序从程序存储器的0030H单元开始存放
DELAY200US:;@11.0592MHz
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微秒的时间。
2013-08-28
推荐于2017-12-16
#define uint unsigned int
#define ulong unsigned long
#include <reg52.h> //包括一个52标准内核的头文件
uchar code zixing[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
uchar code ziwei[]={0x10,0x20,0x40,0x80};
uchar *h,*m;
uchar hour=12,min=0,sec=0,h_ding,m_ding,count=0,ms_50,ms_10,miaobiao_sec;
sbit dp=P0^7;
sbit k1=P3^2;
sbit k2=P3^3;
sbit k3=P3^4;
sbit sound=P2^3;
sfr ZIXING=0x80; //p0口输出字形
sfr ZIWEI=0xa0; //P2口输出字位
typedef enum //枚举类型:4种状态//
{
CLOCK,
SET_RING1,
SET_RING2,
MIAOBIAO_RUN,
}STATE;
STATE status;
typedef struct //定时时间的数据结构//
{
uchar hour;
uchar min;
}DINGSHI_TIME;
DINGSHI_TIME dingshi_time[2];
#define NO_KEY -1 //定义一下方便使用
#define KEY_1 1
#define KEY_2 2
#define KEY_3 3
bit show_on_flag;
//#######定时器T0中断服务程序########//
Timer0() interrupt 1
{
TH0=0x3c;TL0=0xb4; //50ms
ms_50++;
if(ms_50==20) {sec++;ms_50=0;}
if(sec==60) {sec=0;min++;}
if(min==60) {min=0;hour++;}
if(hour==24) {hour=0;}
}
//#######定时器T1中断服务程序########//
Timer1() interrupt 3
{
TH1=0xd8;TL1=0xf4; //10ms
ms_10++;
if(ms_10==100)
{
miaobiao_sec++;
ms_10=0;
}
if(miaobiao_sec==60)
miaobiao_sec=0;
}
//##############数码管显示#####################//
show(uchar time_high,uchar time_low)
{
uchar m;
uint n,k;
k=time_high*1000/10+time_low;
for(m=0;m<4;m++)
{
ZIXING=zixing[k%10];
if(ms_50<10)
dp=0;
ZIWEI=~ziwei[m];
for(n=0;n<500;n++);
ZIXING=0xff;
for(n=0;n<100;n++);
k=k/10;
}
}
//显示 on 定时编号//
show_on(uchar id) //id:定时编号//
{
uchar m;
uint n;
for(m=0;m<2;m++)
{
ZIXING=zixing[id%10];
dp=0;
ZIWEI=~ziwei[m];
for(n=0;n<500;n++);
ZIXING=0xff;
for(n=0;n<80;n++);
id=id/10;
}
ZIXING=0xc8; //字母n//
ZIWEI=~ziwei[2];
for(n=0;n<500;n++);
ZIXING=0xff;
for(n=0;n<200;n++);
ZIXING=0xc0; //字母0//
ZIWEI=~ziwei[3];
for(n=0;n<500;n++);
ZIXING=0xff;
for(n=0;n<200;n++);
}
/*************启动秒表***************/
void run_miaobiao()
{
ms_10=0;
miaobiao_sec=0;
TH1=0xd8; //标准是0xd8e4
TL1=0xf4;
// TR1=1; //启动定时器1
}
/*************显示秒表***************/
void show_miaobiao()
{
show(miaobiao_sec,ms_10);
}
/*********** 检测按键动作函数 *************/
int get_key()
{
uchar d;
if(!k1)
{
for(d=0;d<50;d++);
if(!k1)
{
while(!k1);
return(KEY_1);
}
}
if(!k2)
{
for(d=0;d<50;d++);
if(!k2)
{
while(!k2);
return(KEY_2);
}
}
if(!k3)
{
for(d=0;d<50;d++);
if(!k3)
{
while(!k3);
return(KEY_3);
}
}
else return NO_KEY;
}
/*****************************************
各状态下按键处理函数
******************************************/
void key_process_clock() // 处理时钟状态下的按键和显示//
{
switch(get_key())
{
case KEY_1:
status=SET_RING1; ;//切换状态
show_on_flag=1;
show_on(1);
break;
case KEY_2:
hour++;
if(hour==24) hour=0;
show(hour,min);
break;
case KEY_3:
min++;
if(min==60) min=0;
show(hour,min);
break;
case NO_KEY: //没有按键操作//
show(hour,min);
break;
}
}
/****************设定时1或2状态下的按键处理及显示*****************/
void key_process_set_dingshi()
{
switch(get_key())
{
case KEY_1:
if(status==SET_RING1)
{
status=SET_RING2; //切换设第二段定时状态
show_on_flag=1;
show_on(2);
}
else if(status==SET_RING2)
{
status=MIAOBIAO_RUN; //切换到秒表运行状态
run_miaobiao();
show_miaobiao();
}
break;
case KEY_2:
dingshi_time[status-1].hour++;
if(dingshi_time[status-1].hour==24)
dingshi_time[status-1].hour=0;
show(dingshi_time[status-1].hour,dingshi_time[status-1].min);
show_on_flag=0;
break;
case KEY_3:
dingshi_time[status-1].min++;
if(dingshi_time[status-1].min==60)
dingshi_time[status-1].min=0;
show(dingshi_time[status-1].hour,dingshi_time[status-1].min);
show_on_flag=0;
break;
case NO_KEY: //没有按键操作//
if(show_on_flag)
show_on(status);
else
show(dingshi_time[status-1].hour,dingshi_time[status-1].min);
break;
}
}
/********秒表运行状态按键处理及显示*********/
void key_process_miaobiao_run()
{
switch(get_key())
{
case KEY_1:
TR1=0;
status=CLOCK; //回到时钟显示状态
break;
case KEY_2:
TR1=!TR1; //定时器1暂停、继续
break;
case KEY_3:
TR1=0; //秒表复位
miaobiao_sec=0;
ms_10=0;
break;
case NO_KEY: //无按键操作//
show_miaobiao();
break;
}
}
//############主程序#######################//
void main(void)
{ sound=1;
TH0=0x3c;
TL0=0xb4;
TMOD=0x11;
TR0=1;
ET0=1;
TR1=0;
ET1=1;
EA=1;
status=CLOCK;
dingshi_time[0].hour=0;
dingshi_time[0].min=0;
dingshi_time[1].hour=0;
dingshi_time[1].min=0;
while(1) //程序循环
{
switch(status)
{
case CLOCK:
key_process_clock(); // 处理时钟状态下的按键和显示//
break;
case SET_RING1:
case SET_RING2:
key_process_set_dingshi(); //处理设置定时状态下的按键和显示//
break;
case MIAOBIAO_RUN:
key_process_miaobiao_run(); //处理秒表状态下的按键和显示//
break;
}
if(
((hour==dingshi_time[0].hour) //定时响铃//
&&(min==dingshi_time[0].min)
&&(sec<5))
||
((hour==dingshi_time[1].hour) //定时响铃//
&&(min==dingshi_time[1].min)
&&(sec<5))
)
sound=0;
else sound=1;
}
}