Perpetual calendar for single-chip training

Perpetual calendar for single-chip training (with functions of hour, minute, second, date, and week adjustment

What is a perpetual calendar? ? ? ?

The almanac is the oldest solar calendar in ancient Chinese legends. The perpetual calendar is an annual calendar that records the specific dates of the solar and lunar calendars within a certain time range (such as 100 years or more), which is convenient for people in need to query and use. Wannian is just a symbol, indicating a large time span. The perpetual calendar used is an almanac that includes or applies to a certain number of years. The modern perpetual calendar can display multiple sets of calendars such as the Gregorian calendar, the lunar calendar, and the Ganzhi calendar at the same time. It can also include various functional information related to the almanac, such as good and bad taboos, holidays, reminders, etc., which is extremely convenient for people to query and use.

1. Design of liquid crystal multifunctional perpetual calendar

This project takes AT89C51 microcontroller as the core, combined with digital temperature regulator ds18b20, clock chip ds1302 and liquid crystal display lcd1602 to design a perpetual calendar with liquid crystal display. The clock module in the system provides more accurate time data for the whole system; the temperature sensor module can obtain the temperature value of the surrounding environment and when the temperature is higher than a certain value, the horn alarm is realized; the liquid crystal display module is used to display the date (year, month , day), time (hour, minute, second), day of the week, temperature parameter value, and the value of each parameter can also be adjusted by pressing the button (with addition and subtraction functions).

2. Design the main functions

1. Display information of year, month, day (including leap year), hour, minute, second, week (day of week), temperature; 2. It has temperature display function; 3. It has temperature alarm function.
Once
the temperature exceeds 35 degrees Celsius, it will Turn on the horn to realize the alarm;
4. Timing on and off (open from 8:00 am to 22:00 pm, 22:00 pm to 8:00 am the next day to close) function.
5. It has the adjustment function of date (year, month, day) and time (hour, minute, second), week and temperature.
6. It has the function of telling the time on the hour.

1.2. Design principle

1) Single-chip microcomputer selection: The traditional AT89C51 is used as the control core of this system. AT89C51 is a low-voltage high-performance CMOS 8-bit microprocessor with 4K byte flashing programmable erasable read-only memory.
2) Clock chip selection: DS1302 is a low-power real-time clock chip with trickle current charging capability launched by DALLAS Company of the United States. It can time the year, month, day, week, hour, minute, and second, and has various functions such as leap year compensation.
The clock chip selects DS1302 to realize the clock function. The DS1302 chip is a high-performance chip that can automatically count seconds, minutes, hours, months, days, weeks, and years with high precision.
3) Selection of display module: Use a liquid crystal display (LCD1602) to display time, date and week information.
4) Selection of the button module: choose an independent button (button), the button is specifically set to three buttons, and the functions are divided into setting, addition, subtraction, confirmation and modification.

The main circuit diagram is as follows:

insert image description here

The main code is as follows:

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;
}

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      //default

void 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++;
}
}
#endif

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:00
Write1302(0x88,0x01);
Write1302(0x86,0x02);
Write1302(0x8a,0x07);
Write1302(0x84,0x14);
Write1302(0x82,0x03);
Write1302(0x80,0x00);
Write1302(0x8e,0x80); //禁止写入
}

}
#endif

DS18B20.h

#ifndef DS18B20_H_2009_6_28
#define DS18B20_H_2009_6_28

#define uint unsigned int
#define uchar unsigned char

sbit 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); //精确延时 大于 480us
DQ = 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 important

Init_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';
}
#endif

1.6.2 Display screen after power-on After
power-on, the LCD can display the current date, including year, month, day, week, hour, minute, second, and temperature.
insert image description here

1-11 LCD display after power on
1.6.3 Button setting time
Press the setting button to adjust the display time. (plus operation)
insert image description here

Press the first button on the left to turn on the adjustment button. The number of presses and the corresponding relationship are as follows:
1->Second adjustment
2->Minute adjustment 3-
>Hour adjustment 4-
>Week adjustment
5->Day adjustment Calibration
6-> Monthly Calibration
7-> Yearly Calibration
8-> Confirmed Modification Time
 Second Calibration:
insert image description here

Result after tuning:
insert image description here

 Sub-adjustment:
insert image description here

Adjusted results:
insert image description here

 Time adjustment:
insert image description here

After adjustment:
insert image description here
insert image description here

1-12 key setting
 Week modification:
insert image description here

After modifying the week:

insert image description here
insert image description here

 Daily modification:
insert image description here

Modified after:

insert image description here
insert image description here

 Monthly revision:
insert image description here

After modifying the month:

insert image description here
insert image description here

 Year revision:
insert image description here

Good modification year:
insert image description here

insert image description here

1.6.4 When the small light flashes at the specified time, it means that the alarm clock will sound at the specified time (on the hour). (Realize the time from 20:59-21:00)
insert image description here
insert image description here

1-14 Small light flashes (alarm rings)
1.6.5 Successful completion of timing display (turn on from 8:00 in the morning to 22:00 in the evening, turn off from 22:00 in the evening to 8:00 in the next morning)
 7:59 in the morning- 8:00 Realize the jump

insert image description here

insert image description here

 Jump from 21:59 to 22:00 in the evening
insert image description here
insert image description here

1.6.6 DS1302 obtains the temperature and transmits it to the display screen, and sets the temperature to realize an alarm when the temperature exceeds 35 degrees Celsius
insert image description here

When the temperature is >35 degrees Celsius, the horn will sound.

insert image description here

1.4. Problems encountered in debugging and solutions
(1) After adjusting the time and date, the time of the PC is updated when the MCU is powered on. After checking the information, it is the problem of setting the DS1302, and there is a certain error and the error is within 2 Within -3s, as the running time increases, the error will continue to increase.
(2) Sometimes the function is unstable when the button is operated. This is due to the jitter of the button. Later, a delay function can be added to remove the jitter, so that the button can be responded immediately after pressing the button.
(3) When adjusting the date, the date and the week cannot be linked. It still needs to be improved and revised later.

Guess you like

Origin blog.csdn.net/weixin_45790490/article/details/109608252