单片机实训之万年历(具有时分秒,日期,星期调校功能
什么是万年历????
年历是中国古代传说中最古老的一部太阳历。万年历是记录一定时间范围内(比如100年或更多)的具体阳历与阴历的日期的年历,方便有需要的人查询使用。万年只是一种象征,表示时间跨度大。所使用的万年历,即包括若干年或适用于若干年的历书 。现代的万年历能同时显示公历、农历和干支历等多套历法,更能包含黄历相关吉凶宜忌、节假日、提醒等多种功能信息,极为方便人们查询使用。
1. 液晶多功能万年历的设计
该项目以AT89C51单片机为核心,结合数字温度调节器ds18b20、时钟芯片ds1302和液晶显示器lcd1602设计而成的液晶显示的万年历。系统中时钟模块为整个系统提供较为精准的时间数据;温度传感器模块可以获取周围环境的温度值且当温度高于一定的数值时,实现喇叭器报警;液晶显示模块用于显示日期(年,月,日)、时间(时,分,秒)、星期、温度的参数值,也可以通过按键来调整各个参数的数值(具有加、减功能)。
2. 设计主要功能
1.显示年、月、日(含闰年)、时、分、秒、星期(周几)、温度的信息;
2.具有温度显示功能;
3.具有温度报警功能,一旦温度超过35摄氏度,就开启喇叭实现报警;
4.定时开启和关闭(上午8:00-晚上22:00开启,晚上22:00-第二天上午8:00关闭)功能。
5.具有日期(年,月,日)和时间(时,分,秒)、星期、温度的调较功能。
6.具有整点报时功能。
1.2. 设计原理
1)单片机选择:采用传统的AT89C51作为此系统的控制核心,AT89C51是一种带4K字节闪烁可编程可擦除只读存储器的低电压高性能CMOS8位微处理器。
2)时钟芯片选择:DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能。
时钟芯片选择DS1302来实现时钟功能,DS1302芯片是一种高性能芯片,可自动对秒,分,时,月,日,周,年进行计数,而且精度高。
3)显示模块的选择:使用液晶显示屏(LCD1602)显示时间、日期以及星期的信息。
4)按键模块的选择:选择独立式的按钮(button),按键具体设置为三个按键,功能分为设置,加,减,确定修改。
主要电路图如下:

