标题: 单片机电子时钟如何设置按键来控制时间的加减呢? [打印本页]
作者: 乐呵呵的小鹏 时间: 2018-7-4 08:57
标题: 单片机电子时钟如何设置按键来控制时间的加减呢?
51单片机的电子时钟,如何设置按键来控制时间的加减呢?
作者: zsyzdx 时间: 2018-7-4 11:26
设置变量,加就变量加一,减就变量减一!!!!!!!!!!!
作者: 1157124556 时间: 2018-7-4 11:44
要设置开关来控制
作者: HC6800-ES-V2.0 时间: 2018-7-4 12:20
给你一个例子吧,虽然程序有很多BUG,但自己搞懂了,就可以变成自己的程序了。
main.c:——————————————————————
/*******************************************************************************
* 实验名 : 万年历实验
* 使用的IO :
* 实验效果 :1602显示时钟,按K3进入时钟设置,按K1选择设置的时分秒日月,按K2选择
*选择设置加1。
* 注意 :
*******************************************************************************/
#include<reg51.h>
#include"lcd.h"
#include"ds1302.h"
sbit K1=P3^1;
sbit K2=P3^0;
sbit K3=P3^2;
sbit K4=P3^3;
void Int0Configuration();
void LcdDisplay();
unsigned char SetState,SetPlace;
void Delay10ms(void); //误差 0us
/*******************************************************************************
* 函数名 : main
* 函数功能 : 主函数
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void main()
{
unsigned char i;
Int0Configuration();
LcdInit();
Ds1302Init();
while(1)
{
if(SetState==0)
{
Ds1302ReadTime();
}
else
{
if(K1==0) //检测按键K1是否按下
{
Delay10ms(); //消除抖动
if(K1==0)
{
SetPlace++;
if(SetPlace>=7)
SetPlace=0;
}
while((i<50)&&(K1==0)) //检测按键是否松开
{
Delay10ms();
i++;
}
i=0;
}
if(K2==0) //检测按键K2是否按下
{
Delay10ms(); //消除抖动
if(K2==0)
{
TIME[SetPlace]++;
if((TIME[SetPlace]&0x0f)>9) //换成BCD码。
{
TIME[SetPlace]=TIME[SetPlace]+6;
}
if((TIME[SetPlace]>=0x60)&&(SetPlace<2)) //分秒只能到59
{
TIME[SetPlace]=0;
}
if((TIME[SetPlace]>=0x24)&&(SetPlace==2)) //小时只能到23
{
TIME[SetPlace]=0;
}
if((TIME[SetPlace]>=0x32)&&(SetPlace==3)) //日只能到31
{
TIME[SetPlace]=0;
}
if((TIME[SetPlace]>=0x13)&&(SetPlace==4)) //月只能到12
{
TIME[SetPlace]=0;
}
if((TIME[SetPlace]>=0x7)&&(SetPlace==5)) //周只能到7
{
TIME[SetPlace]=1;
}
// if(SetPlace==5) //月只能到12
// {
// TIME[SetPlace]=;
// }
}
while((i<50)&&(K2==0)) //检测按键是否松开
{
Delay10ms();
i++;
}
i=0;
}
}
LcdDisplay();
}
}
/*******************************************************************************
* 函数名 : LcdDisplay()
* 函数功能 : 显示函数
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void LcdDisplay()
{
LcdWriteCom(0x80+0X40);
LcdWriteData('0'+TIME[2]/16); //时
LcdWriteData('0'+(TIME[2]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+TIME[1]/16); //分
LcdWriteData('0'+(TIME[1]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+TIME[0]/16); //秒
LcdWriteData('0'+(TIME[0]&0x0f));
LcdWriteCom(0x80);
LcdWriteData('2');
LcdWriteData('0');
LcdWriteData('0'+TIME[6]/16); //年
LcdWriteData('0'+(TIME[6]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+TIME[4]/16); //月
LcdWriteData('0'+(TIME[4]&0x0f));
LcdWriteData('-');
LcdWriteData('0'+TIME[3]/16); //日
LcdWriteData('0'+(TIME[3]&0x0f));
LcdWriteCom(0x8D);
LcdWriteData('0'+(TIME[5]&0x07)); //星期
}
/*******************************************************************************
* 函数名 : Int0Configuration()
* 函数功能 : 配置外部中断0
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void Int0Configuration()
{
//设置INT0
IT0=1;//跳变沿出发方式(下降沿)
EX0=1;//打开INT0的中断允许。
EA=1;//打开总中断
}
/*******************************************************************************
* 函数名 : Int0()
* 函数功能 : 外部中断0 中断函数
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void Int0() interrupt 0
{
Delay10ms();
if(K3==0)
{
SetState=~SetState;
SetPlace=0;
Ds1302Init();
}
}
/*******************************************************************************
* 函数名 : Delay10ms
* 函数功能 : 延时函数,延时10ms
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void Delay10ms(void) //误差 0us
{
unsigned char a,b,c;
for(c=1;c>0;c--)
for(b=38;b>0;b--)
for(a=130;a>0;a--);
}
1302.c______________________
#include"ds1302.h"
//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
//---DS1302时钟初始化2013年1月1日星期二12点00分00秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
uchar TIME[7] = {0x00, 0x00, 0x12, 0x01, 0x01, 0x02, 0x13};
/*******************************************************************************
* 函 数 名 : Ds1302Write
* 函数功能 : 向DS1302命令(地址+数据)
* 输 入 : addr,dat
* 输 出 : 无
*******************************************************************************/
void Ds1302Write(uchar addr, uchar dat)
{
uchar n;
RST = 0;
_nop_();
SCLK = 0;//先将SCLK置低电平。
_nop_();
RST = 1; //然后将RST(CE)置高电平。
_nop_();
for (n=0; n<8; n++)//开始传送八位地址命令
{
DSIO = addr & 0x01;//数据从低位开始传送
addr >>= 1;
SCLK = 1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;
_nop_();
}
for (n=0; n<8; n++)//写入8位数据
{
DSIO = dat & 0x01;
dat >>= 1;
SCLK = 1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;
_nop_();
}
RST = 0;//传送数据结束
_nop_();
}
/*******************************************************************************
* 函 数 名 : Ds1302Read
* 函数功能 : 读取一个地址的数据
* 输 入 : addr
* 输 出 : dat
*******************************************************************************/
uchar Ds1302Read(uchar addr)
{
uchar n,dat,dat1;
RST = 0;
_nop_();
SCLK = 0;//先将SCLK置低电平。
_nop_();
RST = 1;//然后将RST(CE)置高电平。
_nop_();
for(n=0; n<8; n++)//开始传送八位地址命令
{
DSIO = addr & 0x01;//数据从低位开始传送
addr >>= 1;
SCLK = 1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;//DS1302下降沿时,放置数据
_nop_();
}
_nop_();
for(n=0; n<8; n++)//读取8位数据
{
dat1 = DSIO;//从最低位开始接收
dat = (dat>>1) | (dat1<<7);
SCLK = 1;
_nop_();
SCLK = 0;//DS1302下降沿时,放置数据
_nop_();
}
RST = 0;
_nop_(); //以下为DS1302复位的稳定时间,必须的。
SCLK = 1;
_nop_();
DSIO = 0;
_nop_();
DSIO = 1;
_nop_();
return dat;
}
/*******************************************************************************
* 函 数 名 : Ds1302Init
* 函数功能 : 初始化DS1302.
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Ds1302Init()
{
uchar n;
Ds1302Write(0x8E,0X00); //禁止写保护,就是关闭写保护功能
for (n=0; n<7; n++)//写入7个字节的时钟信号:分秒时日月周年
{
Ds1302Write(WRITE_RTC_ADDR[n],TIME[n]);
}
Ds1302Write(0x8E,0x80); //打开写保护功能
}
/*******************************************************************************
* 函 数 名 : Ds1302ReadTime
* 函数功能 : 读取时钟信息
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Ds1302ReadTime()
{
uchar n;
for (n=0; n<7; n++)//读取7个字节的时钟信号:分秒时日月周年
{
TIME[n] = Ds1302Read(READ_RTC_ADDR[n]);
}
}
1302.h______________________________
#ifndef __DS1302_H_
#define __DS1302_H_
//---包含头文件---//
#include<reg51.h>
#include<intrins.h>
//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
//---定义ds1302使用的IO口---//
sbit DSIO=P3^4;
sbit RST=P3^5;
sbit SCLK=P3^6;
//---定义全局函数---//
void Ds1302Write(uchar addr, uchar dat);
uchar Ds1302Read(uchar addr);
void Ds1302Init();
void Ds1302ReadTime();
//---加入全局变量--//
extern uchar TIME[7]; //加入全局变量
#endif
LCD.c________________________________
#include"lcd.h"
/*******************************************************************************
* 函 数 名 : Lcd1602_Delay1ms
* 函数功能 : 延时函数,延时1ms
* 输 入 : c
* 输 出 : 无
* 说 名 : 该函数是在12MHZ晶振下,12分频单片机的延时。
*******************************************************************************/
void Lcd1602_Delay1ms(uint c) //误差 0us
{
uchar a,b;
for (; c>0; c--)
{
for (b=199;b>0;b--)
{
for(a=1;a>0;a--);
}
}
}
/*******************************************************************************
* 函 数 名 : LcdWriteCom
* 函数功能 : 向LCD写入一个字节的命令
* 输 入 : com
* 输 出 : 无
*******************************************************************************/
#ifndef LCD1602_4PINS //当没有定义这个LCD1602_4PINS时
void LcdWriteCom(uchar com) //写入命令
{
LCD1602_E = 0; //使能
LCD1602_RS = 0; //选择发送命令
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = com; //放入命令
Lcd1602_Delay1ms(1); //等待数据稳定
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5); //保持时间
LCD1602_E = 0;
}
#else
void LcdWriteCom(uchar com) //写入命令
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 0; //选择写入命令
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = com; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
// Lcd1602_Delay1ms(1);
LCD1602_DATAPINS = com << 4; //发送低四位
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 数 名 : LcdWriteData
* 函数功能 : 向LCD写入一个字节的数据
* 输 入 : dat
* 输 出 : 无
*******************************************************************************/
#ifndef LCD1602_4PINS
void LcdWriteData(uchar dat) //写入数据
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //选择输入数据
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = dat; //写入数据
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5); //保持时间
LCD1602_E = 0;
}
#else
void LcdWriteData(uchar dat) //写入数据
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //选择写入数据
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = dat; //由于4位的接线是接到P0口的高四位,所以传送高四位不用改
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
LCD1602_DATAPINS = dat << 4; //写入低四位
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 数 名 : LcdInit()
* 函数功能 : 初始化LCD屏
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
#ifndef LCD1602_4PINS
void LcdInit() //LCD初始化子程序
{
LcdWriteCom(0x38); //开显示
LcdWriteCom(0x0c); //开显示不显示光标
LcdWriteCom(0x06); //写一个指针加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(0x80); //设置数据指针起点
}
#else
void LcdInit() //LCD初始化子程序
{
LcdWriteCom(0x32); //将8位总线转为4位总线
LcdWriteCom(0x28); //在四位线下的初始化
LcdWriteCom(0x0c); //开显示不显示光标
LcdWriteCom(0x06); //写一个指针加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(0x80); //设置数据指针起点
}
#endif
LCD.h_________________________________
#ifndef __LCD_H_
#define __LCD_H_
/**********************************
当使用的是4位数据传输的时候定义,
使用8位取消这个定义
**********************************/
#define LCD1602_4PINS
/**********************************
包含头文件
**********************************/
#include<reg51.h>
//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
/**********************************
PIN口定义
**********************************/
#define LCD1602_DATAPINS P0
sbit LCD1602_E=P2^7;
sbit LCD1602_RW=P2^5;
sbit LCD1602_RS=P2^6;
/**********************************
函数声明
**********************************/
/*在51单片机12MHZ时钟下的延时函数*/
void Lcd1602_Delay1ms(uint c); //误差 0us
/*LCD1602写入8位命令子函数*/
void LcdWriteCom(uchar com);
/*LCD1602写入8位数据子函数*/
void LcdWriteData(uchar dat) ;
/*LCD1602初始化子程序*/
void LcdInit();
#endif
作者: yang1039710 时间: 2018-7-4 13:38
电子时钟用单片机控制
作者: haikuotian 时间: 2018-7-4 14:15
我是这样做的
-
1893878478.jpg
(689.05 KB, 下载次数: 40)
-
1894796573.jpg
(454.72 KB, 下载次数: 56)
-
1891574732.jpg
(132.13 KB, 下载次数: 36)
作者: haikuotian 时间: 2018-7-4 14:17
;电子钟程序
;
;STC12C5A60S2 12MC 12T
;
;
;以下定义中断向量地址
ORG 0000H
LJMP CHUSI
ORG 0003H
RETI
ORG 000BH ;定时器0中断向量
LJMP DSQ0
ORG 0013H
RETI
ORG 001BH
RETI
ORG 0023H
RETI
ORG 002BH ;定时器2中断向量
RETI
NOP
NOP
NOP
NOP
ORG 0064H
;初始化和定义寄存器用途
CHUSI: CLR A ;清零
MOV 87H,A ;置CPU功率方式
MOV IE,A ;禁止中断
MOV IP,A ;禁止中断优先控制
MOV SCON,A ;关闭串行控制
MOV TMOD,A ;计数器控制
MOV TCON,A ;计数器控制
MOV SP,#080H ;设置栈底
;
MOV P0,#0FFH ;显示划驱动低有效
MOV P2,#0FFH ;显示位驱动,低有效
MOV P3,#0FFH ;按键,低电平有效
MOV 21H,#0 ;62.5mS计数器
MOV 22H,#0 ;
MOV 23H,#0 ;秒计数暂存位
MOV 24H,#10 ;分计数暂存位
MOV 25H,#9 ;时计数暂存位
MOV 26H,#2 ;日计数暂存位,上电为16
MOV 27H,#7 ;月计数暂存位,上电为7
MOV 28H,#1 ;星期计数器
CLR 0H ;时间/日期标志,0=时间,1=日期
MOV 30H,#0 ;
MOV 31H,#0 ;
MOV 32H,#0 ;
MOV 33H,#0H ;
;设置定时器0为16位计数器方式(65536-62500)
MOV TL0,#213 ;重装定时器0寄存器低位(T0=62.5毫微秒)
MOV TH0,#0BH ;重装定时器0高位重装入寄存器
NOP ;
;
NOP ; TMOD GATE C/T M1 M0 GATE C/T M1 M0
MOV TMOD,#01H ;定时/计数 0 0 0 0 0 0 0 1
;
NOP ; TCON TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0
MOV TCON,#00H ;启动定时器0 0 0 0 0 0 0 0 0
;
;
MOV IP,#0H ;中断优先控制 X X PT2 PS PT1 PX1 PT0 PX0
; 0 0 0 0 0 0 0 0
;
;中断控制 EA -- ET2 ES ET1 EX1 ET0 EX0
MOV IE,#10001010B; 1 0 0 1 0 1 0
LJMP XIANSHI
NOP
NOP
ORG 0100H ;
XIANSHI:NOP
JNB P3.2,AJS4 ;查询按键 显示日期
MOV A,23H ;23H里有秒计数器
CJNE A,#5,M6 ;每分钟第5秒到第10秒显示日期
SETB 0H
LJMP D1
M6: CJNE A,#6,M7
SETB 0H
LJMP D1
M7: CJNE A,#7,M8
SETB 0H
LJMP D1
M8: CJNE A,#8,M9
SETB 0H
LJMP D1
M9: CJNE A,#9,M10
SETB 0H
LJMP D1
M10: CLR 0H ;非5 6 7 8 9 显示时间
LJMP D1 ;S4=1 没按
AJS4: SETB 0H ;S4=0 按下
SETB TR0 ;启动用
D1: MOV P0,#0FFH ;关闭显示划驱动,准备显示第一位
MOV P2,#0FFH ;关闭显示位驱动
JB 0,XSRQ1 ;BIT0为1显示日期
MOV B,#10 ;小时计数器0-23
MOV A,25H ;小时计数器
DIV AB ;小时计数器除10,商在A,余数在B
CJNE A,#0,SWW0 ;十位为0不显示
LCALL YSQ1 ;调用延时器1
LJMP D2
XSRQ1: MOV B,#10 ;月份计数器1-12
MOV A,27H ;月份计数器计数器
DIV AB ;小时计数器除10,商在A,余数在B
CJNE A,#0,SWW0 ;十位为0不显示
LCALL YSQ1 ;调用延时器1
LJMP D2
SWW0: LCALL YMQ ;调用译码器
MOV P0,A ;显示划驱动
CLR P2.0 ;显示第一位
LCALL YSQ1 ;调用延时器1
NOP
NOP
NOP
D2: MOV P0,#0FFH ;关闭显示划驱动,准备显示第二位
MOV P2,#0FFH ;关闭显示位驱动
JB 0,XSRQ2 ;BIT0为1显示日期
MOV B,#10 ;小时计数器0-23
MOV A,25H ;小时计数器
DIV AB ;小时计数器除10,商在A,余数在B
MOV A,B ;个位数在B
LCALL YMQ ;调用译码器
MOV P0,A ;显示划驱动
CLR P2.1 ;显示第二位
LCALL YSQ1 ;调用延时器1
LJMP D3
XSRQ2: MOV B,#10 ;月份计数器1-12
MOV A,27H ;月份计数器计数器
DIV AB ;小时计数器除10,商在A,余数在B
MOV A,B ;个位数在B
LCALL YMQ ;调用译码器
MOV P0,A ;显示划驱动
CLR P2.1 ;显示第二位
LCALL YSQ1 ;调用延时器1
NOP
NOP
NOP
D3: MOV P0,#0FFH ;关闭显示划驱动,准备显示第三位
MOV P2,#0FFH ;关闭显示位驱动
JB 0,XSRQ3 ;BIT0为1显示日期
MOV A,#0BFH ;中间划
MOV P0,A ;显示划驱动
CLR P2.2 ;显示第三位
LCALL YSQ1 ;调用延时器1
LJMP D4
XSRQ3: MOV A,#0F7H ;下边划
MOV P0,A ;显示划驱动
CLR P2.2 ;显示第三位
LCALL YSQ1 ;调用延时器1
NOP
NOP
NOP
D4: MOV P0,#0FFH ;关闭显示划驱动,准备显示第四位
MOV P2,#0FFH ;关闭显示位驱动
JB 0,XSRQ4 ;BIT0为1显示日期
MOV B,#10 ;分位计数器0-59
MOV A,24H ;分计数器
DIV AB ;分计数器除10,商在A,余数在B
LCALL YMQ ;调用译码器
MOV P0,A ;显示划驱动
CLR P2.3 ;显示第四位
LCALL YSQ1 ;调用延时器1
LJMP D5
XSRQ4: MOV B,#10 ;日期计数器1-31
MOV A,26H ;日期计数器计数器
DIV AB ;小时计数器除10,商在A,余数在B
CJNE A,#0,SWW4 ;十位为0不显示
LCALL YMQ ;调用译码器
MOV P0,A ;显示划驱动
CLR P2.3 ;显示第四位
LCALL YSQ1 ;调用延时器1
LJMP D5
SWW4: LCALL YMQ ;调用译码器
MOV P0,A ;显示划驱动
CLR P2.3 ;显示第位
LCALL YSQ1 ;调用延时器1
NOP
NOP
NOP
D5: MOV P0,#0FFH ;关闭显示划驱动,准备显示第五位
MOV P2,#0FFH ;关闭显示位驱动
JB 0,XSRQ5 ;BIT0为1显示日期
MOV B,#10 ;小时计数器0-23
MOV A,24H ;小时计数器
DIV AB ;小时计数器除10,商在A,余数在B
MOV A,B ;个位数在B
LCALL YMQ ;调用译码器
MOV P0,A ;显示划驱动
CLR P2.4 ;显示第五位
LCALL YSQ1 ;调用延时器1
LJMP D6
XSRQ5: MOV B,#10 ;月份计数器1-12
MOV A,26H ;月份计数器计数器
DIV AB ;小时计数器除10,商在A,余数在B
MOV A,B ;个位数在B
LCALL YMQ ;调用译码器
MOV P0,A ;显示划驱动
CLR P2.4 ;显示第五位
LCALL YSQ1 ;调用延时器1
NOP
NOP
NOP
D6: MOV P0,#0FFH ;关闭显示划驱动,准备显示第六位
MOV P2,#0FFH ;关闭显示位驱动
JB 0,XSRQ6 ;BIT0为1显示日期
MOV A,#0BFH ;中间划
MOV P0,A ;显示划驱动
CLR P2.5 ;显示第六位
LCALL YSQ1 ;调用延时器1
LJMP D7
XSRQ6: MOV A,#0F7H ;下边划
MOV P0,A ;显示划驱动
CLR P2.5 ;显示第六位
LCALL YSQ1 ;调用延时器1
NOP
NOP
NOP
D7: MOV P0,#0FFH ;关闭显示划驱动,准备显示第七位
MOV P2,#0FFH ;关闭显示位驱动
JB 0,XSRQ7 ;BIT0为1显示日期
MOV B,#10 ;秒计数器0-59
MOV A,23H ;秒计数器
DIV AB ;秒计数器除10,商在A,余数在B
LCALL YMQ ;调用译码器
MOV P0,A ;显示划驱动
CLR P2.6 ;显示第七位
LCALL YSQ1 ;调用延时器1
LJMP D8
XSRQ7: MOV A,#0F7H ;星期计数器
MOV P0,A ;显示划驱动
CLR P2.6 ;显示第七位
LCALL YSQ1 ;调用延时器1
NOP
NOP
D8: MOV P0,#0FFH ;关闭显示划驱动,准备显示第八位
MOV P2,#0FFH ;关闭显示位驱动
JB 0,XSRQ8 ;BIT0为1显示日期
MOV B,#10 ;秒计数器0-59
MOV A,23H ;秒计数器
DIV AB ;秒计数器除10,商在A,余数在B
MOV A,B ;个位数在B
LCALL YMQ ;调用译码器
MOV P0,A ;显示划驱动
CLR P2.7 ;显示第八位
LCALL YSQ1 ;调用延时器1
LJMP XIANSHI
XSRQ8: MOV A,28H ;星期计数器计数器
LCALL YMQ ;调用译码器
MOV P0,A ;显示划驱动
CLR P2.7 ;显示第八位
LCALL YSQ1 ;调用延时器1
LJMP XIANSHI
NOP
NOP
NOP
LJMP XIANSHI
LJMP XIANSHI
DSQ0: PUSH PSW ;程序状态字入栈
PUSH ACC ;累加器入栈
NOP ;空操作 每插入一个操作可增大每日误差115.2毫秒 每8天一秒
NOP ;
NOP
NOP
NOP
NOP
NOP
NOP
NOP
MOV TL0,#197 ;重装定时器0寄存器低位(T0=62.5毫秒)( 减小变慢 增大变快)
MOV TH0,#0BH ;重装定时器0高位重装入寄存器(每调整一个数日误差1.3824秒)
SETB TR0 ;启动定时器0
INC 21H ;定时器0的第1计数器(62.5mS)
LCALL S30 ;查询调秒按键
MOV A,21H ;62.5毫秒+1
CJNE A,#8,P16 ;不到8 半秒则返回
LCALL AJ ;到半秒查询调时分键
LJMP DSQ0W
P16: CJNE A,#16,DSQ0W ;不到整秒时间则返回
MOV 21H,#0 ;62.5毫秒重新计数
INC 23H ;分计数+1
LCALL AJ ;调用按键
MOV A,23H ;比较
CJNE A,#60,DSQ0W ;60秒吗
MOV 23H,#0 ;秒重新计数
INC 24H ;分计数
MOV A,24H ;
CJNE A,#60,DSQ0W ;不到时间则返回
MOV 24H,#0 ;分重新计数
INC 25H ;小时计数
MOV A,25H ;
CJNE A,#24,DSQ0W ;24吗
MOV 25H,#0 ;重新计数
INC 28H ;星期加1
MOV A,28H
CJNE A,#7,RQJS ;每星期7天 显示 0 1 2 3 4 5 6
MOV 28H,#0
RQJS: INC 26H ;日期计数
MOV DPTR,#TSZS ;设置每月天数指示
MOV A,27H ;把当前月数送A
MOVC A,@A+DPTR ;读取该月应有天数
CJNE A,26H,DSQ0W ;比较,如相等,满月了,否则从中断返回
MOV 26H,#1 ;日寄存器置1
INC 27H ;月寄存器加1
MOV A,27H
CJNE A,#13,DSQ0W; 如等于13,月寄存器置1,否则从中断返回
MOV 27H,#1 ;
DSQ0W: POP ACC ;程序状态字出栈
POP PSW ;累加器出栈
RETI ;从定时器0中断返回
NOP
NOP
NOP
YMQ: MOV DPTR,#YMSJ ;设置译码数据地址指针
MOVC A,@A+DPTR ;读取译码数据
RET
RET
YMSJ: DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H,0
NOP
NOP
RET ;返回
NOP
YSQ1: CLR P3.1
MOV 30H,#255 ;延时3
YSQ: NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
DJNZ 30H,YSQ ;5
SETB P3.1
RET
TSZS: DB 0H,32,29,32,31 ;月中天数数据(+1)
DB 32,31,32,32,31
DB 32,31,32
NOP
NOP
NOP
AJ: NOP ;查询按键程序
JNB P3.3,S1 ;查询按键 小时 月
JNB P3.6,S2 ;查询按键 分钟 日
JNB P3.7,S3 ;查询按键 秒 星期
RET ;没有按键 返回
S1: JNB P3.2,S14 ;检查日期显示键 如有效调月份
MOV A,25H ;读取小时到A
CJNE A,#24,XY23 ;小于23吗
MOV 25H,#0 ;23+1=24(0)
RET
XY23: INC 25H ;
RET
NOP
S14: MOV A,27H ;读取月份到A
CJNE A,#12,XY12 ;小于12吗
MOV 27H,#1 ;12+1=1
RET
XY12: INC 27H ;
RET
RET
RET ;
NOP
S2: JNB P3.2,S24 ;检查日期显示键 如有效调月份
MOV A,24H ;读取分到A
CJNE A,#59,XY59 ;小于23吗
MOV 24H,#0 ;59+1=60(0)
RET
XY59: INC 24H ;
RET
NOP
S24: MOV DPTR,#TSZS ;设置每月天数指示
MOV A,27H ;把当前月数送A
MOVC A,@A+DPTR ;读取该月应有天数
DEC A
CJNE A,26H,XYDQY ;比较,如相等,满月了,
MOV 26H,#1 ;12+1=1
RET
XYDQY: INC 26H ;
RET
RET
RET ;
S3: JNB P3.2,S34 ;检查日期显示键 如有效调月份
RET
S34: MOV A,28H ;读取星期到A
CJNE A,#6,XY6 ;小于6吗
MOV 28H,#0 ;6+1=0
RET
XY6: INC 28H ;
RET
RET
RET ;
NOP
S30: JB P3.7,AJFH ;查询按键 秒 星期
JNB P3.2,AJFH ;检查日期显示键 如有效调月份
S31: MOV A,23H ;读取秒到A
CJNE A,#30,XY33 ;等于30吗
S331: MOV 23H,#0 ;等于30退到0
MOV 21H,#0
RET
XY33: JC S331
MOV 23H,#0
MOV 21H,#0
INC 24H ;分计数
MOV A,24H ;
CJNE A,#60,AJFH ;不到时间则返回
MOV 24H,#0 ;分重新计数
INC 25H ;小时计数 ;
AJFH: RET
NOP
RET
RET
RET ;
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
END
作者: 腾飞梦想5 时间: 2018-7-4 14:45
先通过按键加减来设置好变量参数,然后将数值通过写入函数写入时钟芯片
作者: zzffw 时间: 2018-7-4 14:49
按键 长按 触发 功能 是怎么完成的
作者: mengsiu 时间: 2018-7-4 14:55
献丑一下
http://www.51hei.com/bbs/dpj-121532-1.html
作者: 求知心 时间: 2018-7-4 22:46
同求个电子钟程序
作者: haikuotian 时间: 2018-7-5 14:12
回复11楼 求知心 ,7楼是完整的51系列单片机作时钟的程序,用两组端口扫描方式驱动8只数码管,用四个端口作校时控制,利用内部定时器0,分频定时,中断计数,程序支持8051系列40脚的系列,我用的是STC12C560S2,试验通过,日误差能控制到0.125秒
作者: 2015012655 时间: 2018-7-5 14:33
写一个延时函数通过按键改变延时函数参数就行
作者: zl2168 时间: 2018-7-7 16:14
实例94 模拟电子钟(由80C51定时器产生秒时基)
先Proteus仿真一下,确认有效。
以上摘自张志良编著《80C51单片机仿真设计实例教程——基于Keil C和Proteus》清华大学出版社ISBN 978-7-302-41682-1,内有常用的单片机应用100案例,用于仿真实验操作,电路与程序真实可靠可信可行。书中电路和程序设计有详细说明,程序语句条条有注解
作者: zl2168 时间: 2018-7-7 16:16
本帖最后由 zl2168 于 2018-7-7 16:21 编辑
实例93 具有校正功能的时钟1302(LED数码管显示)
先Proteus仿真一下,确认有效。
以上摘自张志良编著《80C51单片机仿真设计实例教程——基于Keil C和Proteus》清华大学出版社ISBN 978-7-302-41682-1,内有常用的单片机应用100案例,用于仿真实验操作,电路与程序真实可靠可信可行。
欢迎光临 (http://www.51hei.com/bbs/) |
Powered by Discuz! X3.1 |