51 MCU--DS1302 reloj

DS1302

DS1302 es un producto lanzado por la empresa estadounidense DALLASChip de circuito de reloj en tiempo real. Tiene las características de alto rendimiento y bajo consumo de energía, y puede comunicarse con la CPU sincrónicamente a través de la interfaz SPI de tres hilos. DS1302 puede proporcionar información de tiempo como segundos, minutos, horas, días, semanas, meses y años, y puede ajustar automáticamente la fecha, y también tiene una función de compensación en años bisiestos. Opera en una amplia gama de voltajes y puede ser2,5 V a 5,5 Vutilizado entre.
El DS1302 se puede utilizar para fabricar relojes electrónicos y otras aplicaciones. Tiene un reloj/calendario en tiempo real incorporado y 31 bytes de RAM estática. Conectado con un microcontrolador u otro controlador a través de una interfaz serial simple, los datos de tiempo se pueden leer y configurar, y se puede almacenar información adicional.

En comparación con la sincronización de los temporizadores, DS1302 es un reloj de sincronización en el hardware. En cuanto a los temporizadores, deben ser procesados ​​por programas de software antes de que puedan cronometrar relojes. Por lo tanto, DS1302 puede realizar relojes solo a través de un diseño de programa simple. Función;

Definición de pines y circuito de aplicación.

inserte la descripción de la imagen aquí
Este es el chip DS1302 en el microcontrolador 51;
inserte la descripción de la imagen aquí

La imagen superior izquierda muestra dos técnicas de empaque diferentes. El empaque DIP también se denomina tecnología de empaque dual en línea, que es el método de empaque más simple; el empaque SOP es una forma de empaque de componentes. Generalmente, hay muchos materiales de empaque: plástico, cerámica , vidrio, metal, etc.; los envases de plástico son ampliamente utilizados ahora; se utilizan principalmente en varios circuitos integrados.

En nuestra microcomputadora de un solo chip STC89C52,
utiliza el método de empaquetado SOP; tiene 8 pines VCC como fuente de alimentación en la microcomputadora de un solo chip, de los cuales VCC1 es la batería de respaldo, es decir, cuando la fuente de alimentación principal está apagada , es alimentado por la batería de respaldo, pero debe tenerse en cuenta que existenNo hay batería de respaldo en este microcontrolador;Y VCC2 es la fuente de alimentación principal, que no se puede invertir con la batería de respaldo; GND está conectado a tierra; X1 y X2 están conectados a un oscilador de cristal de 32.768kHz, que es el mismo principio que el temporizador, y está cronometrado por la frecuencia de vibración del oscilador de cristal; el cilindro en la figura a continuación es el componente del oscilador de cristal en la microcomputadora de un solo chip; luego se habilita el chip CE (habilitación del núcleo), y el chip puede controlar el componente a través de esta ruta; IO son los datos puerto de entrada y salida, utilizado para la transmisión de datos; SCLK es el reloj en serie, generalmente utilizado para la sincronización La señal del reloj para la transmisión de datos controla la velocidad de transmisión y el tiempo de los datos.
inserte la descripción de la imagen aquí
A continuación, mire la imagen de la derecha; la CPU controla el reloj del DS1302 a través de los tres pines CE, I\O y SCLK; el DS1302 está conectado a la fuente de alimentación y la batería, y luego conectado a tierra; luego conectado a la interfaz de cristal .
inserte la descripción de la imagen aquí
Este es el diagrama esquemático del microcontrolador 51.

Diagrama de estructura interna

inserte la descripción de la imagen aquí
Para el interior, a excepción del control de potencia, generalmente se puede simplificar a 4 módulos:

  1. Módulo de reloj: principalmente responsable de proporcionar señales de reloj precisas. Está impulsado por un oscilador de cristal de 32,768 kHz que genera la señal del reloj del sistema para mantener la precisión del conteo del tiempo.
  2. Módulo RAM: 31 bytes de RAM están integrados dentro de DS1302 paraAlmacene información de fecha y hora, registros de control y datos definidos por el usuarioesperar.
  3. Módulo lógico de control : este módulo recibe instrucciones del host y realiza operaciones de reloj y RAM de acuerdo con las instrucciones.operaciones de lectura y escritura. También incluye funciones como control de habilitación de reloj, control de protección contra escritura y control de temporizador.
  4. Interfaz de comunicación: DS1302 proporciona una interfaz serial para comunicarse con el host, generalmente una interfaz de 3 hilos (I\O, SCLK, CE), a través de la cual se realizan la transmisión y el control de datos con el host.