主要代码如下:
shuzishizhong.c
#include<REG51.H>#include<stdio.h>#include<stdlib.h>#include "LCD1602.H"#include "DS1302.H"#include "ds18b20.H"#define uint unsigned int#define uchar unsigned char#define TH 35 //设置温度上限extern unsigned char week_value[2],TempBuffer[5]; //声明外部变量extern int temp_value;char hide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year; //秒,分,时到日,月,年位闪的计数sbit Set = P3^0; //P3.0口控制模式切换键sbit Up = P3^1; //加法按钮sbit Down = P3^2; //减法按钮sbit out = P3^3; //立刻跳出调整模式按钮sbit deng = P1^1; sbit bee=P1^3;sbit key_set_alarm=P3^7;char done,count,temp,flag,up_flag,down_flag;char SD=1;int a,b,c;int b=1;void show_time(); //液晶显示函数声明void close_time(); //液晶屏关闭函数声明/**************************************************************
延时子程序
**************************************************************/void mdelay(uint delay){ uint i;
for(;delay>0;delay--)
{for(i=0;i<62;i++) //1ms延时.
{;}
}}/**************************************************************
用于液晶屏显示关闭
**************************************************************/void close_time(){
LCD_Write(0,0x01);
mdelay(1);}/**************************************************************
用于液晶屏显示开起
**************************************************************///void open_time(){// LCD_SetDisplay(0x04|0x02);
//mdelay(1000);//}/**************************************************************
升序按键
**************************************************************/void Upkey(){ Up=1;if(Up==0){
mdelay(8);
switch(count)
{
case 1:
temp=Read1302(DS1302_SECOND); //读取秒数
temp=temp+1; //秒数加1
up_flag=1; //数据调整后更新标志
if((temp&0x7f)>0x59) //超过59秒,清零
temp=0;
break;
case 2:
temp=Read1302(DS1302_MINUTE); //读取分数
temp=temp+1; //分数加1
up_flag=1;
if(temp>0x59) //超过59分,清零
temp=0;
break;
case 3:
temp=Read1302(DS1302_HOUR); //读取小时数
temp=temp+1; //小时数加1
up_flag=1;
if(temp>0x23) //超过23小时,清零
temp=0;
break;
case 4:
temp=Read1302(DS1302_WEEK); //读取星期数
temp=temp+1; //星期数加1
up_flag=1;
if(temp>0x7) //大于周1-周7清零
temp=1;
break;
case 5:
temp=Read1302(DS1302_DAY); //读取日数
temp=temp+1; //日数加1
up_flag=1;
if(temp>0x31) //大于31天清零
temp=1;
break;
case 6:
temp=Read1302(DS1302_MONTH); //读取月数
temp=temp+1; //月数加1
up_flag=1;
if(temp>0x12) //大于12个月清零
temp=1;
break;
case 7:
temp=Read1302(DS1302_YEAR); //读取年数
temp=temp+1; //年数加1
up_flag=1;
if(temp>0x85) //大于85年清零
temp=0;
break;
default:break;
}
while(Up==0);
}}/**************************************************************
降序按键
**************************************************************/void Downkey(){
Down=1;
if(Down==0){
mdelay(8);
switch(count){
case 1:
temp=Read1302(DS1302_SECOND); //读取秒数
temp=temp-1; //秒数减1
down_flag=1; //数据调整后更新标志
if(temp==0x7f){ //小于0秒,返回59秒
temp=0x59;
}
break;
case 2:
temp=Read1302(DS1302_MINUTE); //读取分数
temp=temp-1; //分数减1
down_flag=1;
if(temp==-1){
temp=0x59;
} //小于0分,返回59分
break;
case 3:
temp=Read1302(DS1302_HOUR); //读取小时数
temp=temp-1; //小时数减1
down_flag=1;
if(temp==-1)
temp=0x23;
break;
case 4:
temp=Read1302(DS1302_WEEK); //读取星期数
temp=temp-1; //星期数减1
down_flag=1;
if(temp==0)
temp=0x07;
break;
case 5:
temp=Read1302(DS1302_DAY); //读取日数
temp=temp-1; //日数减1
down_flag=1;
if(temp==0)
temp=0x31;
break;
case 6:
temp=Read1302(DS1302_MONTH); //读取月数
temp=temp-1; //月数减1
down_flag=1;
if(temp==0)
temp=0x12;
break;
case 7:
temp=Read1302(DS1302_YEAR); //读取年数
temp=temp-1; //年数减1
down_flag=1;
if(temp==-1)
temp=0x85;
break;
default:break;
}
while(Down==0);
}}/**************************************************************
模式选择按键
**************************************************************/void Setkey(){Set=1;if(Set==0){
mdelay(8);
count=count+1; //Setkey按一次,count就加1
done=1; //进入调整模式
while(Set==0);
}}/**************************************************************
跳出调整模式,返回默认显示
**************************************************************/void outkey() { uchar Second;
out=1;
if(out==0)
{
count=0;
hide_sec=0,hide_min=0,hide_hour=0,hide_day=0,hide_week=0,hide_month=0,hide_year=0;
Second=Read1302(DS1302_SECOND);
Write1302(0x8e,0x00); //写入允许
Write1302(0x80,Second&0x7f);
Write1302(0x8E,0x80); //禁止写入
done=0;
while(out==0);
}}/**************************************************************
按键功能执行
**************************************************************/void keydone(){ uchar Second;if(flag==0) //关闭时钟,停止计时{
Write1302(0x8e,0x00); //写入允许
temp=Read1302(0x80);
Write1302(0x80,temp|0x80);
Write1302(0x8e,0x80); //禁止写入
flag=1;}Setkey(); //扫描模式切换按键switch(count){
case 1:do{ //count=1,调整秒
outkey(); //扫描跳出按钮
Upkey(); //扫描加按钮
Downkey(); //扫描减按钮
if(up_flag==1||down_flag==1) //数据更新,重新写入新的数据
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x80,temp|0x80); //写入新的秒数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_sec++; //位闪计数
if(hide_sec>3)
hide_sec=0;
show_time(); //液晶显示数据
}while(count==2);break;
case 2:do{ //count=2,调整分
hide_sec=0;
outkey();
Upkey();
Downkey();
if(temp>0x60)
temp=0;
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x82,temp); //写入新的分数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_min++;
if(hide_min>3)
hide_min=0;
show_time();
}while(count==3);break;
case 3:do{ //count=3,调整小时
hide_min=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x84,temp); //写入新的小时数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_hour++;
if(hide_hour>3)
hide_hour=0;
show_time();
}while(count==4);break;case 4:do{ //count=4,调整星期
hide_hour=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x8a,temp); //写入新的星期数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_week++;
if(hide_week>3)
hide_week=0;
show_time();
}while(count==5);break;
case 5:do{ //count=5,调整日
hide_week=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x86,temp); //写入新的日数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_day++;
if(hide_day>3)
hide_day=0;
show_time();
}while(count==6);break;
case 6:do{ //count=6,调整月
hide_day=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x88,temp); //写入新的月数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_month++;
if(hide_month>3)
hide_month=0;
show_time();
}while(count==7);break;
case 7:do{ //count=7,调整年
hide_month=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x8c,temp); //写入新的年数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_year++;
if(hide_year>3)
hide_year=0;
show_time();
}while(count==8);break;
case 8:
count=0;hide_year=0; //count8, 跳出调整模式,返回默认显示状态
Second=Read1302(DS1302_SECOND);
Write1302(0x8e,0x00); //写入允许
Write1302(0x80,Second&0x7f);
Write1302(0x8E,0x80); //禁止写入
done=0;
break; //count=7,开启中断,标志位置0并退出
default:break;}}/**************************************************************
液晶显示程序
**************************************************************/void show_time() {//while(1)//{
DS1302_GetTime(&CurrentTime); //获取时钟芯片的时间数据
TimeToStr(&CurrentTime); //时间数据转换液晶字符
DateToStr(&CurrentTime); //日期数据转换液晶字符
ReadTemp(); //开启温度采集程序
temp_to_str(); //温度数据转换成液晶字符
GotoXY(12,1); //液晶字符显示位置
Print(TempBuffer); //显示温度
GotoXY(0,1);
Print(CurrentTime.TimeString); //显示时间
GotoXY(0,0);
Print(CurrentTime.DateString); //显示日期
GotoXY(15,0);
Print(week_value); //显示星期
GotoXY(11,0);
Print("Week"); //在液晶上显示 字母 week
mdelay(50); //扫描延时 //} }/**************************************************************
报警检测与取消
**************************************************************/void warming(){
if(temp_value>=TH)
{if(SD==1&&SD!=0)ET0=1;}
else {deng=0;ET0=0;SD=1;}
out=1;if(out==0){ET0=0;SD=0;}}/**************************************************************
主程序
**************************************************************/void main(){
TMOD=0x02; //设置模式为定时器T0的模式2 (8位自动重装计数初值的计数值)
TH0=0x03; //设置计数器初值,靠TH0存储重装的计数值
TL0=0x03;
TR0=1; //启动T0
ET0=0; //关定时器T0中断
EA=1;
P1=0;
flag=1; //时钟停止标志
LCD_Initial(); //液晶初始化
Initial_DS1302(); //时钟芯片初始化
up_flag=0; //调整标志位置零
down_flag=0;
done=0; //进入默认液晶显示while(1){
while(done==1){
keydone(); //进入调整模式
warming();
} while(done==0) {
show_time();
warming();
b=1;
while(b) //b为标志量
{
a=(int)Read1302(DS1302_HOUR); //获取小时数 0x0x
b=(int)Read1302(DS1302_MINUTE); //获取分钟数 0x0x
c=(int)Read1302(DS1302_SECOND); //获取秒钟数 0x0x
warming();
if(b==0x00 && c==0x00){ //实现整点报时
bee=0;
warming();
}else{
bee=1;
warming();
}
if(a<0x08 || a>0x21){
b=1;
warming();
close_time(); //清屏
}else{
b=0;
warming();
}
}
flag=0;
Setkey(); //扫描各功能键
warming();/* while(1){
b=(int)Read1302(DS1302_MINUTE);
c=(int)Read1302(DS1302_SECOND);
if(b==0x00 && c==0x00){
bee=0;
}
}*/
} }warming(); }//}/**************************************************************
定时器中断
**************************************************************/void t0 (void) interrupt 1 using 1 {deng=!deng;}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
LCD1602.h
#ifndef LCD_CHAR_1602#define LCD_CHAR_1602#include <intrins.h>sbit LcdRs = P2^0; //定义端口sbit LcdRw = P2^1;sbit LcdEn = P2^2;sfr DBPort = 0x80; //P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口/********************************************************
内部等待函数
********************************************************/unsigned char LCD_Wait(void){LcdRs=0;LcdRw=1; _nop_();LcdEn=1; _nop_();
LcdEn=0;return DBPort;}/*******************************************************
向LCD写入命令或数据
*******************************************************/#define LCD_COMMAND 0 // Command#define LCD_DATA 1 // Data#define LCD_CLEAR_SCREEN 0x01 // 清屏#define LCD_HOMING 0x02 // 光标返回原点void LCD_Write(bit style, unsigned char input){LcdEn=0;LcdRs=style;LcdRw=0; _nop_();DBPort=input; _nop_();//注意顺序LcdEn=1; _nop_();//注意顺序LcdEn=0; _nop_();LCD_Wait();}/*****************************************************
设置显示模式
*****************************************************/#define LCD_SHOW 0x04 //显示开#define LCD_HIDE 0x00 //显示关 #define LCD_CURSOR 0x02 //显示光标#define LCD_NO_CURSOR 0x00 //无光标 #define LCD_FLASH 0x01 //光标闪动#define LCD_NO_FLASH 0x00 //光标不闪动void LCD_SetDisplay(unsigned char DisplayMode){LCD_Write(LCD_COMMAND, 0x08|DisplayMode);}/***************************************************
设置输入模式
***************************************************/#define LCD_AC_UP 0x02#define LCD_AC_DOWN 0x00 // default#define LCD_MOVE 0x01 // 画面可平移#define LCD_NO_MOVE 0x00 //defaultvoid LCD_SetInput(unsigned char InputMode){LCD_Write(LCD_COMMAND, 0x04|InputMode);}/***************************************************
初始化LCD
***************************************************/void LCD_Initial(){LcdEn=0;LCD_Write(LCD_COMMAND,0x38); //8位数据端口,2行显示,5*7点阵LCD_Write(LCD_COMMAND,0x38);LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR); //开启显示, 无光标LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE); //AC递增, 画面不动}/***********************************************
液晶字符输入的位置
************************************************/void GotoXY(unsigned char x, unsigned char y){if(y==0)LCD_Write(LCD_COMMAND,0x80|x);if(y==1)LCD_Write(LCD_COMMAND,0x80|(x-0x40));}/************************************************
将字符输出到液晶显示
************************************************/void Print(unsigned char *str){while(*str!='\0'){LCD_Write(LCD_DATA,*str);str++;}}#endif123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
DS1302.h
#ifndef _REAL_TIMER_DS1302_2009_6_28_#define _REAL_TIMER_DS1302_2009_6_28_sbit DS1302_CLK = P1^6; //实时时钟时钟线引脚 sbit DS1302_IO = P1^7; //实时时钟数据线引脚 sbit DS1302_RST = P1^5; //实时时钟复位线引脚sbit ACC0 = ACC^0;sbit ACC7 = ACC^7;unsigned char week_value[2];char hide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year; //秒,分,时到日,月,年位闪的计数typedef struct __SYSTEMTIME__{unsigned char Second;unsigned char Minute;unsigned char Hour;unsigned char Week;unsigned char Day;unsigned char Month;unsigned char Year;unsigned char DateString[11];unsigned char TimeString[9];}SYSTEMTIME; //定义的时间类型SYSTEMTIME CurrentTime;#define AM(X) X#define PM(X) (X+12) // 转成24小时制#define DS1302_SECOND 0x80 //时钟芯片的寄存器位置,存放时间#define DS1302_MINUTE 0x82#define DS1302_HOUR 0x84 #define DS1302_WEEK 0x8A#define DS1302_DAY 0x86#define DS1302_MONTH 0x88#define DS1302_YEAR 0x8C void DS1302InputByte(unsigned char d) //实时时钟写入一字节(内部函数){
unsigned char i;
ACC = d;
for(i=8; i>0; i--)
{
DS1302_IO = ACC0; //相当于汇编中的 RRC
DS1302_CLK = 1;
DS1302_CLK = 0;
ACC = ACC >> 1;
} }unsigned char DS1302OutputByte(void) //实时时钟读取一字节(内部函数){
unsigned char i;
for(i=8; i>0; i--)
{
ACC = ACC >>1; //相当于汇编中的 RRC
ACC7 = DS1302_IO;
DS1302_CLK = 1;
DS1302_CLK = 0;
}
return(ACC); }void Write1302(unsigned char ucAddr, unsigned char ucDa) //ucAddr: DS1302地址, ucData: 要写的数据{
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr); // 地址,命令
DS1302InputByte(ucDa); // 写1Byte数据
DS1302_CLK = 1;
DS1302_RST = 0;} unsigned char Read1302(unsigned char ucAddr) //读取DS1302某地址的数据{
unsigned char ucData;
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr|0x01); // 地址,命令
ucData = DS1302OutputByte(); // 读1Byte数据
DS1302_CLK = 1;
DS1302_RST = 0;
return(ucData);}void DS1302_GetTime(SYSTEMTIME *Time) //获取时钟芯片的时钟数据到自定义的结构型数组{unsigned char ReadValue;ReadValue = Read1302(DS1302_SECOND);Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_MINUTE);Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_HOUR);Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_DAY);Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_WEEK);Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_MONTH);Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);ReadValue = Read1302(DS1302_YEAR);Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);}void DateToStr(SYSTEMTIME *Time) //将时间年,月,日,星期数据转换成液晶显示字符串,放到数组里DateString[]{ if(hide_year<2) //这里的if,else语句都是判断位闪烁,<2显示数据,>2就不显示,输出字符串为 2013-01-02
{
Time->DateString[0] = '2';
Time->DateString[1] = '0';
Time->DateString[2] = Time->Year/10 + '0';
Time->DateString[3] = Time->Year%10 + '0';}
else
{
Time->DateString[0] = ' ';
Time->DateString[1] = ' ';
Time->DateString[2] = ' ';
Time->DateString[3] = ' ';}Time->DateString[4] = '-';if(hide_month<2){
Time->DateString[5] = Time->Month/10 + '0';
Time->DateString[6] = Time->Month%10 + '0';}
else
{
Time->DateString[5] = ' ';
Time->DateString[6] = ' ';
}Time->DateString[7] = '-';if(hide_day<2){
Time->DateString[8] = Time->Day/10 + '0';
Time->DateString[9] = Time->Day%10 + '0';}
else
{
Time->DateString[8] = ' ';
Time->DateString[9] = ' ';
}/* if(hide_week<2)
{
week_value[0] = Time->Week%10+'0'; //星期的数据另外放到 week_value[]数组里,跟年,月,日的分开存放,因为等一下要在最后显示
}
else
{
week_value[0] = ' ';
}
week_value[1] = '\0';
Time->DateString[10] = '\0'; //字符串末尾加 '\0' ,判断结束字符 */}void TimeToStr(SYSTEMTIME *Time) //将时,分,秒数据转换成液晶显示字符放到数组 TimeString[];{ if(hide_hour<2)
{
Time->TimeString[0] = Time->Hour/10 + '0';
Time->TimeString[1] = Time->Hour%10 + '0';}
else
{
Time->TimeString[0] = ' ';
Time->TimeString[1] = ' ';}Time->TimeString[2] = ':';
if(hide_min<2){
Time->TimeString[3] = Time->Minute/10 + '0';
Time->TimeString[4] = Time->Minute%10 + '0';}
else
{
Time->TimeString[3] = ' ';
Time->TimeString[4] = ' ';
}Time->TimeString[5] = ':';
if(hide_sec<2)
{
Time->TimeString[6] = Time->Second/10 + '0';
Time->TimeString[7] = Time->Second%10 + '0';
}
else
{
Time->TimeString[6] = ' ';
Time->TimeString[7] = ' ';
}Time->DateString[8] = '\0';}void Initial_DS1302(void) //时钟芯片初始化{ unsigned char Second=Read1302(DS1302_SECOND);if(Second&0x80) //判断时钟芯片是否关闭
{Write1302(0x8e,0x00); //写入允许Write1302(0x8c,0x13); //以下写入初始化时间 日期:13-01-02.星期: 3. 时间: 14:03:00Write1302(0x88,0x01);Write1302(0x86,0x02);Write1302(0x8a,0x07);Write1302(0x84,0x14);Write1302(0x82,0x03);Write1302(0x80,0x00);Write1302(0x8e,0x80); //禁止写入}}#endif123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
DS18B20.h
#ifndef DS18B20_H_2009_6_28#define DS18B20_H_2009_6_28#define uint unsigned int#define uchar unsigned charsbit DQ = P1^0; //温度传送数据IO口int temp_value; //温度值unsigned char TempBuffer[5]; // 存放温度的各个位的值/***********ds18b20延迟子函数(晶振12MHz )*******/ void delay_18B20(unsigned int i){while(i--);}/**********ds18b20初始化函数**********************/void Init_DS18B20(void) {unsigned char x=0;DQ = 1; //DQ复位delay_18B20(8); //稍做延时DQ = 0; //单片机将DQ拉低delay_18B20(80); //精确延时 大于 480usDQ = 1; //拉高总线delay_18B20(14);x=DQ; //稍做延时后 如果x=0则初始化成功 x=1则初始化失败delay_18B20(20);}/***********ds18b20读一个字节**************/ unsigned char ReadOneChar(void){uchar i=0;uchar dat = 0;for (i=8;i>0;i--){
DQ = 0; // 给脉冲信号
dat>>=1;
DQ = 1; // 给脉冲信号
if(DQ)
dat|=0x80;
delay_18B20(4);}
return(dat);}/*************ds18b20写一个字节****************/ void WriteOneChar(uchar dat){
unsigned char i=0;
for (i=8; i>0; i--)
{
DQ = 0;
DQ = dat&0x01;
delay_18B20(5);
DQ = 1;
dat>>=1;
}}/**************读取ds18b20当前温度************/void ReadTemp(void){unsigned char a=0;unsigned char b=0;unsigned char t=0;Init_DS18B20();WriteOneChar(0xCC); // 跳过读序号列号的操作WriteOneChar(0x44); // 启动温度转换delay_18B20(100); // this message is wery importantInit_DS18B20();WriteOneChar(0xCC); //跳过读序号列号的操作WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度delay_18B20(100);a=ReadOneChar(); //读取温度值低位b=ReadOneChar(); //读取温度值高位temp_value=b<<4;temp_value+=(a&0xf0)>>4; }void temp_to_str() //温度数据转换成液晶字符显示{
TempBuffer[0]=temp_value/10+'0'; //十位
TempBuffer[1]=temp_value%10+'0'; //个位
TempBuffer[2]=0xdf; //温度符号
TempBuffer[3]='C';
TempBuffer[4]='\0';}#endif123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
1.6.2 上电后显示屏
通电后的LCD可以显示出现在的日期,包括年月日星期还有时分秒,另外还有温度的显示。

