51单片机——DS1302时钟

这篇具有很好参考价值的文章主要介绍了51单片机——DS1302时钟。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1.前言

1.1 实验现象

2. DS1302的介绍

2.1 DS1302的引脚定义以及应用电路

2.2 DS1302内部结构

2.21  DS1302内部特殊寄存器

2.22 时序

2.3 BCD码

3.源码

3.1 main.c

3.2 DS1302.c

3.3 DS1302.h

3.4 LCD1602.c

3.5 Delay.c

3.6 Delay.h


1.前言

之前我们已经使用了定时器做过了简易的时钟了,为什么还要用DS1302制作时钟呢?

定时器计时的缺点:

1.精度没有时钟芯片高

2.它会占用单片机cpu时间

3.单片机的定时器时钟不能掉电后继续运行;

DS1302时钟芯片带有备用电池,如果掉电,它的内部逻辑判断就会自动把电源切换到备用电池;

由于开发板上vcc1没有接备用电源,掉电继续走时的现象就看不到了

1.1 实验现象

第一行显示年— 月— 日 第二行显示时:分:秒

ds1302,51单片机,单片机,fpga开发,51单片机,嵌入式硬件

 

 

2. DS1302的介绍

DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能
RTC(Real Time Clock):实时时钟,是一种集成电路,通常称为时钟芯片

ds1302,51单片机,单片机,fpga开发,51单片机,嵌入式硬件ds1302,51单片机,单片机,fpga开发,51单片机,嵌入式硬件

2.1 DS1302的引脚定义以及应用电路

 ds1302,51单片机,单片机,fpga开发,51单片机,嵌入式硬件ds1302,51单片机,单片机,fpga开发,51单片机,嵌入式硬件

ds1302,51单片机,单片机,fpga开发,51单片机,嵌入式硬件

2.2 DS1302内部结构

ds1302,51单片机,单片机,fpga开发,51单片机,嵌入式硬件

x1,x2 接外部晶振,通过内部电路输出1HZ标准计时频率;

右下角:内部寄存器,内部时间存在这里;

CE:芯片使能 这里的CE相当于一个中介开关,CE高电平有效。

输入移位寄存器与74HC595差不多,进行串行数据的交互的;

2.21  DS1302内部特殊寄存器

ds1302,51单片机,单片机,fpga开发,51单片机,嵌入式硬件

ds1302,51单片机,单片机,fpga开发,51单片机,嵌入式硬件

内部不止这些寄存器还有一些通用寄存器 ,这些特殊寄存器是与时钟有关的

寄存器都有一个地址,每个地址下就是一个数据,数据是一个字节一个字节存储的;

wp:写保护,置高电平,写入的操作是无效的,但可以读取数据;

TCS TCS...涓细电流充电的,开发板没有这个寄存器就不用配置了;

80H,81H是命令字,也代表了它的地址;

完成时钟显示的基本流程:

在哪里  写入 什么

在哪里 读出 什么

命令字任务:

在哪里  写入

在哪里 读出

2.22 时序

ds1302,51单片机,单片机,fpga开发,51单片机,嵌入式硬件

单字节写为16个脉冲,单字节读为15个脉冲,编写代码时需注意;单字节读:写完指令后,单片机释放对I/O口的控制,把I/O口控制权交给DS1302;我们只要写完指令后重复置高电平就可以过滤掉一个脉冲了;

 单字节写:

首先把CE置高电平,开始写,第二步命令字发两个字节,第一个:命令字;第二个字节数据

命令字:第一位先发R/(--W)设置到I/O口上 别问为什么,问就是内部芯片就是这样设计的。

上升沿数据写入;依次循环,直到最高位被写入;

CE置高电平后,第一个写入的就是命令字(告诉它在哪里读,还是在哪里写)操作完成后CE置低电平

单字节读:

写入完成命令字后,下降沿把I/O口线释放掉,就不再操作I/O口了,就开始读出数据

每一个下降沿来一个数据,把数据一个一个读出来;注意单字节读D1到D7是不用操作I/O口的;

2.3 BCD码

