Multifunctional Electronic Perpetual Calendar Based on AT89S52 Single Chip Microcomputer

1. Project introduction (design content)

The hardware structure and software and hardware design method of the multifunctional electronic perpetual calendar based on AT89S52 microcontroller. This design consists of four modules: data display module, temperature acquisition module, time processing module and adjustment setting module. The system uses AT89S52 single-chip microcomputer as the controller, and uses the serial clock calendar chip DS1302 to record the calendar and time. It can time the year, month, day, hour, minute and second, and also has many functions such as leap year compensation. The DS18B20 chip is used for temperature acquisition, the perpetual calendar adopts intuitive digital display, and the data display adopts 1602 liquid crystal display module, which can simultaneously display year, month, day, Sunday, hour, minute and second on LCD1602, and also has functions such as time calibration.

2. The overall design of the project

The function of the system often determines the structure adopted by the system. After considering the cost, performance, power consumption and other aspects, it is decided to use three 8-bit 74LS164 serial interfaces to connect external LED displays. RESPACK-8 supplies power to the microcontroller AT89S52. The time chip DS1302 is connected MCU AT89S52. Thereby realizing the function of electronic perpetual calendar.
According to the requirements of the system design, it is preliminarily determined that the system consists of six modules: power supply module, clock module, display module, keyboard interface module, temperature measurement module and alarm clock module. The block diagram of the circuit system is shown in Figure 1.
insert image description here
Figure 1 Hardware circuit block diagram

insert image description here

Figure 2 Main program flow chart

3. Design ideas and implementation steps (including hardware design and software design)

3.1 Proteus simulation diagram

There are many ways to make a single-chip electronic perpetual calendar, and there are many kinds of devices and technologies to choose from. Therefore, the overall design of the system should fully consider the environment in which the system is used under the premise of satisfying the system functions. The selected structure should be simple to use and easy to implement. power consumption and low cost.
The function of the system often determines the structure adopted by the system. After considering the cost, performance, power consumption and other aspects, it is decided to use three 8-bit 74LS164 serial interfaces to connect external LED displays. RESPACK-8 supplies power to the microcontroller AT89S52. The time chip DS1302 is connected MCU AT89S52. Thereby realizing the function of electronic perpetual calendar.
According to the requirements of the system design, it is preliminarily determined that the system consists of six modules: power supply module, clock module, display module, keyboard interface module, temperature measurement module and alarm clock module. The block diagram of the circuit system is shown in Figure 1.
insert image description here

				图3 硬件电路框图 

3.2 DS1302 read and write program design

The time reading of this system mainly comes from the operation of the single-chip microcomputer on the DS1302. On the hardware, the connection between the clock chip DS1302 and the single-chip microcomputer requires three lines, namely SCLK (7), I/O (6), and RST (5). The specific connection diagram See system hardware design schematic diagram. The read and write program design is as follows:
Function name: RTInputByte()
Function: Write a byte by real-time clock
Description: Write 1Byte data to DS1302 (internal function)
Entry parameter: d written data
Return value: None

