万年历制作
标签: DS1302,DS18B20,AT89S52,万年历
DS1302 万年历的制作
上次做了简单的数码管数字钟(详情请点击http://www.555diy.com/n_show.asp?nid=66),后来又修改了程序,改成自己想要的按键设置方法(详情请点击http://bbs.555diy.com/dispbbs.asp?boardID=8&ID=298&page=1)。功能是实现了,可是觉得太浪费了89S52,做的也不够好看,拿不出手,于是开始酝酿做个漂亮一点的,至少像个产品,也进一步锻炼自己的...
标签: DS1302,DS18B20,AT89S52,万年历
DS1302 万年历的制作
上次做了简单的数码管数字钟(详情请点击http://www.555diy.com/n_show.asp?nid=66),后来又修改了程序,改成自己想要的按键设置方法(详情请点击http://bbs.555diy.com/dispbbs.asp?boardID=8&ID=298&page=1)。功能是实现了,可是觉得太浪费了89S52,做的也不够好看,拿不出手,于是开始酝酿做个漂亮一点的,至少像个产品,也进一步锻炼自己的编程能力,毕竟我也只能算个初学者。
为了让万年历的时钟走的更准,在网上了解了一些资料后,决定用DS1302做为时钟芯片(下载DS1302中文资料请点击http://www.555diy.com/s_show.asp?sid=19)。要显示年、月、日、星期、时、分、秒一共需要15个数码管,如果只显示时间的话有点单调,于是又加个3个数码管用来显示温度。一共18个数码管,不能用IO口直接驱动了,那样的话占用的IO口多,也怕到时候扫描下来会出现闪烁。看了其他人的一些
后,决定将“年”的前2位(20)用一个口驱动,剩下的16个数码管用2个74HC164来输出段码,用P0口来驱动片选。那用什么来检测温度呢?网上查了一下,觉得DS18B20不错,也有一些实例程序可以借鉴,不过价格偏贵。用555和热敏电阻组成测温的话,因为热敏电阻的阻值不是线性的,做的准不容易。考虑来考虑去,决定把这两个都LAY在板子上。另外加个4个按键,几个LED指示灯,还有用来当闹钟的蜂鸣器。另外加了24C01用来存储设定的闹钟时间。
原理图如下:
后来才发现控制板的排阻位置放错了,该打PP ^__^
LAY好的PCB
下面是做好的板子,这年头什么都涨价,PCB也涨啊~~~晒晒图先~
再来几张焊上元件的图
接下来是工作中的万年历,白天拍的,数码管不是很亮,程序还没有完全编好,有些功能还没实现
下面这张是在设定闹钟时的万年历
现在一天走下来的话会快3、4秒,看了DS1302的DATASHEET,说是在晶振的两端并一6PF的电容会好点。
有何问题和建议可以去论坛http://bbs.555diy.com/dispbbs.asp?boardID=8&ID=326&page=1讨论,谢谢!
按键功能描述:
正常显示下:
按S1:全部数码管闪烁 → 按S3进入时间设定模式
→ 按S4进入闹钟设定模式
按S2:进入睡眠模式,全部数码管熄灭,LED6闪烁 → 按S1恢复显示
按S3:闹钟关闭
按S4:闹钟打开,并显示闹钟时间3秒
时间设定模式及闹钟设定模式:
按S1:不设定时间或闹钟
按S2:待设定数码管左移
按S3:待设定数码管+1
按S4:保存设定
C代码如下:
//*****************************************************//
// www.555diy.com 三五电子网 //
//作者;ksysl //
//日期:2008-03-04 //
//PCB型号:calendar001-A calendar001-B(组合而成) //
//软件版本:DS1302 002-A //
//*****************************************************//
//*****************************************************//
#include
#include
#include
unsigned char year,month,day,week,hour,minute,second;
unsigned char temp_1,temp_2,temp_3;
unsigned char buff1,buff2;
unsigned char disp_data;
unsigned int temp_data;
unsigned char led_flash_flag; //设定时间时数码管闪烁用
unsigned char tcnt;
unsigned char add_data; //设时数据暂放用
unsigned char save_data; //保存设时用
unsigned char led_data1,led_data2,led_data3,led_data4,led_data5,led_data6,led_data7;//设定时间数据保存区
unsigned char led_data8,led_data9,led_data10,led_data11,led_data12,led_data13; //设定时间数据保存区
unsigned char key;
unsigned char key_qu;
unsigned char key_flag;
unsigned char set_flag; //=0 正常显示时间;=1设定时间;=2设定闹钟时间;=3不显示时间;=4选择设定时间还是闹钟;
unsigned char led_select; //数码管选择用
unsigned char set_time_over; //60秒无按键按下自动返回用
unsigned char led_select1,led_select2; //数码管闪烁选择用
unsigned char sleep; //=1关闭数码管显示用
unsigned char clock_set; //闹钟设定标志,=1关闭其余数码管
unsigned char clock_set_flag;
unsigned char clock_hour,clock_minute,clock_second;//闹钟时间
unsigned char hour_data,minute_data,second_data; //正常显示时间暂放区
unsigned char clock_time; //闹钟响铃记时
unsigned char clock_come; //闹钟时间到标志
unsigned char code disp_code[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x00}; //0~9段码 第10位为设定时间时数码管闪烁用
sbit s1=P2^0; //按键定义
sbit s2=P2^1;
sbit s3=P2^2;
sbit s4=P2^3;
sbit hc164data=P2^7; //74HC164数据口
sbit hc164clock=P2^6; //74HC164时钟口
sbit clock="P1"^0; //闹钟打开显示 LOW----亮
sbit wake_up=P1^1; //定时唤醒显示 LOW----亮
sbit led_flash=P1^2; //正常显示时LED闪烁控制 LOW----亮
sbit year_20=P1^3; //年份前两位显示控制 LOW----亮
sbit buzzer="P1"^4; //闹钟时间到响铃用 LOW----响
sbit ds1302_sclk=P1^5; //DS1302时钟口
sbit ds1302_rst=P1^6; //DS1302复位口
sbit ds1302_data=P1^7; //DS1302数据口
sbit DQ="P3"^7; //DS18B20数据口
void display(void);
void key_scan(void);
void send_hc164_data(void);
void delay(unsigned char time);
void int_1(void);
void int_0(void);
void time_1(void);
//延时函数
void delay_us(unsigned int us)
{
for(;us>0;us--);
}
//初始化函数
unsigned char RES_DS18B20(void)
{
unsigned char x;
DQ = 0; //DQ复位
delay_us(29); //精确延时 大于 480us
DQ = 1;
delay_us(3); //稍做延时
x=DQ;
delay_us(25);
return(x); //稍做延时后 如果x=0则初始化成功 x="1则初始化失败"
}
//读一个字节
unsigned char ReadOneChar(void)
{
unsigned char i;
unsigned char dat="0";
for (i=8;i>0;i--)
{
dat>>=1;
DQ = 0; // 给脉冲信号
DQ = 1; // 给脉冲信号
delay_us(1);
if(DQ==1)
{
dat|=0x80;
}
delay_us(6);
}
return(dat);
}
//写一个字节
WriteOneChar(unsigned char da)
{
unsigned char i;
for (i=8; i>0; i--)
{
DQ = 0;
DQ = da&0x01;
delay_us(5);
DQ = 1;
da="da/2";
}
delay_us(5);
}
//读取温度
float ReadTemperature(void)
{
unsigned char a="0";
unsigned char b="0";
unsigned char c="0";
unsigned char d="0";
unsigned int t="0";
float tt="0";
RES_DS18B20();
WriteOneChar(0xCC); // 跳过读序号列号的操作
WriteOneChar(0x44); // 启动温度转换
delay_us(10);
RES_DS18B20();
WriteOneChar(0xCC); //跳过读序号列号的操作
WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
a=ReadOneChar(); //LSB
b=ReadOneChar(); //MSB
t="b"*256+a; //将char转为int型
tt=t*0.0625; //实际温度
tt= tt*10+0.5; // 将实际温度放大10倍输出并四舍五入
return(tt);
}
//********DS1302读写程序**********************************************//
/**********************************************************************
函 数 名:input_byte1302()
功 能:实时时钟写入一字节
说 明:往DS1302写入1Byte数据 (内部函数)
入口参数:inputdata 写入的数据
返 回 值:无
***********************************************************************/
void input_byte1302(unsigned char inputdata)
{
unsigned char i;
for(i=8; i>0; i--)
{
ds1302_data = (bit)(inputdata&0x01);
ds1302_sclk = 1;
ds1302_sclk = 0;
inputdata = inputdata >>1;
}
}
/********************************************************************
函 数 名:output_byte1302()
功 能:实时时钟读取一字节
说 明:从DS1302读取1Byte数据 (内部函数)
入口参数:无
返 回 值:outputdata
设 计: 日 期:
修 改: 日 期:
***********************************************************************/
unsigned char output_byte1302(void)
{
unsigned char i;
for(i=0; i<8; i++)
{
ACC = ACC >>1; //相当于汇编中的 RRC
ACC7 = ds1302_data;
ds1302_sclk = 1;
ds1302_sclk = 0;
}
return(ACC);
}
/********************************************************************
函 数 名:write1302()
功 能:往DS1302写入数据
说 明:先写地址,后写命令/数据 (内部函数)
调 用:input_byte1302()
入口参数:addr: DS1302地址, indata: 要写的数据
返 回 值:无
***********************************************************************/
void write1302(unsigned char addr, unsigned char indata)
{
ds1302_rst = 0;
ds1302_sclk = 0;
ds1302_rst = 1;
input_byte1302(addr); // 地址,命令
input_byte1302(indata); // 写1Byte数据
ds1302_sclk = 1;
ds1302_rst = 0;
}
/********************************************************************
函 数 名:read1302()
功 能:读取DS1302某地址的数据
说 明:先写地址,后读命令/数据 (内部函数)
调 用:input_byte1302() , output_byte()
入口参数:addr: DS1302地址
返 回 值:outdata :读取的数据
***********************************************************************/
unsigned char read1302(unsigned char addr)
{
unsigned char outdata;
ds1302_rst = 0;
ds1302_sclk = 0;
ds1302_rst = 1;
input_byte1302(addr); // 地址,命令
outdata = output_byte1302(); // 读1Byte数据
ds1302_sclk = 1;
ds1302_rst = 0;
return(outdata);
}
void delay(unsigned char time) //延时
{
unsigned char m;
unsigned char n;
for(m=time;m>0;m--)
for(n=248;n>0;n--);
}
//********************************************************************//
// 74hc164发送数据
void send_hc164_data(void)
{
unsigned char i;
disp_data=disp_code[buff2];
hc164clock=0;
for(i=0;i<8;i++)
{
hc164data=(bit)(disp_data&0x80);
hc164clock=1;
disp_data<<=1;
hc164clock=0;
}
disp_data=disp_code[buff1];
for(i=0;i<8;i++)
{
hc164data=(bit)(disp_data&0x80);
hc164clock=1;
disp_data<<=1;
hc164clock=0;
}
hc164clock=0;
}
// 74hc164发送数据结素
//**************************************************************************//
//**************************************************************************//
// 数码管显示程序开始
void display()
{
if(sleep==0)
{
if(clock_set==0)
{
year_20=0;
delay(3);
year_20=1;
}
//************************************************************************//
if(((bit)(led_select1&0x01)==1)||(clock_set==1))
{
buff1=10;
}
else
{
buff1=led_data1;
}
if((bit)(led_select2&0x01)==1)
{
buff2=10;
}
else
{
buff2=led_data8;
}
send_hc164_data();
P0=0xfe;
delay(3);
P0=0xff;
//***********************************************************************//
if(((bit)(led_select1&0x02)==1)||(clock_set==1))
{
buff1=10;
}
else
{
buff1=led_data2;
}
if((bit)(led_select2&0x02)==1)
{
buff2=10;
}
else
{
buff2=led_data9;
}
send_hc164_data();
P0=0xfd;
delay(3);
P0=0xff;
//************************************************************************//
if(((bit)(led_select1&0x04)==1)||(clock_set==1))
{
buff1=10;
}
else
{
buff1=led_data3;
}
if((bit)(led_select2&0x04)==1)
{
buff2=10;
}
else
{
buff2=led_data10;
}
send_hc164_data();
P0=0xfb;
delay(3);
P0=0xff;
//***********************************************************************//
if(((bit)(led_select1&0x08)==1)||(clock_set==1))
{
buff1=10;
}
else
{
buff1=led_data4;
}
if((bit)(led_select2&0x08)==1)
{
buff2=10;
}
else
{
buff2=led_data11;
}
send_hc164_data();
P0=0xf7;
delay(3);
P0=0xff;
//***********************************************************************//
if(((bit)(led_select1&0x10)==1)||(clock_set==1))
{
buff1=10;
}
else
{
buff1=led_data5;
}
if((bit)(led_select2&0x10)==1)
{
buff2=10;
}
else
{
buff2=led_data12;
}
send_hc164_data();
P0=0xef;
delay(3);
P0=0xff;
//**********************************************************************//
if(((bit)(led_select1&0x20)==1)||(clock_set==1))
{
buff1=10;
}
else
{
buff1=led_data6;
}
if((bit)(led_select2&0x20)==1)
{
buff2=10;
}
else
{
buff2=led_data13;
}
send_hc164_data();
P0=0xdf;
delay(3);
P0=0xff;
//*************************************************************************//
if(((bit)(led_select1&0x40)==1)||(clock_set==1))
{
buff1=10;
}
else
{
buff1=led_data7;
}
if(clock_set==1)
{
buff2=10;
}
else
{
buff2=temp_1;
}
send_hc164_data();
P0=0xbf;
delay(3);
P0=0xff;
//**************************************************************************//
if(clock_set==0)
{
buff1=temp_3;
buff2=temp_2;
send_hc164_data();
P0=0x7f;
delay(3);
P0=0xff;
}
}
//****************************************************************************//
// 需设定数码管闪烁,设定时间和闹钟共用
if((set_flag==1)||(set_flag==2))
{
switch(led_select)
{
case 1: led_select1=0x00;
led_select2=0x00;
if(led_flash_flag==0)
{
led_select1=0x01;
}
break;
case 2: led_select1=0x00;
led_select2=0x00;
if(led_flash_flag==0)
{
led_select1=0x02;
}
break;
case 3: led_select1=0x00;
led_select2=0x00;
if(led_flash_flag==0)
{
led_select1=0x04;
}
break;
case 4: led_select1=0x00;
led_select2=0x00;
if(led_flash_flag==0)
{
led_select1=0x08;
}
break;
case 5: led_select1=0x00;
led_select2=0x00;
if(led_flash_flag==0)
{
led_select1=0x10;
}
break;
case 6: led_select1=0x00;
led_select2=0x00;
if(led_flash_flag==0)
{
led_select1=0x20;
}
break;
case 7: led_select1=0x00;
led_select2=0x00;
if(led_flash_flag==0)
{
led_select1=0x40;
}
break;
case 8: led_select1=0x00;
led_select2=0x00;
if(led_flash_flag==0)
{
led_select2=0x01;
}
break;
case 9: led_select1=0x00;
led_select2=0x00;
if(led_flash_flag==0)
{
led_select2=0x02;
}
break;
case 10: led_select1=0x00;
led_select2=0x00;
if(led_flash_flag==0)
{
led_select2=0x04;
}
break;
case 11: led_select1=0x00;
led_select2=0x00;
if(led_flash_flag==0)
{
led_select2=0x08;
}
break;
case 12: led_select1=0x00;
led_select2=0x00;
if(led_flash_flag==0)
{
led_select2=0x10;
}
break;
case 13: led_select1=0x00;
led_select2=0x00;
if(led_flash_flag==0)
{
led_select2=0x20;
}
break;
default : break;
}
}
}
//*****************************************************************************************//
// 数码管显示程序结束
//********************************************************************************//
//**********************************************************************************//
// 按键处理程序开始
void key_scan(void)
{
if(clock_come==1) //闹钟响时按S1,关闭闹钟
{
if(s1==0)
{
clock_come=0;
clock="0";
buzzer="1";
set_flag=0;
}
}
if(set_flag==2)
{
if(s1==0) //闹钟时间设定时按S1,退出闹钟设定时间,不保存闹钟设定时间
{
set_time_over=119;
}
if(s4==0) //闹钟时间设定时按S4,保存闹钟设定时间
{
clock="0";
// led_data8=led_data8<<4;
clock_hour=(led_data8*10+led_data9);
// led_data10=led_data10<<4;
clock_minute=(led_data10*10+led_data11);
// led_data12=led_data12<<4;
clock_second=(led_data12*10+led_data13);
set_time_over=119;
}
}
if(set_flag==4)
{
if(s1==0) //时间设定选择时按S1退出选择
{
set_time_over=119;
}
if(s3==0) //时间设定选择时按S3进入时间设定
{
sleep="0";
set_flag=1;
led_flash=1;
led_select=1;
}
if(s4==0) //时间设定选择时按S4进入闹钟设定
{
sleep="0";
clock_set=1;
set_flag=2;
led_select=8;
led_flash=1;
led_data8=clock_hour/10;
led_data9=clock_hour%10;
led_data10=clock_minute/10;
led_data11=clock_minute%10;
led_data12=clock_second/10;
led_data13=clock_second%10;
}
}
if(set_flag==1)
{
if(s1==0) //设定时间的情况下再按S1,退出设定时间,不保存设定时间
{
set_time_over=119;
}
if(s4==0) //设定时间的情况下按S4,保存设定时间
{
write1302(0x8e,0x00);
led_data12=led_data12<<4;
save_data=led_data12+led_data13;
write1302(0x80,save_data);
led_data10=led_data10<<4;
save_data=led_data10+led_data11;
write1302(0x82,save_data);
led_data8=led_data8<<4;
save_data=led_data8+led_data9;
write1302(0x84,save_data);
led_data5=led_data5<<4;
save_data=led_data5+led_data6;
write1302(0x86,save_data);
led_data3=led_data3<<4;
save_data=led_data3+led_data4;
write1302(0x88,save_data);
save_data=led_data7;
write1302(0x8a,save_data);
led_data1=led_data1<<4;
save_data=led_data1+led_data2;
write1302(0x8c,save_data);
write1302(0x8e,0x80);
set_time_over=119;
}
}
if(set_flag==1) //设定时间
{
if(s2==0) //按S2需设定数码管右移
{
set_time_over=0;
led_select++;
if(led_select==14)
{
led_select=1;
}
}
}
if(set_flag==2) //闹钟设定时间
{
if(s2==0) //按S2需设定数码管右移
{
set_time_over=0;
led_select++;
if(led_select==14)
{
led_select=8;
}
}
}
if((set_flag==1)||(set_flag==2)) //按S3需设定数码管加1,设定时间和闹钟共用
{
if(s3==0)
{
set_time_over=0;
switch(led_select)
{
case 1:
led_data1++;
if(led_data1==10)
{
led_data1=0;
}
break;
case 2:
led_data2++;
if(led_data2==10)
{
led_data2=0;
}
break;
case 3:
led_data3++;
if(led_data3==2)
{
led_data3=0;
}
break;
case 4:
led_data4++;
if(led_data4==10)
{
led_data4=0;
}
break;
case 5:
led_data5++;
if(led_data5==4)
{
led_data5=0;
}
break;
case 6:
led_data6++;
if(led_data6==10)
{
led_data6=0;
}
break;
case 7:
led_data7++;
if(led_data7==8)
{
led_data7=1;
}
break;
case 8:
led_data8++;
if(led_data8==3)
{
led_data8=0;
}
break;
case 9:
led_data9++;
if(led_data9==10)
{
led_data9=0;
}
break;
case 10:
led_data10++;
if(led_data10==6)
{
led_data10=0;
}
break;
case 11:
led_data11++;
if(led_data11==10)
{
led_data11=0;
}
break;
case 12:
led_data12++;
if(led_data12==6)
{
led_data12=0;
, ; }
break;
case 13:
led_data13++;
if(led_data13==10)
{
led_data13=0;
}
break;
default : break;
}
}
}
if((set_flag=
本文档为【万年历制作】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑,
图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。