51 MCU--DS1302 Clock

DS1302

DS1302 is a product launched by American DALLAS companyReal-time clock circuit chip. It has the characteristics of high performance and low power consumption, and can communicate with CPU synchronously through SPI three-wire interface. DS1302 can provide time information such as seconds, minutes, hours, days, weeks, months and years, and can automatically adjust the date, and also has a compensation function in leap years. It operates over a wide range of voltages and can be2.5V to 5.5Vused between.
DS1302 can be used to make electronic clocks and other applications. It has a built-in real-time clock/calendar and 31 bytes of static RAM. Connected with a microcontroller or other controller via a simple serial interface, time data can be read and set, and some additional information can be stored.

Compared with the timing of timers, DS1302 is a timing clock on the hardware. As for timers, they need to be processed by software programs before they can time clocks. Therefore, DS1302 can realize clocks only through simple program design. Function;

Pin definition and application circuit

insert image description here
This is the DS1302 chip on the 51 microcontroller;
insert image description here

The upper left picture shows two different packaging techniques. DIP packaging is also called dual-in-line packaging technology, which is the simplest packaging method; SOP packaging is a form of component packaging. Generally, there are many packaging materials: plastic, ceramics , glass, metal, etc.; plastic packaging is widely used now; it is mainly used in various integrated circuits.

On our STC89C52 single-chip microcomputer,
it uses the SOP packaging method; it has 8 pins VCC as the power supply on the single-chip microcomputer, of which VCC1 is the backup battery, that is, when the main power supply is powered off, it is powered by the backup battery, but it should be noted that ,existThere is no backup battery on this microcontroller;And VCC2 is the main power supply, which cannot be reversed with the backup battery; GND is grounded; X1 and X2 are connected to a 32.768kHz crystal oscillator, which is the same principle as the timer, and is timed by the vibration frequency of the crystal oscillator; the cylinder in the figure below It is the crystal oscillator component on the single-chip microcomputer; then the CE (core enable) chip is enabled, and the chip can control the component through this route; IO is the data input and output port, used for data transmission; SCLK is the serial clock, usually used for synchronization The clock signal for data transmission controls the transmission rate and timing of data.
insert image description here
Next, look at the picture on the right; the CPU controls the DS1302 clock through the three pins CE, I\O, and SCLK; the DS1302 is connected to the power supply and battery, and then grounded; then connected to the crystal interface.
insert image description here
This is the schematic diagram on the 51 microcontroller.

Internal Structure Diagram

insert image description here
For the interior, except for power control, it can generally be simplified to 4 modules:

  1. Clock module: mainly responsible for providing accurate clock signals. It is driven by a 32.768kHz crystal oscillator that generates the system clock signal to keep time counting accurate.
  2. RAM module: 31 bytes of RAM are integrated inside DS1302 forStore time and date information, control registers, and user-defined datawait.
  3. Control logic module : This module receives instructions from the host, and performs clock and RAM operations according to the instructions.read and write operations. It also includes functions such as clock enable control, write protection control, and timer control.
  4. Communication interface: DS1302 provides a serial interface to communicate with the host, generally a 3-wire interface (I\O, SCLK, CE), through which data transmission and control are performed with the host.

register definition

insert image description here
This is the most important register to control the clock; according to the above block diagram, for DS1302, it needs to use read and write operations, which are divided into two parts to complete; in simple terms, **we write to the DS1302 clock through the program Enter the information, then store the information in RAM, and then take it out of RAM when it is read; **So we will see that there are two bits READ and WRITE in the register; the first line
iscontrol seconds, the CH in bit 7 is the clock pause flag. When it is 1, the clock oscillator stops and the clock stops running. When it is 0, the clock starts running; the second line
controlsminute;
The third line controls theHour, can be 12-hour or 24-hour format, high level is 12-hour mode, and when bit 5 is 1, it means PM; low level is 24 hours; the order of control
isday, month, week, year;
Last second rowWrite protection (WP: write protect), when the corresponding read-write address is set to 0x00, the write-in protection is turned on;
the last line is related to the backup battery, since there is no single-chip microcomputer, no specific introduction is given;

The figure below is the address or command byte:
through the corresponding address, find the corresponding year, month, day, hour, minute and second;
when the low bit is 0, it is writing, and when it is 1, it is reading;

timing definition

insert image description here
These are the three pin interfaces connecting the CPU and the DS1302 clock. For us, the program is to realize the link with the DS1302 clock through these three interfaces; here, the registers are not bit-addressable; first look at the written part
:
The I\O port is for data transmission, there are two bytes here, the first is the byte of the address, and the second is the byte corresponding to the data; when we want to transmit data, we have to putWHAT 1, is the high level; when we transmit, we must consider the SCLK serial clock, which means that we have to transmit bit by bit, and consider thenot bit addressable, so we useBitwise AND and binary left shift rightWhen transmitting 1 bit, SCLK is set to low level first, then high level, and the corresponding bit is stored by means of rising edge; in this way, the transmission of the address is completed after 8 cycles; then Repeat the data transmission 8 times to complete the writing operation; finally set CE to 0;
insert image description here
look at the writing part again:
if we count the concave and convex bits corresponding to SCLK, we will find that there are only 15, so here, we To reuse a bump bit once, it can be solved; other operations are no different from writing;
insert image description here

BCD code

BCD code (Binary Coded Decimal‎), uses 4 binary numbers to represent 1 decimal number.
For example, 13, it is represented by this: 0001 0011; it
uses 4 bits to represent the corresponding decimal number, but This representation method will also have problems on the display screen, such as: 0001 1010 expressed in hexadecimal is 0x1A, and decimal is illegal;insert image description here