1-11 通电后LCD显示屏
1.6.3 按键设置时间
按下设置按键时可对显示屏的时间进行调整。(加操作)

按下左边第一个键,开启调较按钮,按下次数与对应关系如下:
1->秒调校
2->分调较
3->时调校
4->星期调校
5->日调校
6->月调校
7->年调校
8->确定的修改时间
秒调校:

调教后的结果:

分调节:

调校后的结果:

时调校:

调较后:
http://ask.baikezh.com/hefei/

1-12 按键设置
星期修改:

修改星期后:
http://ask.baikezh.com/chengdou/

日修改:
http://dxb.myzx.cn

修改日后:
http://dxb.myzx.cn/oldage/

月修改:

修改月份后:
http://zzdxb.baikezh.com/

年修改:
http://ask.baikezh.com/hunan/

修改年份好:


1.6.4 小灯到指定时间闪烁,表示闹钟在指定时间(整点)响起。(从20:59——21:00实现报时)

1-14 小灯闪烁(闹铃响起)
1.6.5 顺利完成定时显示(早上8:00-晚上22:00开启,晚上22:00-第二天早上8:00关闭)
早上7:59-8:00实现跳转
http://dxb.myzx.cn/jilin/


晚上21:59-22:00实现跳转
http://ask.baikezh.com/question/

1.6.6 DS1302获取温度传入显示屏,并设置温度当温度超过35摄氏度时实现报警

温度>35摄氏度时,喇叭响。

1.4. 调试中遇到的问题和解决方法
http://zzdxb.baikezh.com/
(1)在调节时间和日期之后,单片机上电更新的是PC的时间,后来查资料,是设置DS1302的问题,且存在一定的误差且误差在2-3s内,随着运行的时间不断增加,误差会不断地加大。
(2)按键操作时有时会出现功能不稳定,这是由于按键存在抖动,后来加个延时函数就可以去抖动,实现按键按下后马上得到相应。
(3)调整日期时,使得日期与星期无法联动。后期仍需要改进和修改。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/30239065/viewspace-2733719/
,如需转载,请注明出处,否则将追究法律责任。