void RTInputByte(uchar d) 
{
    
     
    uchar i;
    ACC = d;
    for(i=8; i>0; i--)
    {
    
    
        T_IO = ACC0;           /*相当于汇编中的 RRC */
        T_CLK = 1;
        T_CLK = 0;
        ACC = ACC >> 1; 
    } 

Function name: RTOutputByte()
Function: Read a byte from the real-time clock
Description: Read 1Byte data from DS1302 (internal function)
Entry parameters: None
Return value: ACC

uchar RTOutputByte(void) 
{
    
     
    uchar i;
    for(i=8; i>0; i--)
    {
    
    
        ACC = ACC >>1;         /*相当于汇编中的 RRC */
        ACC7 = T_IO;
        T_CLK = 1;
        T_CLK = 0;
    } 
    return(ACC); 
}

Function name: W1302()
Function: Write data to DS1302
Description: Write address first, then write command/data (internal function)
call: RTInputByte(), RTOutputByte()
entry parameters: ucAddr: DS1302 address, ucData: to write Data
return value: none

void W1302(uchar ucAddr, uchar ucDa)
{
    
    
    T_RST = 0;
    T_CLK = 0;
    T_RST = 1;
    RTInputByte(ucAddr);       /* 地址,命令 */
    RTInputByte(ucDa);       /* 写1Byte数据*/
    T_CLK = 1;
    T_RST = 0;
}

Function name: R1302()
Function: Read the data of a certain address of DS1302
Description: Write the address first, then read the command/data (internal function)
Call: RTInputByte(), RTOutputByte()
Entry parameters: ucAddr: DS1302 address

Return value: ucData: read data

uchar R1302(uchar ucAddr)
{
    
    
    uchar ucData;
    T_RST = 0;
    T_CLK = 0;
    T_RST = 1;
    RTInputByte(ucAddr);             /* 地址,命令 */
    ucData = RTOutputByte();         /* 读1Byte数据 */
    T_CLK = 1;
    T_RST = 0;
    return(ucData);
}

When the DS1302 exchanges data with the microprocessor, the microprocessor first sends a command byte to the circuit, and the MSB (D7) of the command byte must be logic 1. If D7=0, writing to the DS1302 is prohibited, that is, write protection; D6=0, specifies the clock data, D6=1, specifies the RAM data; D5~D1 specifies the specific register for input or output; the lowest bit LSB (D0) is logic 0, specifies the write operation (input), D0=1, specifies the read operation(output).

3.3 Complete code

#include<reg52.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
char a,miao,shi,fen,ri,yue,nian,keynum;
int temp;//,year1,month1,day1;

#define h1 0x80 //LCD第一行的初始化位置
#define h2 0x80+0x40 //LCD第二行初始化位置

//定义1602相关管脚
sbit rs=P1^2;
sbit en=P1^0;
sbit rw=P1^1;

//DS1302芯片的管脚定义
sbit DSIO=P1^5;
sbit SCLK=P1^4;
sbit RST=P1^6;

sbit ACC0=ACC^0;//设置累加器
sbit ACC7=ACC^7;

//按键
sbit key1=P3^2;
sbit key2=P3^3;
sbit key3=P3^4;

void delay2(uint s)//延时,用于温度程序部分
{
    
    
	while(s--);//区分i,用s表示
}

void delay(uint z)//延时函数
{
    
    
	uint x,y;
	for(x=z;x>0;x--)
	for(y=110;y>0;y--);
}
void writecom(uchar com)//写入指令函数
{
    
    	
	rs=0;
	rw=0;
	P0=com;
	delay2(1);
	en=1;
	delay2(1);
	en=0;
}
void writedata(uchar dat)//写入数据函数
{
    
    
	rs=1;
	rw=0; 
	P0=dat;
	delay2(1);
	en=1;
	delay2(1);
	en=0;
}
void print(uchar a3,uchar *str)//写字符串函数
{
    
    
	writecom(a3|0x80);
	while(*str!='\0')
	{
    
    
		//delay(100);
		writedata(*str++);
	}
	*str=0;
}

void lcdinit()
{
    
    
	writecom(0x38);//设置为两行显示,8位显示
	writecom(0x0c);//开显示,不显示光标
	writecom(0x06);//光标右移
	writecom(0x01);//清屏		
}

void write_1302(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_();
}
uchar read_1302(uchar addr )//从1302读数据函数,指定读取数据来源地址
{
    
    
	uchar n,dat,dat1;
	RST = 0;
	_nop_();

	SCLK = 0;//先将SCLK置低电平。
	_nop_();
	RST = 1;
	_nop_();

	for(n=0; n<8; n++)//开始传送八位地址命令
	{
    
    
		DSIO = addr & 0x01;
		addr >>= 1;
		SCLK = 1;
		_nop_();
		SCLK = 0;
		_nop_();
	}
	_nop_();
	for(n=0; n<8; n++)//读取8位数据
	{
    
    
		dat1 = DSIO;
		dat = (dat>>1) | (dat1<<7);
		SCLK = 1;
		_nop_();
		SCLK = 0;
		_nop_();
	}

	RST = 0;
	_nop_();	
	SCLK = 1;
	_nop_();
	DSIO = 0;
	_nop_();
	DSIO = 1;
	_nop_();
	return dat; 
}

uchar turnBCD(uchar bcd)//BCD码转换为十进制函数
{
    
    
	return((bcd>>4)*10+(bcd&0x0F));
}
void ds1302_init()//1302时钟芯片初始化函数
{
    
    
	RST=0;
	SCLK=0;
	write_1302(0x8e,0x00);//允许写
	write_1302(0x8e,0x80);//打开保护
}

//时分秒显示函数
void writetime(uchar add,uchar dat)//写入时分秒
{
    
    
	uchar gw,sw;
	gw=dat%10;//取得个位数
	sw=dat/10;//取得十位数
	writecom(h2+add);//第二行显示
	writedata(0x30+sw);//显示该数字
	writedata(0x30+gw);
}
//年月日显示函数
void writeday(uchar add,uchar dat)//写入年月日函数
{
    
    
	uchar gw,sw;
	gw=dat%10;//取得个位数字
	sw=dat/10;//取得十位数字
	writecom(h1+add);//在第一行显示
	writedata(0x30+sw);
	writedata(0x30+gw);//显示
}
//按键扫描函数
void keyscan()
{
    
    
	if(key1==0)
	{
    
    
		delay(5);
		if(key1==0)
		{
    
    
			while(!key1);
			keynum++;
			if(keynum>=8)
			keynum=1;
			switch(keynum)
			{
    
    
			case 1:TR0=0;
				   writecom(h2+0x0b);//秒的位置
				   writecom(0x0f);//设置为光标闪烁
				   temp=(miao)/10*16+(miao)%10;//秒化为bcd码
				   write_1302(0x8e,0x00);
				   write_1302(0x80,0x80|temp);//秒数据写入
				   write_1302(0x8e,0x80);
				   break;
			case 2:writecom(h2+8);
				   break;
			case 3:writecom(h2+5);
				   break;
			case 4:writecom(h1+0x0c);
				   break;
			case 5:writecom(h1+0x09);
				  break;
			case 6:writecom(h1+0x06);
				  break;
			case 7:writecom(0x0c);
				  TR0=1;//重新打开定时器
				  temp=(miao)/10*16+(miao)%10;
				  write_1302(0x8e,0x00);
				  write_1302(0x80,0x00|temp);//写入秒
				  write_1302(0x8e,0x80);
				  break;
			}
		}
	}
	if(keynum!=0)//当设置键按下时才能操作
	{
    
    
		if(key2==0)
		{
    
    
			delay(5);
			if(key2==0)
			{
    
    
				while(!key2);
				switch(keynum)
				{
    
    
					case 1:miao++;//
						   if(miao>=60)	miao=0;
						   writetime(0x0a,miao);
						   temp=(miao)/10*16+(miao)%10;//转换为bcd码
						   write_1302(0x8e,0x00);//允许写
						   write_1302(0x80,temp);// 写入秒
						   write_1302(0x8e,0x80);//打开保护
						   writecom(h2+0x0b);//液晶模式为写入后自动右移,在此返回原来位置
						   break;
					case 2:fen++;
						   if(fen>=60) fen=0;
						   writetime(0x07,fen);
						   temp=(fen)/10*16+(fen)%10;
						   write_1302(0x8e,0x00);
						   write_1302(0x82,temp);
						   write_1302(0x8e,0x80);
						   writecom(h2+0x08);
						   break;
					case 3:shi++;
						   if(shi>=24) shi=0;
						   writetime(0x04,shi);
						   temp=(shi)/10*16+(shi)%10;
						   write_1302(0x8e,0x00);
						   write_1302(0x84,temp);
						   write_1302(0x8e,0x80);
						   writecom(h2+0x05);
						   break;
					case 4:ri++;
						   if(ri>=32) ri=1;
						   writeday(0x0b,ri);
						   temp=(ri)/10*16+(ri)%10;
						   write_1302(0x8e,0x00);
						   write_1302(0x86,temp);
						   write_1302(0x8e,0x80);
						   writecom(h1+0x0c);
						   break;
					case 5:yue++;
						   if(yue>=13) yue=1;
						   writeday(0x08,yue);
						   temp=(yue)/10*16+(yue)%10;
						   write_1302(0x8e,0x00);
						   write_1302(0x88,temp);
						   write_1302(0x8e,0x80);
						   writecom(h1+0x09);
						   break;
					case 6:nian++;
						   if(nian>=100) nian=0;
						   writeday(0x05,nian);
						   temp=(int)((nian)/10*16+(nian)%10);
						   write_1302(0x8e,0x00);
						   write_1302(0x8c,temp);
						   write_1302(0x8e,0x80);
						   writecom(h1+0x06);
						   break;
				}		   

			}
		}
		//以下是减的函数
		if(key3==0)
		{
    
    
			delay(5);//消除抖动
			if(key3==0)
			{
    
    
				while(!key3);
				switch(keynum)
				{
    
    
					case 1:miao--;
						   if(miao<0) miao=59;//减到-1返回59
						   writetime(0x0a,miao);//在十位数写入 
						   temp=(miao)/10*16+(miao)%10;//转换为bcd码
						   write_1302(0x8e,0x00);//允许写
						   write_1302(0x80,temp);//写入秒
						   write_1302(0x8e,0x80);//打开保护
						   writecom(h2+0x0b);//返回个位位置
						   break;
					case 2:fen--;
						   if(fen<0) fen=59;
						   writetime(0x07,fen);
						   temp=(fen)/10*16+(fen)%10;
						   write_1302(0x8e,0x00);
						   write_1302(0x82,temp);
						   write_1302(0x8e,0x80);
						   writecom(h2+8);
						   break;
				    case 3:shi--;
						   if(shi<0) shi=23;
						   writetime(0x04,shi);
						   temp=(shi)/10*16+(shi)%10;
						   write_1302(0x8e,0x00);
						   write_1302(0x84,temp);
						   write_1302(0x8e,0x80);
						   writecom(h2+0x05);
						   break;
					case 4:ri--;
						   if(ri<1) ri=31;
						   writeday(0x0b,ri);
						   temp=(ri)/10*16+(ri)%10;
						   write_1302(0x8e,0x00);
						   write_1302(0x86,temp);
						   write_1302(0x8e,0x80);
						   writecom(h1+0x0c);
						   break;
					case 5:yue--;
						   if(yue<1) yue=12;
						   writeday(0x08,yue);
						   temp=(yue)/10*16+(yue)%10;
						   write_1302(0x8e,0x00);
						   write_1302(0x88,temp);
						   write_1302(0x8e,0x80);
						   writecom(h1+0x09);
						   break;
					case 6:nian--;
						   if(nian<0) nian=99;
						   writeday(0x05,nian);
						   temp=(int)((nian)/10*16+(nian)%10);
						   write_1302(0x8e,0x00);
						   write_1302(0x8c,temp);
						   write_1302(0x8e,0x80);
						   writecom(h1+0x06);
						   break;
				}
			}
		}
	}
}

void init()
{
    
    
	TMOD=0x01;
	TH0=(65536-60000)/256;//10毫秒
	TL0=(65536-60000)%256;
	EA=1;
	ET0=1;//允许T0中断
	TR0=1;//启动中断
}


void main()
{
    
    
	lcdinit();
	ds1302_init();
	init();//定时器初始化函数
	while(1)
	{
    
    
		keyscan();
	}
}
void timer0() interrupt 1
{
    
    
	TH0=(65536-60000)/256;
	TL0=(65536-60000)%256;
//	TR0=0;
	//读取数据
	miao=turnBCD(read_1302(0x81));
	fen=turnBCD(read_1302(0x83));
	shi=turnBCD(read_1302(0x85));
	ri=turnBCD(read_1302(0x87));
	yue=turnBCD(read_1302(0x89));
	nian=turnBCD(read_1302(0x8d));
	//显示数据
									
		print(0x80+3,"20");
		print(0x80+7,"/");
		print(0x80+10,"/");

		writeday(0x0b,ri);//显示日
		writeday(0x08,yue);//显示月
		writeday(0x05,nian);//显示年
		print(0x40+6,":");
		print(0x40+9,":");
		writetime(0x0a,miao);//显示出秒
		writetime(0x07,fen);//显示出分
		writetime(0x04,shi);//显示出时,第二行第一个开始
}

4. Running results or test results

①次电路主要是检测格其引脚电压是否正常,晶振和电源是否接好,检测硬件电路是否有短路、断路、虚焊等,以确保设计的可靠性和电器元件的性能。而电路中的电源电路、晶体振荡电路、按键接口电路及复位电路、闹钟电路等都是采用基础的电路设计,除了基础电路硬件调试外我们还可以通过软件来测试硬件,如通过下载口写入其它一个比较简单的程序,以便测试。
②首先由USB电源插口接入5V的直流电压供给系统使用。在这里接上一个发光二级管作为指示,单输入电压正常时,二极管亮,LCD同时显示正常。系统在正常工作时,LCD液晶上第一行显示时分秒和温度,第二行显示年月日和星期,如果想要对时间进行调整,可以通过调整设置模块来实现。当按下设置键P3.0键时可调节主页面的时分秒、年月日的调节,P3.1为调整加按键,P3.2为调整减按键,P3.3按下时可进入另一种模式。第二种模式可显示闰年,第三种模式可设置闹钟时间。如果想要退出该模式就在按一下P3.3即可。

③During the hardware debugging process, when the power was turned on, we found that the LCD did not work, the backlight was on but no data came out. But the power indicator light is on, indicating that the power input is normal. When we use the voltages in the multimeter circuit, we find that the voltages of the pins of the single-chip microcomputer are also normal, and the pins of the display are also normal. With the help of classmates and teachers, I found that the program was wrong, and after changing it, I connected the power supply again, and the circuit was normal.
insert image description here

insert image description here

5. Problems encountered and solutions

The phenomenon of electronic digital perpetual calendar crashing:
this fault is mostly caused by voltage instability and other interference. First replace the memory battery, which can eliminate the fault in most cases; if it still does not work, unplug the power supply and the motherboard connection, and plug it in again. Some crashes can return to normal; if it still does not work, you can use tweezers to short-circuit all the filter capacitors on the motherboard without power on, power on to see if it works normally, and finally check the crystal oscillator.

Time inaccuracy occurs:
5V voltage is low, the memory battery is undervoltage, and the performance of the crystal oscillator is poor. Repair the power supply to make it return to normal, replace the battery, and replace the crystal oscillator.
  
Wrong power-on time and date:
This is a long-term failure. It is likely that the round electronics that come with the circuit board are out of power. If it is not used for a long time, it may exhaust its own power, and in that case it will lose its memory. Function.

6. Summary

In the whole design process, the minimum system of AT89S52 MCU, DS1302 interface circuit, DS18B20 interface circuit, alarm clock and LCD display were mainly designed in terms of hardware; in terms of software, the data reading program of Gregorian calendar and conversion of solar calendar to lunar calendar were mainly designed with the help of information from various channels. program, temperature acquisition program, alarm program and LCD display program; system debugging is mainly realized through an AT89S52 development board, and then with the help of Keil, STC and a few peripheral circuits built by yourself; in this process, step by step debugging It shows the date and time of the Gregorian calendar, as well as the real-time temperature, but the centralized debugging did not achieve the desired effect. The perpetual calendar has many advantages such as intuitive reading and display, various functions, simple circuit, low cost, etc., conforms to the development trend of electronic instruments and meters, and has broad market prospects.
In the whole design process, I learned a lot of knowledge that I didn't learn. It is necessary to have a good idea for the design and layout of the circuit, so that the circuit board looks beautiful and generous. In programming, due to unclear thinking, I encountered a lot of problems at the beginning. After calming down and thinking, I sorted out the thinking, but it was handy. In this design, we know that we must have a normal heart in doing things, and don't think about taking shortcuts, one step at a time. It also cultivates our patience, and we must be patient in everything we do. I have learned many things in this design, this is the most important

7. Source code acquisition

perpetual calendar

Guess you like

Origin blog.csdn.net/qq_53869058/article/details/131310322