内部寄存器数据不是以正常二进制进行存储的,而是以BCD码进行存储的(方便译码)

BCD码(Binary Coded Decimal‎),用4位二进制数来表示1位十进制数

例:0001 0011表示13,1000 0101表示85,0001 1010不合法

在十六进制中的体现:0x13表示13,0x85表示85,0x1A不合法

BCD码转十进制:DEC=BCD/16*10+BCD%16; (2位BCD)
十进制转BCD码:BCD=DEC/10*16+DEC%10; (2位BCD)

注:这个方法只能转化2位BCD,所以下面代码中显示年份2022的只显示为22年

3.源码

3.1 main.c

#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"

void main()
{
	LCD_Init();
	DS1302_Init();
	LCD_ShowString(1,1,"  -  -  ");//静态字符初始化显示
	LCD_ShowString(2,1,"  :  :  ");//第二行的时分秒
	
	DS1302_SetTime();//设置时间
	
	while(1)
	{
		DS1302_ReadTime();//不断循环读取DS1302中的时间数据
		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);//显示秒
	}
}

3.2 DS1302.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

//时间数组,索引0~6分别为年、月、日、时、分、秒、星期
unsigned char DS1302_Time[]={22,11,16,12,59,55,6};

//单片机上电后默认置高电平,所以初始化
void DS1302_Init()
{
	DS1302_CE=0;
	DS1302_SCLK=0;
}

/**
  * @brief  DS1302写一个字节
  * @param  Command 命令字/地址
  * @param  Data 要写入的数据
  * @retval 无
  */
void DS1302_WriteByte(unsigned char Command,Data)
{
	unsigned char i;
	DS1302_CE=1;
	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);
		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;   //看着时序配
}

/**
  * @brief  DS1302读一个字节
  * @param  Command 命令字/地址
  * @retval 读出的数据
  */
unsigned char DS1302_ReadByte(unsigned char Command)
{
	unsigned char i,Data=0x00;
	Command|=0x01;	//将指令转换为读指令
	DS1302_CE=1;
	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);
		DS1302_SCLK=0;
		DS1302_SCLK=1;
	}
	for(i=0;i<8;i++)
	{
		DS1302_SCLK=1;//重复置高电平,过滤掉一个脉冲
		DS1302_SCLK=0;
		if(DS1302_IO){Data|=(0x01<<i);}
	}
	DS1302_CE=0;
	DS1302_IO=0; //读取后将IO设置为0,否则读出的数据会出错
	return Data; //写完指令后,单片机释放对I/O口的控制,把I/O口控制权交给DS1302;
}

/**
  * @brief  DS1302设置时间,调用之后,DS1302_Time数组的数字会被设置到DS1302中
  * @param  无
  * @retval 无
  */
void DS1302_SetTime()  //十进制转BCD码后写入
{
	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);
}

/**
  * @brief  DS1302读取时间,调用之后,DS1302中的数据会被读取到DS1302_Time数组中
  * @param  无
  * @retval 无
  */
void DS1302_ReadTime()  //BCD码转十进制后读取
{
	unsigned char 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;
}

3.3 DS1302.h

#ifndef __DS1302_H__
#define __DS1302_H__

//外部可调用时间数组,索引0~6分别为年、月、日、时、分、秒、星期
extern unsigned char 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

3.4 LCD1602.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文章来源地址https://www.toymoban.com/news/detail-794291.html

#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

3.5 Delay.c


void Delay(unsigned int xms)
{
	unsigned char i, j;
	while(xms--)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}

3.6 Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__

void Delay(unsigned int xms);

#endif

