附件里有完整源码,原理图,PCB图,protel格式的,PCB板和12864的尺寸一样大,采用大字符数字显示,效果还是比较好的。源码是论坛里的,做了些改动;
大数字显示时间,冒号闪烁;
加背光调亮度的代码,温度显示有点跳动,后来就改成背光开关了。
DS1302的接晶振的脚留有电容的位置,加10~20pF的电容可以微调时间的精度。有备用电池,掉电时钟芯片继续走时。
实物图:
电路原理图:
背面图:
pcb图(protel99格式):
晶振脚接的15P的电容,测试下来,每天慢2秒,请高手看一下,能不能写一个自动校正误差的函数,我在数码管时钟的程序里写过自动校正误差的函数,但是在这里不行。
以下是数码管时钟自动校正误差的函数:- /*********************************************************************************
- 描述: 8位共阴数码管时钟,显示88-88-88样式,正常走时的时候,两个“-”0.5秒闪烁一次;
- 调时:按KEY1按键第1次分钟位闪烁,再按KEY2一次分钟加1,按KEY3一次分钟减1,长按连加连减;
- 按KEY1按键第2次小时位闪烁,再按KEY2一次小时加1,按KEY3一次小时减1,长按连加连减;
- 按KEY1按键第3次,秒从零开始累加,时钟回到正常走时;
- 对时的时候先调好时、分,分钟要比参考时间的分钟加1分,
- 再看参考时间的秒数到了59再按KEY1按键的第3次,这样对时可以很准的。
- 加备用电池,掉电走时
- 仿真 实物都通过. 11.0592MHz晶振,STC89C52RC,两个74HC573锁存器做位选、段选
- **********************************************************************************/
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- sbit TSCLK = P1^0;//时钟线 接到P10上用杜邦线
- sbit TIO = P1^1;//数据线,接到P11上
- sbit TRST = P1^2;//使能端,接到P12上
- sbit wela = P2^7; //位选
- sbit dula = P2^6; //段选
- sbit KEY1=P3^0; //按键 设置/确认
- sbit KEY2=P3^1; //按键 加
- sbit KEY3=P3^2; //按键 减
- uchar snum,fnum;
- char shi,fen,miao;
- uchar ss;
- char FunctionKeyNum=0; //功能键键值
- char FuncTempNum=0; //功能键临时键值
- typedef enum KeyState{StateInit,StateAffirm,StateSingle,StateRepeat}; //键值状态值
- bit flag=0; //自动校时标志位
- /***********写时分秒地址************/
- #define write_shi 0x84
- #define write_fen 0x82
- #define write_miao 0x80
- #define write_ram 0xc0
- /***********读时分秒地址************/
- #define read_shi 0x85
- #define read_fen 0x83
- #define read_miao 0x81
- #define read_ram 0xc1
- // 0 1 2 3 4 5 6 7 8 9
- uchar d[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //共阴不带小数点
- //uchar dd[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef}; // 共阴带小数点
- void delay(uint z)
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=120;y>0;y--);
- }
- void t0_init() //定时50ms一个中断
- {
-
- TMOD |= 0X01;
- TH0 = (65536-46080)/256;
- TL0 = (65536-46080)%256;
- EA = 1;
- ET0 = 1;
- TR0 = 1;
- }
- void t1_init()
- {
- TMOD |= 0x10;
- TH1 = 0xDC;
- TL1 = 0x00;
- TR1 = 1;
- }
- void temer0() interrupt 1
- {
- TH0=(65536-46080)/256;
- TL0=(65536-46080)%256;
- ss++;
- if(ss==20)
- ss=0;
-
- }
- void display(uchar shi,uchar fen,uchar miao) //显示函数
- {
- if(FunctionKeyNum==0)
- {
- snum=30;
- fnum=30;
- }
-
- if(FunctionKeyNum==1)
- {
- fnum++;
- snum=30;
- }
-
- if(FunctionKeyNum==2)
- {
- snum++;
- fnum=30;
- }
-
-
- if(snum>=30)
- {
- if((shi/10)<1) //如果小时十位小于1,
- {
- dula=1; //消影
- P0=0;
- dula=0;
-
-
- wela=1;
- P0=0xfe; //第1位
- wela=0;
- dula = 1;
- P0=0xff; // 小时十位就不显示
- dula = 0;
- }
-
- else
- {
- dula=1; //消影
- P0=0;
- dula=0;
-
-
- wela=1;
- P0=0xfe; //第1位
- wela=0;
- dula=1;
- P0=d[shi/10];
- dula=0;
- P0=0xff;
- delay(2);
- }
-
- dula=1; //消影
- P0=0;
- dula=0;
-
- wela=1;
- P0=0xfd; //第2位
- wela=0;
- dula=1;
- P0=d[shi%10];
- dula=0;
- delay(2);
-
-
- if(snum==60)
- snum=0;
- }
- // if(miao%2==0) //if(miao%2==0) 1秒闪烁1次
- if(ss>=10) // 这里写为ss>=10,闪烁频率可调
- {
- dula=1; //消影
- P0=0;
- dula=0;
-
- wela=1;
- P0=0xfb; //第3位
- wela=0;
- dula=1;
- P0=0x40; //第三位数码管显示“— ”
-
- dula=0;
- delay(2);
-
- }
- else
- {
- dula=1;
- P0=0;
- dula=0;
-
- wela=1;
- P0=0xfb; //第3位
- wela=0;
- dula=1;
- P0=0; //第三位数码管不显示
- dula=0;
- delay(2);
- }
-
-
- if(fnum>=30)
- {
- dula=1; //消影
- P0=0;
- dula=0;
-
- wela=1;
- P0=0xf7; //第4位
- wela=0;
- dula=1;
- P0=d[fen/10];
- dula=0;
- delay(2);
-
- dula=1;
- P0=0;
- dula=0;
- wela=1;
- P0=0xef; //第5位
- wela=0;
- dula=1;
- P0=d[fen%10];
- dula=0;
- delay(2);
-
-
- if(fnum==60)
- fnum=0;
- }
-
- // if(miao%2==0) //if(miao%2==0) 1秒闪烁1次
- if(ss>=10) //if(ss>=10)闪烁频率可调
- {
- dula=1;
- P0=0;
- dula=0;
-
- wela=1;
- P0=0xdf; //第6位
- wela=0;
- dula=1;
- P0=0x40; //第六位数码管显示“— ”
- dula=0;
- delay(2);
- }
- else
- {
- dula=1; //消影
- P0=0;
- dula=0;
-
- wela=1;
- P0=0xdf; //第6位
- wela=0;
- dula=1;
- P0=0; //第六位数码管不显示
- dula=0;
- delay(2);
- }
- //--------------------/
- dula=1; //消影
- P0=0;
- dula=0;
-
- wela=1;
- P0=0xbf; //第7位
- wela=0;
- dula=1;
- P0=d[miao/10]; //秒十位
- dula=0;
- delay(2);
- //--------------------/
- dula=1; //消影
- P0=0;
- dula=0;
-
- wela=1;
- P0=0x7f; //第8位
- wela=0;
- dula=1;
- P0=d[miao%10]; //秒个位
- dula=0;
- delay(2);
- }
- //写DS1302数据
- void Write_DS1302_DAT(uchar cmd, uchar dat)
- {
- uchar i;
- TRST = 0; //拉低使能端
- TSCLK = 0;//拉低数据总线
- TRST = 1; //拉高使能端,产生上升沿开始写数据
- for(i = 0; i < 8; i++)//每次写1位,写8次
- {
- TSCLK = 0; //拉低时钟总线
- TIO = cmd & 0x01; //写1位数据,从最低位开始写
- TSCLK = 1; //拉高时钟总线,产生上升沿数据被DS1302读走
- cmd >>=1; //右移一位
- }
- for(i = 0; i < 8; i++)//每次写1位,写8次
- {
- TSCLK = 0; //拉低时钟总线
- TIO = dat & 0x01; //写1位数据,从最低位开始写
- TSCLK = 1; //拉高时钟总线,产生上升沿数据被DS1302读走
- dat >>= 1; //右移一位
- }
- }
- //读DS1302数据
- uchar Read_DS1302_DAT(uchar cmd)
- {
- uchar i, dat;
- TRST = 0; //拉低使能端
- TSCLK = 0; //拉低数据总线
- TRST = 1; //拉高使能端,产生上升沿开始写数据
- for(i = 0; i < 8; i++)//每次写1位,写8次
- {
- TSCLK = 0; //拉低时钟总线
- TIO = cmd & 0x01;//写1位数据,从最低位开始写
- TSCLK = 1; //拉高时钟总线,产生上升沿数据被DS1302读走
- cmd >>=1; //右移一位
- }
- for(i = 0; i < 8; i++)//每次读1位,读8次
- {
- TSCLK = 0; //拉低时钟总线,产生下降沿,DS1302把数据放到TIO上
- dat >>= 1; //右移一位
- if(TIO) dat |= 0x80;//读取数据,从最低位开始
- TSCLK = 1; //拉高时钟总线,以备下一次产生下降沿
- }
- return dat; //返回读出数据
- }
- //数据转BCD码
- uchar Dat_Chg_BCD(uchar dat)
- {
- uchar dat1, dat2;
- dat1 = dat / 10;
- dat2 = dat % 10;
- dat2 = dat2 + dat1 * 16;
- return dat2;
- }
- //BCD码转换为数据
- uchar BCD_Chg_Dat(uchar dat)
- {
- uchar dat1, dat2;
- dat1 = dat / 16;
- dat2 = dat % 16;
- dat2 = dat2 + dat1 * 10;
- return dat2;
- }
- void init_1302() //初始化函数 设置时间
- { //加备用电池,掉电走时
- if((Read_DS1302_DAT(0x81)& 0x80) != 0) //读出秒数据,再跟80h(0x80)与运算看结果,结果是0则不需要初始化1302;是80h就要初始化!
- {
- Write_DS1302_DAT(0x8e, 0);//清除写保护
- Write_DS1302_DAT(0x80, Dat_Chg_BCD(58));//58秒(并且进行BCD码转换)
- Write_DS1302_DAT(0x82, Dat_Chg_BCD(10));//10分
- Write_DS1302_DAT(0x84, Dat_Chg_BCD(9));//9时
- Write_DS1302_DAT(0x8e, 0x80);//开写保护
- }
- }
- void read_sf()
- {
- miao = BCD_Chg_Dat(Read_DS1302_DAT(0x81));//读秒寄存器(并且进行BCD码转换)
- fen = BCD_Chg_Dat(Read_DS1302_DAT(0x83));//读分寄存器
- shi = BCD_Chg_Dat(Read_DS1302_DAT(0x85));//读时寄存器
- display(shi,fen,miao);
- }
- void zdjs() //自动校时,这方法测试可行,每天减去快出的秒数
- {
- if((shi==12)&&(fen==0)&&(miao==4)) // 清翔实验板上的时钟每天快4秒
- {
- if(flag==0)
- {
- Write_DS1302_DAT(0x8e,0x00); //写保护取消
- Write_DS1302_DAT(write_miao,0x00); //写秒0,这里是假如每天快4秒,每到这个时候就减去4秒
- Write_DS1302_DAT(0x8e,0x80); //启动写保护
- flag=1; //标志位置1,不然这里会成一个死循环
- }
- }
- if((shi==12)&&(fen==1)&&(miao==0))
- flag=0; //标志位清零,准备第二天校时
- }
- void KeyScan(void)
- {
- static uchar KeyStateTemp1 = 0; //按键状态临时存储值1
- static uchar KeyStateTemp2 = 0; //按键状态临时存储值2
- static uchar KeyStateTemp3 = 0; //按键状态临时存储值3
- static uchar KeyTime = 0; //按键延时时间
- bit KeyPressTemp1; //按键是否按下存储值1
- bit KeyPressTemp2; //按键是否按下存储值2
- bit KeyPressTemp3; //按键是否按下存储值3
- KeyPressTemp1 = KEY1; //读取IO口的键值
- switch(KeyStateTemp1)
- {
- case StateInit:
- if(!KeyPressTemp1) //KEY1按下
- KeyStateTemp1 = StateAffirm; //按键状态切换到确认态
- break;
- case StateAffirm: //确认状态
- if(!KeyPressTemp1) //按键还在按下
- {
- KeyTime = 0;
- KeyStateTemp1 = StateSingle; //按键状态切换到单击状态
- }
- else KeyStateTemp1 = StateInit; //否则按键抬起,回到初始态
- break;
-
- case StateSingle: //单击
- if(KeyPressTemp1)
- {
- KeyStateTemp1 = StateInit; //按键释放
- FuncTempNum++; //键值加1
- if(FuncTempNum>3) FuncTempNum = 0;
- }
- else if(++KeyTime>100)
- {
- KeyPressTemp1 = StateRepeat;
- KeyTime = 0;
- }
- break;
-
- case StateRepeat: //连发
- if(KeyPressTemp1)
- KeyStateTemp1 = StateInit;
- else
- {
- if(++KeyTime > 10)
- {
- KeyTime = 0;
- FuncTempNum++;
- if(FuncTempNum>3) FuncTempNum = 0;
- }
- break;
- }
- break;
-
- default :KeyStateTemp1 = KeyStateTemp1 = StateInit; break;
-
- }
- if(FuncTempNum) //只有功能键被按下后,增加和减小键才有效
- {
- KeyPressTemp2 = KEY2; //读取I/O口的键值
- switch(KeyStateTemp2)
- {
- case StateInit: //按键初始状态
- if(!KeyPressTemp2) //当按键按下,状态切换到确认态
- KeyStateTemp2 = StateAffirm;
- break;
- case StateAffirm: //按键确认态
- if(!KeyPressTemp2)
- {
- KeyTime = 0;
- KeyStateTemp2 = StateSingle;//切换到单次触发态
- }
- else KeyStateTemp2 = StateInit; //按键已抬起,切换到初始态
- break;
- case StateSingle: //按键单发态
- if(KeyPressTemp2) //按下时间小于1s
- {
- KeyStateTemp2 = StateInit; //按键释放,则回到初始态
- if(FunctionKeyNum == 1) //若功能键第一次按下
- {
- fen++;
- fen=fen/10*16+fen%10; //转为16进制
- if(fen==0x60)
- fen=0x00;
- Write_DS1302_DAT(write_fen,fen);
- // write_1302(write_fen,fen); //写入1302
- read_sf(); //读出时间,然后显示
- }
- if(FunctionKeyNum == 2) //若功能键第二次按下
- {
- shi++;
- shi=shi/10*16+shi%10; //转为16进制
- if(shi==0x24)
- shi=0x00;
- Write_DS1302_DAT(write_shi,shi);
- // write_1302(write_shi,shi);
- read_sf();
- }
- }
- else if(++KeyTime > 100) //按下时间大于1s(100*10ms)
- {
- KeyStateTemp2 = StateRepeat;//状态切换到连发态
- KeyTime = 0;
- }
- break;
- case StateRepeat: //按键连发态
- if(KeyPressTemp2)
- KeyStateTemp2 = StateInit; //按键释放,则进初始态
- else //按键未释放
- {
- if(++KeyTime > 10) //按键计时值大于100ms(10*10ms)
- {
- KeyTime = 0;
- if(FunctionKeyNum == 1) //若功能键第一次按下
- {
- fen++;
- fen=fen/10*16+fen%10; //转为16进制
- if(fen==0x60)
- fen=0x00;
- Write_DS1302_DAT(write_fen,fen);
- // write_1302(write_fen,fen); //写入1302
- read_sf(); //读出时间,然后显示
- }
-
- if(FunctionKeyNum == 2) //若功能键第二次按下
- {
- shi++;
- shi=shi/10*16+shi%10; //转为16进制
- if(shi==0x24)
- shi=0x00;
-
- Write_DS1302_DAT(write_shi,shi);
- // write_1302(write_shi,shi);
- read_sf();
- }
- }
- break;
- }
- break;
- default: KeyStateTemp2 = KeyStateTemp2 = StateInit; break;
- }
- KeyPressTemp3 = KEY3; //读取I/O口的键值
- switch(KeyStateTemp3)
- {
- case StateInit: //按键初始状态
- if(!KeyPressTemp3) //当按键按下,状态切换到确认态
- KeyStateTemp3 = StateAffirm;
- break;
- case StateAffirm: //按键确认态
- if(!KeyPressTemp3)
- {
- KeyTime = 0;
- KeyStateTemp3 = StateSingle; //切换到单次触发态
- }
- else KeyStateTemp3 = StateInit; //按键已抬起,切换到初始态
- break;
- case StateSingle: //按键单发态
- if(KeyPressTemp3) //按下时间小于1s
- {
- KeyStateTemp3 = StateInit; //按键释放,则回到初始态
- if(FunctionKeyNum == 1) //若功能键第一次按下
- {
- fen--;
- fen=fen/10*16+fen%10; //转为16进制
- if(fen==-1)
- fen=0x59;
- Write_DS1302_DAT(write_fen,fen);
- // write_1302(write_fen,fen);
- read_sf();
- }
- if(FunctionKeyNum == 2) //若功能键第二次按下
- {
- shi--;
- shi=shi/10*16+shi%10; //转为16进制
- if(shi==-1)
- shi=0x23;
-
- Write_DS1302_DAT(write_shi,shi);
- // write_1302(write_shi,shi);
- read_sf();
- }
- }
- else if(++KeyTime > 100) //按下时间大于1s(100*10ms)
- {
- KeyStateTemp3 = StateRepeat; //状态切换到连发态
- KeyTime = 0;
- }
- break;
- case StateRepeat: //按键连发态
- if(KeyPressTemp3)
- KeyStateTemp3 = StateInit; //按键释放,则进初始态
- else //按键未释放
- {
- if(++KeyTime > 10) //按键计时值大于100ms(10*10ms)
- {
- KeyTime = 0;
- if(FunctionKeyNum == 1) //若功能键第一次按下
- {
- fen--;
- fen=fen/10*16+fen%10; //转为16进制
- if(fen==-1)
- fen=0x59;
- Write_DS1302_DAT(write_fen,fen);
- // write_1302(write_fen,fen);
- read_sf();
- }
- if(FunctionKeyNum == 2) //若功能键第二次按下
- {
- shi--;
- shi=shi/10*16+shi%10; //转为16进制
- if(shi==-1)
- shi=0x23;
- Write_DS1302_DAT(write_shi,shi);
- // write_1302(write_shi,shi);
- read_sf();
- }
- }
- break;
- }
- break;
- default: KeyStateTemp3 = KeyStateTemp3 = StateInit; break;
- }
- }
- }
- void ExecuteKeyNum()
- {
- if(TF1)
- {
- TF1 = 0;
- TH1 = 0xDC;
- TL1 = 0x00;
- KeyScan();
- }
- switch (FuncTempNum)
- {
- case 1: FunctionKeyNum = 1;
- Write_DS1302_DAT(0x8e,0x00); //写保护取消
- Write_DS1302_DAT(write_miao,0x80); // 写秒80,时钟停止走时;
- break;
-
- case 2: FunctionKeyNum = 2;
- break;
-
- case 3:
- FunctionKeyNum = 0;
- Write_DS1302_DAT(write_miao,0x00);
- Write_DS1302_DAT(0x8e,0x80); //保护启动
- FuncTempNum =0;
- break;
- }
- }
- void main()
- {
- t0_init();
- t1_init();
- init_1302();
- while(1)
- {
- read_sf();
- ExecuteKeyNum();
- zdjs();//自动校时
- }
- }
复制代码
单片机源程序:
- /*---------------------------------------------------------------------------
- 单 片 机:STC90C516RD+ (HEX文件不到8K,用STC89C52也可以)
- 晶 振:11.0592MHz
- 时钟芯片:DS1302
- 测温芯片:DS18B20
- 接 收 头:HS0038BD
- 液 晶 屏:LCM-12864-ST7920
- 功能描述: 大数字显示时间;能显示农历、温度和设置闹铃;有整点报时功能
- 红外遥控和按键都能设置时间、闹铃和背光的开关
- 实物测试通过
- ------------------------------------------------------------------------------*/
- /*-------------------------------头文件---------------------------------------*/
- #include <reg52.h>
- #include <intrins.h>
- #include "LCD12864.h"
- #include "DS1302.h"
- #include "DS18B20.h"
- #include "nongli.h"
- #include "displaytime.h"
- #include "zk.h"
- #include "bell.h"
- #include "HW.H"
- #include "delay.h"
- #define uint unsigned int
- #define uchar unsigned char
- /*--------------------定义按键-----------------------------------------------*/
- sbit K1 = P3^0; //K1-设置
- sbit K2 = P3^1; //K2-确认、返回
- sbit K3 = P3^3; //K3-加
- sbit K4 = P3^4; //K4-减
- sbit K6 = P3^6; //背光开关
- sbit BL = P2^7; //背光控制端
- /*---------------------函数声明------------------------------*/
- void ds_w0(void);
- void ds_w(void);
- void Conver_week(bit c,uchar year,uchar month,uchar day);
- /*-----------------------------定义全局变量------------------------------*/
- bit w=0; //调时标志位
- unsigned char yy,mo,dd,xq,hh,mm,ss,month_moon,day_moon,week,tiangan,dizhi,moontemp1,moontemp2;//定义时间映射全局变量(专用寄存器)
- signed char address,item,item0,max,mini;
- unsigned char clk_ala[2]={0x00,0x00};//闹钟数据存放初,始值为00:00
- unsigned char hour,minute,time;//用于闹铃的设置
- //unsigned char ba=5,bi=0;
- /*-----------------------------日期、时间设置函数-----------------------------*/
- void tiaozheng(void){
- yy = read_clock(0x8d);//调用1302时钟数据中的年数据,从地址0x8d中
- mo = read_clock(0x89);//调用1302时钟数据中的月数据,从地址0x89中
- dd = read_clock(0x87);//从1302芯片中读取日数据,从地址0x87中
- week = read_clock(0x8b);//从1302芯片中读取星期数据,从地址0x8b中
- //----------------------------------
- lcm_w_test(0,0x80);
- lcm_w_word("20");//显示内容字符20
- lcm_w_test(1,(yy/16)+0x30);//函数参数1,代表本行写数据,YY/16+0X30得出年十位数字的显示码地址,送显示
- lcm_w_test(1,yy%16+0x30);//函数
- lcm_w_word("年");
- //----------------------------------
- lcm_w_test(1,(mo/16)+0x30);
- lcm_w_test(1,mo%16+0x30);//与16取余数,得到月份的个位数,加0x30得到该数字的液晶内定显示码送显示
- lcm_w_word("月");//调用字符显示函数,显示文字 月
- //----------------------------------
- /*
- lcm_w_test(0,0x88);//第一个参数0,表示本行写入LCM的是指令,指定显示位置88H(第三行左端)
- lcm_w_word("星期");//调用字符显示函数,显示文字 星期
- lcm_w_test(1,mo%16+0x30);//与16取余数,得到月份的个位数,加0x30得到该数字的液晶内定显示码送显示
- */
- //----------------------------------
- lcm_w_test(1,(dd/16)+0x30);
- lcm_w_test(1,dd%16+0x30);//第一个1参数,表示本行写数据,日数据与16取余得个位数,加0x30得到显示码
- lcm_w_word("日");//显示字符 日
- //----------------------------------
- if(read_clock(0x85) != hh){//如果程序中的小时与1302芯片中的不同,
- hh = read_clock(0x85);//刷新程序中的小时数据
- }
- lcm_w_test(0,0x91);//第一个参数0,表示本行写入LCM的是指令,指定显示位置88H(第三行左端)
- lcm_w_test(1,(hh/16)+0x30);//显示十位
- lcm_w_test(1,hh%16+0x30);//显示个位
- lcm_w_word("时");
- //----------------------------------
- if(read_clock(0x83) != mm){//如果1302芯片中的分钟数据与程序中的分钟变量不相等
- mm = read_clock(0x83);//刷新程序中的分钟数据
- }
- lcm_w_test(1,(mm/16)+0x30);//向液晶写数据,显示分钟的十位数
- lcm_w_test(1,mm%16+0x30);//向液晶写数据,显示分钟的个位数
- lcm_w_word("分");
- //----------------------------------
- if(read_clock(0x81) != ss){//如果1302芯片中的分钟数据与程序中的秒钟变量不相等(0x81为读秒数据0x80为写秒数据)
- ss = read_clock(0x81);//刷新程序中的秒钟数据
- }
- lcm_w_test(1,(ss/16)+0x30);//向液晶写数据,显示分钟的十位数
- lcm_w_test(1,ss%16+0x30);//向液晶写数据,显示分钟的个位数
- lcm_w_word("秒");
- //////////////////////////////////////////////////////////////////////
- //=========显示闹钟的设置时间===================
-
- hour=clk_ala[0]; //取出上一次的闹钟小时值
- minute=clk_ala[1]; //取出上一次的闹钟分钟值
-
- lcm_w_test(0,0x88);
- lcm_w_word("闹钟---");
- //----------------------------
- lcm_w_test(1,(hour/10)+0x30);//显示小时十位
- lcm_w_test(1,(hour%10)+0x30);//显示小时个位
- //----------------------------
- lcm_w_word(":");
- //----------------------------
- lcm_w_test(1,(minute/10)+0x30);//显示分钟的十位
- lcm_w_test(1,(minute%10)+0x30);//显示分钟的个位
- //----------------------------
- lcm_w_word("----");
- /////////////////////////////////////////////////////////////////////////
- }
- /*****************************************************************************/
- //被调数据加一或减一,并检查数据范围,写入1302指定地址保存
- void ds_w(void)
- {
- item0=time;
- item=((read_clock(address+1))/16)*10 + (read_clock(address+1))%16;//时间的调整
- if(K3 == 0||key_add==1){//如果按动上调键
- item++;//数加 1
- }
- if(K4 == 0||key_minish==1){//如果按动下调键
- item--;//数减 1
- }
- if(item>max) item=mini;//查看数值是否在有效范围之内
- if(item<mini) item=max;//如果数值小于最小值,则自动等于最大值
- write_clock(0x8e,0x00);//允许写1302芯片操作
- write_clock(address,(item/10)*16+item%10);//转换成16进制写入1302
- write_clock(0x8e,0x80);//写保护,禁止写操作
- }
- /********************************************************************/
- //===============闹钟时间的加减设置======================
- void ds_w0(void)
- {
- item0=time;
- if(K3 == 0||key_add==1){//如果按动上调键
- item0++;//数加 1
- }
- if(K4 == 0||key_minish==1){//如果按动下调键
- item0--;//数减 1
- }
- if(item0>max) item0=mini;//查看数值是否在有效范围之内
- if(item0<mini)item0=max;//如果数值小于最小值,则自动等于最大值
- time=item0;//调整后的时间重新赋值给time(time为hour或minute),这步很重要,没有将无法更新闹钟数据
- }
- /**********************************************************************************************************/
- //调整时间子函数,设置键、数据范围、上调加一,下调减一功能。
- void Set_time(unsigned char sel){ //根据选择调整的相应项目加1并写入DS1302,函数参数是按动设置键的次数
- write_com(0x30); write_com(0x06);
- lcm_w_test(0,0x98);//第一参数0表示本行写入指令,指定下面行的 调整 显示起始位置为9AH
- lcm_w_word(">>调整>> <<<<");//调用字符显示函数,显示 调整字样
- /* if(sel==8) {lcm_w_word("星期");address=0x8a; max=7;mini=1;
- tiaozheng();
- ds_w();
- tiaozheng();
- }
- */
- //================================================================
- lcm_w_test(0,0x9c);
- if(sel==7) {lcm_w_word("闹钟分"); time=minute;max=59;mini=0;
- tiaozheng();//显示调整前的内容
- ds_w0();//设置闹钟
- clk_ala[1]=time;//把更新后的分钟数据重新保存
- tiaozheng();//显示调整后的内容
- }//按动8次显示 调整闹钟的分钟部分
- if(sel==6) {lcm_w_word("闹钟时");time=hour; max=23;mini=0;
- tiaozheng();
- ds_w0();
- clk_ala[0]=time;//把更新后的小时数据重新保存
- tiaozheng();
- }//按动7次显示 调整闹钟的小时部分
- //================================================================
- if(sel==5) {lcm_w_word("秒钟");address=0x80; max=59;mini=0;
- tiaozheng(); //调用日期、时间调整函数
- ds_w(); //被调数据加一或减一函数
- tiaozheng();
- } //秒6,按动6次显示 调整秒钟
- //并指定秒钟数据写入1302芯片的写入地址是0x80,秒钟数据的最大值是59,最小值是0
- if(sel==4) {lcm_w_word("分钟");address=0x82; max=59;mini=0;
- tiaozheng();
- ds_w();
- tiaozheng();
- } //分钟5,按动5次显示 调整分钟
- //并指定分钟数据写入1302芯片的地址是0x82,分钟数据的最大值是59,最小值是0
- if(sel==3) {lcm_w_word("小时");address=0x84; max=23;mini=0;
- tiaozheng();
- ds_w();
- tiaozheng();
- } //小时4,按动4次显示 调整小时
- //规定小时数据写入1302芯片的位置是0x84,小时数据最大值23,最小值是0
- if(sel==2) {lcm_w_word("日期");address=0x86;
- mo = read_clock(0x89);//读月数据
- moontemp1=mo/16;
- moontemp2=mo%16;
- mo=moontemp1*10+moontemp2;//转换成10进制月份数据
- yy = read_clock(0x8d);//读年数据
- moontemp1=yy/16;
- moontemp2=yy%16;
- yy=moontemp1*10+moontemp2;//转换成10进制年份数据
- if(mo==2&&yy%4!=0){max=28;mini=1;}//平年2月28天
- if(mo==2&&yy%4==0){max=29;mini=1;}//闰年2月29天
- if(mo==1||mo==3||mo==5||mo==7||mo==8||mo==10||mo==12){max=31;mini=1;}//31天的月份
- if(mo==4||mo==6||mo==9||mo==11){max=30;mini=1;}//30天的月份
- tiaozheng();
- ds_w();
- tiaozheng(); //调用日期、时间调整函数
- } //日3,按动3次显示 调整日期
- //规定日期数据写入1302的位置地址是0x86,日期最大值31,最小值是1
- if(sel==1) {lcm_w_word("月份");address=0x88; max=12;mini=1;
- tiaozheng();
- ds_w();
- tiaozheng();
- } //月2,按动2次显示 调整月份
- //规定月份写入1302的位置地址是0x88,月份最大值12,最小值1
- if(sel==0) {lcm_w_word("年份");address=0x8c; max=99; mini=0;
- tiaozheng();
- ds_w(); //被调数据加一或减一函数
- tiaozheng(); //调用日期、时间调整函数
- } //年1,按动1次显示 调整年份,
- //规定年份写入1302的地址是0x8c,年份的最大值99,最小值0
- }
- /*********************************************************************
- **********************************************************************
- ************** 主函数 ****************
- **********************************************************************
- /********************************************************************/
- void main()
- {
- unsigned char e=0,f=0,tmp,i;
- IE = 0x81; //允许总中断中断,使能 INT0 外部中断
- TCON = 0x01; //触发方式为脉冲负边沿触发
- IRIN=1; //IO口初始化
- // TMOD |=0x02;
- //// EA=1;
- // ET0=1;
- // TR0=1;
-
-
- BEEP=1;
- K1=1;K2=1;K3=1;K4=1; K6=1;
-
- BL = 0;
- // duan = 1;
- // P0 = 0;
- // duan = 0;
- Init_1302(); //时钟芯片初始化
- lcm_init(); //液晶初始化
- welcome0(); //调用欢迎信息1
- DelayM(2000);//延时
- //welcome();DelayM(1000); //调用欢迎信息2
- lcm_clr(); //清屏
- Clean_12864_GDRAM(); //清屏
- while(1)
- {
- if (w == 0) //正常走时
- {
- displaydate(); //显示日期
- displaynl(); //显示农历
- displaytime(); //显示时间
- read_temp(); //读取温度
- ds1820disp(); //显示温度
- displayxq(); //显示星期
-
- //=================以下是闹钟的相关处理===================
-
- if(ala_flag==1){//闹钟标志位
- set1616pic(6,1,0,2);} //显示"闹钟图标"
- else{
- set1616pic(6,1,0,3);}//关闭"闹钟图标"显示
- //----------------------------------------
- tmp=read_clock(0x85);//取出1302小时
- i = tmp/16;
- tmp = tmp&0x0f;
- tmp = tmp + i*10;
- if(clk_ala[0]==tmp)//与闹钟设定的小时值相同
- {
- tmp=read_clock(0x83);//取出1302分钟
- i = tmp/16;
- tmp = tmp&0x0f;
- tmp = tmp + i*10;
- if(clk_ala[1]==tmp)//与闹钟设定的分钟值相同
- {
- if(ala_flag==1)//闹钟打开
- {
- alarmbeep();//闹铃声响1分钟后自动关闭,
- DelayM(200);//控制闹钟响的间隔即频率
- }
- else BEEP=1;//关闭蜂鸣器
- }
- else BEEP=1;//关闭蜂鸣器
- }
- //==============闹钟处理结束=======================
- }
- else {} //========否则启动调时=========================
- /*---------------按键及红外遥控设置时间------------------------------*/
- if (K1 == 0||key_manue==1)
- {
-
- DelayM(8); //按键消抖
- /*当是调时状态 本键用于调整下一项---------------------------------------------------*/
- if((K1 == 0 && w == 1)||(key_manue==1&&w==1)) //
- {
-
- e++;
- if (e >= 8 ) {e = 0;}
- while(! K1 ); //等待键松开
- key_manue=0;
- Set_time(e); beep(); //调整
- }
- /*当是正常状态时就进入调时状态---------------------------------------------------*/
- if((K1 == 0 && w == 0)||(key_manue==1&&w==0)) //
- {
- key_manue=0;
- lcm_clr();
- Clean_12864_GDRAM(); //清屏
- w=1; //进入调时
- Set_time(e);beep();
- }
- while(K1 == 0); //等待键松开
- }
- /*当在调时状态时就退出调时---------------------------------------------------*/
- if (K2 == 0||key_ok==1) //
- { beep();
- DelayM(8);
- if((K2 == 0 && w == 1)||(key_ok==1&&w==1))
- {
- w = 0; //退出调时
- e = 0; //"下一项"计数器清0
- }
- if((K2 == 0 && w == 0)||(key_ok==1&&w==0))
- {
- lcm_clr(); Clean_12864_GDRAM();
- write_com(0x30); write_com(0x06);
- welcome();
- while(K2 == 0); //按下K2是显示欢迎信息
- DelayM(500);key_ok=0;//红外"OK"按键按下时显示0.5秒钟的欢迎界面2
- }
- lcm_clr(); Clean_12864_GDRAM();
- // ds_write(0x0a,0x20); //调时完毕,开启时钟振荡器
-
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
全部资料下载地址:
万年历12864 红外 按键.rar
(866.48 KB, 下载次数: 335)
|