definición de registro

inserte la descripción de la imagen aquí
Este es el registro más importante para controlar el reloj; de acuerdo con el diagrama de bloques anterior, para DS1302, necesita usar operaciones de lectura y escritura, que se dividen en dos partes para completar; en términos simples, **escribimos en el DS1302 reloj a través del programa Ingrese la información, luego almacene la información en la RAM y luego sáquela de la RAM cuando se lea; ** Entonces veremos que hay dos bits LEER y ESCRIBIR en el registro; la primera línea
essegundos de control, el CH en el bit 7 es el indicador de pausa del reloj. Cuando es 1, el oscilador del reloj se detiene y el reloj deja de funcionar. Cuando es 0, el reloj comienza a funcionar; la segunda línea
controlaminuto;
La tercera línea controla elHora, puede tener formato de 12 o 24 horas, el nivel alto es el modo de 12 horas, y cuando el bit 5 es 1, significa PM; el nivel bajo es de 24 horas; el orden de control
esdía, mes, semana, año;
Última segunda filaProtección contra escritura (WP: protección contra escritura), cuando la dirección de lectura y escritura correspondiente se establece en 0x00, la protección contra escritura se activa;
la última línea está relacionada con la batería de respaldo, ya que no hay una microcomputadora de un solo chip, no se proporciona una introducción específica;

La siguiente figura es la dirección o byte de comando:
a través de la dirección correspondiente, encuentra el año, mes, día, hora, minuto y segundo correspondiente;
cuando el bit bajo es 0, está escribiendo, y cuando es 1, está leyendo ;

definición de tiempo

inserte la descripción de la imagen aquí
Estas son las interfaces de tres pines que conectan la CPU y el reloj DS1302. Para nosotros, el programa es realizar el enlace con el reloj DS1302 a través de estas tres interfaces; aquí, los registros no son direccionables por bits; primero mire la parte escrita
:
El puerto I\O es para transmisión de datos, aquí hay dos bytes, el primero es el byte de la dirección, y el segundo es el byte correspondiente a los datos, cuando queremos transmitir datos, tenemos que ponerQUE 1, es el nivel alto, cuando transmitimos, debemos considerar el reloj serial SCLK, lo que significa que tenemos que transmitir bit a bit, y considerar elno poco direccionable, entonces usamosAND bit a bit y desplazamiento a la izquierda binario a la derechaAl transmitir 1 bit, SCLK se establece primero en nivel bajo, luego en nivel alto, y el bit correspondiente se almacena mediante un flanco ascendente; de ​​esta manera, la transmisión de la dirección se completa después de 8 ciclos; luego repite la transmisión de datos 8 veces para completar la operación de escritura; finalmente establezca CE en 0;
inserte la descripción de la imagen aquí
mire la parte de escritura nuevamente:
si contamos los bits cóncavos y convexos correspondientes a SCLK, encontraremos que solo hay 15, así que aquí, para reutilizar un bit de choque una vez, se puede resolver, otras operaciones no son diferentes de la escritura;
inserte la descripción de la imagen aquí

código BDC

El código BCD (Binary Coded Decimal‎), usa 4 números binarios para representar 1 número decimal.
Por ejemplo, 13, se representa así: 0001 0011; usa
4 bits para representar el número decimal correspondiente, pero este método de representación también tiene problemas en la pantalla de visualización, tales como: 0001 1010 expresado en hexadecimal es 0x1A, y el decimal es ilegal;inserte la descripción de la imagen aquí

Así que tenemos que calcular, cuando ingresamos el almacenamiento de datos, necesitamos convertir los números decimales en códigos BCD para el almacenamiento, y cuando queremos leer, necesitamos convertir los códigos BCD en números decimales ;

Código BCD a decimal: DEC=BCD/16 10+BCD%16; (BCD de 2 dígitos)
código decimal a BCD: BCD=DEC/10
16+DEC%10; (BCD de 2 dígitos)

También podemos observar que en el registro se utiliza la cantidad de dígitos del registro correspondiente para almacenar y representar; y finalmente se ingresan 4 dígitos en 10 dígitos, que es el código BCD.

Código de reloj DS1302

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

C Principal

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

Supongo que te gusta

Origin blog.csdn.net/m0_74068921/article/details/131745259
Recomendado
Clasificación