So we have to calculate, when we input data storage, we need to convert the decimal numbers into BCD codes for storage, and when we want to read, we need to convert the BCD codes into decimal numbers ;

BCD code to decimal: DEC=BCD/16 10+BCD%16; (2-digit BCD)
decimal to BCD code: BCD=DEC/10
16+DEC%10; (2-digit BCD)

We can also observe that in the register, the number of digits in the corresponding register is used to store and represent; and 4 digits are finally entered into 10 digits, which is the BCD code.

DS1302 clock code

LED1602.c

#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
    
    
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
    
    
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
    
    
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
    
    
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
    
    
	if(Line==1)
	{
    
    
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
    
    
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
    
    
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
    
    
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
    
    
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
    
    
		LCD_WriteData(String[i]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
    
    
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
    
    
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
    
    
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
    
    
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
    
    
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
    
    
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
    
    
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
    
    
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
    
    
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
    
    
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
    
    
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
    
    
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
    
    
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
    
    
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}

LCD1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

DS1302.c


```c
#include <REGX52.H>

//通过名称的转换,易于引用
//进行引脚定义
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;

//寄存器写入地址
#define DS1302_SECOND  	0x80
#define DS1302_MINUTE		0x82
#define DS1302_HOUR			0x84
#define DS1302_DATE			0x86
#define DS1302_MONTH		0x88
#define DS1302_DAY			0x8A
#define DS1302_YEAR			0x8C
#define DS1302_WP				0x8E   //写入保护

//时间数组,分别表示年月日,时分秒,星期
unsigned int DS1302_Time[]={
    
    23,7,15,17,47,20,6};

//对DS1302进行初始化
//由于DS1302接电时,会将CE和SCLK置于高电平;¯
void DS1302_Init()
{
    
    
	DS1302_CE=0;
	DS1302_SCLK=0;
}

//DS1302写入一个字节
void DS1302_WriteByte(unsigned char Command,Data)
{
    
    
	unsigned int i;
	//将CE置1
	DS1302_CE=1;
	//先写入地址
	for(i=0;i<8;i++)
	{
    
    
		DS1302_IO=Command&(0x01<<i);
		//将地址一位一位与上0x01通过循环左移1,
		DS1302_SCLK=1;//上升沿开;
		DS1302_SCLK=0;
		//在每一次循环中,上升沿会将对应的位进行上升,使之不会影响到下一次按位与;
	}
	//再写入数据
	for(i=0;i<8;i++)
	{
    
    
		DS1302_IO=Data&(0x01<<i);
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	}
	DS1302_CE=0;
}

unsigned char DS1302_ReadByte(unsigned char Command)
{
    
    
	unsigned char i,Data=0x00;
	Command|=0x01; //将指令或上0x01将最低位置1,转换为读指令;
	DS1302_CE=1;
	for(i=0;i<8;i++)
	{
    
    
		DS1302_IO=Command&(0x01<<i);
		DS1302_SCLK=0;
		DS1302_SCLK=1;
		//在这里,先将SCLK先置0,后置1,便于对SCLK一个凹凸位多次利用
	}
	for(i=0;i<8;i++)
	{
    
    
		//利用与上一个循环SCLK最后为1,这次循环开始也将SCLK置1,就能达到重复利用一个凹凸位;
		DS1302_SCLK=1;
		DS1302_SCLK=0;
		//判断数据是否为空
		if(DS1302_IO)
		{
    
    
			Data|=(0x01<<i);
		}
	}
	DS1302_CE=0;
	DS1302_IO=0;   //读取后需要将IO置为0,否则将会出现错误;
	return Data;
	}
	
	//DS1302设置时间,十进制转换为BCD码
void DS1302_SetTime()
{
    
    
	DS1302_WriteByte(DS1302_WP,0x00);
	DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);
	DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
	DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
	DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
	DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
	DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
	DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
	DS1302_WriteByte(DS1302_WP,0x80);
}

//DS1302读取数据,将BCD码转为十进制
void DS1302_ReadTime()
{
    
    
	unsigned int Temp;
	Temp=DS1302_ReadByte(DS1302_YEAR);
	DS1302_Time[0]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_MONTH);
	DS1302_Time[1]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_DATE);
	DS1302_Time[2]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_HOUR);
	DS1302_Time[3]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_MINUTE);
	DS1302_Time[4]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_SECOND);
	DS1302_Time[5]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_DAY);
	DS1302_Time[6]=Temp/16*10+Temp%16;
}
	
	

DS1302.h


```c
#ifndef __DS1302_H__
#define __DS1302_H__

extern unsigned int DS1302_Time[];


void DS1302_Init();¯
void DS1302_WriteByte(unsigned char Command,Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_SetTime();
void DS1302_ReadTime();

#endif

main.c

#include <REGX52.H>
#include"Ds1302.h"
#include"LCD1602.h"
void  main()
{
    
    
	LCD_Init();
	DS1302_Init();
	LCD_ShowString(1,1,"  _  _  ");
	LCD_ShowString(2,1,"  :  :  ");
	DS1302_SetTime();
	while(1)
	{
    
    
		DS1302_ReadTime();
		LCD_ShowNum(1,1,DS1302_Time[0],2);
		LCD_ShowNum(1,4,DS1302_Time[1],2);
		LCD_ShowNum(1,7,DS1302_Time[2],2);
		LCD_ShowNum(2,1,DS1302_Time[3],2);
		LCD_ShowNum(2,4,DS1302_Time[4],2);
		LCD_ShowNum(2,7,DS1302_Time[5],2);
	}
	
}

Guess you like

Origin blog.csdn.net/m0_74068921/article/details/131745259