到了这里,关于51单片机——DS1302时钟的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于51单片机、DS1302时钟模块的电子闹钟设计

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 提示:以下是本篇文章正文内容,下面案例可供参考 DS1302 是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周、时、分、秒进行计时,具有闰年补偿功能,工作

    2024年02月02日
    浏览(63)
  • 使用51单片机和DS1302时钟芯片做一个简易的电子时钟

    今天给大家推荐一个51单片机小实验,带你使用51单片机做一款简易的电子时钟,其中计时模块采用DS1302硬件模块,显示采用LCD显示屏,具体怎么实现开来一起看看吧! DS1302 是 DALLAS 公司推出的涓流充电时钟芯片,内含有一个实时时钟和31字节静态 RAM,通过简单的串行接口与

    2024年02月11日
    浏览(45)
  • 【单片机】13-实时时钟DS1302

    (rtc for real time clock) (1)时间点和时间段的概念区分 (2)单片机为什么需要时间点【一定的时间点干什么事情】 (3)RTC如何存在于系统中(单片机内部集成 or 单片机外部扩展【DS1302】) 1.数据手册 DS1302中文数据手册 - 豆丁网 2. SPI数字接口 访问 SPI通信协议【DS1302也使用

    2024年02月07日
    浏览(43)
  • 单片机第一季:零基础11——实时时钟DS1302

    目录 1,DS1302 时钟芯片介绍  2,BCD码介绍  3,涉及到的寄存器  3.1,控制寄存器 3.2,日历/时钟寄存器  3.3,DS1302 的读写时序  4,相关代码  这一章我们来学习DS1302 时钟芯片,该芯片是3 线SPI 接口,所以需要使用51单片机的3 个IO 口模拟SPI 时序与DS1302 时钟芯片通信,将时钟

    2024年02月16日
    浏览(53)
  • 蓝桥杯单片机比赛学习:12、DS1302时钟基本原理与使用方法

    DS1302是 DALLAS 公司推出的时钟芯片,内含一个实时时钟/日历和 31字节静态 RAM,通过简单的串行接口与单片机进行通信。实时时钟/日历电路提供秒、分、时、日、周、月、年的信息,每月的天数和闰年的天数可自动调整。 但是在我们比赛中一般只需要写/读时钟。 DS1302可以采

    2024年02月02日
    浏览(45)
  • STC单片机DS1307+ssd1306 oled时钟显示

    📌相关篇《STC单片机DS1302+ssd1306 oled时钟显示》 📍《STC单片机对DS1307读写操作》 ✨效果演示: 🌿实验对象:STC12C5A60S2 🌿屏幕型号:I2C ssd1306 0.96“ oled 🌿晶振频率:11.059MHz 🌿串口波特率:9600 📜串口打印读取信息: 🛠引脚说明 ✨由于屏幕接口ssd1306 0.96“ oled和DS1307的接

    2023年04月09日
    浏览(49)
  • 51单片机温度传感器DS18B20

    实现功能 插上DS18B20温度传感器,数码管显示检测的温度值 单片机型号:STC89C52 DS18B20介绍 1、DS18B20简介 DS18B20 是由 DALLAS 半导体公司推出的一种的“一线总线(单总线)”接口的温度传感器。与传统的热敏电阻等测温元件相比,它是一种新型的体积小、 适用电压宽、与微处理

    2024年02月01日
    浏览(47)
  • 基于51单片机的DS18B20温度显示

    本讲内容:       了解温度传感器DS18B20的使用,并通过一个例程展示温度传感器DS18B20测温过程。 DS18B20简介:       DS18B20 是单线数字温度传感器,即“一线器件”,其具有独特的优点:     (1)采用单总线的接口方式 与微处理器连接时 仅需要一条口线即可实现微处理器

    2024年02月12日
    浏览(50)
  • 51单片机读取DS18B20温度传感器

    1 .首先我们知道DS18B20是 单总线协议 ,只有一根数据线。所以Data数据线即使发送端又是接收端,同时DS18B20内部接了弱上拉电阻(如图一所示),数据线默认为高电平。有了这些概念,我们就能进行下一步。                                                图一 (截取

    2024年02月08日
    浏览(37)
  • 51单片机(十三)DS18B20温度传感器

    ❤️ 专栏简介:本专栏记录了从零学习单片机的过程,其中包括51单片机和STM32单片机两部分;建议先学习51单片机,其是STM32等高级单片机的基础;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 :适用于想要从零基础开始学习入门单片机,且有一定C语言基础的的童鞋

    2024年02月11日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包