IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 51单片机-DS1302可调时钟(实现代码) -> 正文阅读

[嵌入式]51单片机-DS1302可调时钟(实现代码)

目录

一、介绍

1.DS1302介绍

2.引脚定义和应用电路

3.内部结构框图

4. 寄存器定义

?5.时序定义

6.BCD码

?二、文件内容

a.代码功能

1.代码实现功能

2.工程文件内容

b.代码详细内容

1.main.c

2.DS1302.c

3.DS1302.h

4.?Delay.c

5.?Delay.h

6.Key.c

7.Key.h

8.LCD1602.c

9.LCD1602.h

10.Timer0.c

11.Timer0.h


一、介绍

1.DS1302介绍

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

2.引脚定义和应用电路

? ? ? ?? ? ? ? ? ??

引脚名

作用

引脚名

作用

VCC2

主电源

CE

芯片使能

VCC1

备用电池

IO

数据输入/输出

GND

电源地

SCLK

串行时钟

X1X2

32.768KHz晶振

3.内部结构框图

4. 寄存器定义

?5.时序定义

6.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)

?二、文件内容

a.代码功能

1.代码实现功能

????????显示年月日、时分秒

? ? ? ? 按下按键1选择模式【显示/更改】,按下按键2选择要更改的数,按键3【+】,按键4【-】

2.工程文件内容

b.代码详细内容

1.main.c

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

unsigned char KeyNumber,MODE,TimeSetSelect,TimeSetFlashFlag;
unsigned char YEAR(unsigned char year,month);
void TimeShow();
void TimeSet();
	

void main(){
	LCD_Init();
	DS1302_Init();
	Timer0_Init();
	
	DS1302_SetTime();
	LCD_ShowString(1,1,"  -  -  ");
	LCD_ShowString(2,1,"  :  :  ");
	
	
	while(1){
		KeyNumber = Key();
		if(KeyNumber==1){
			if(MODE==0)MODE=1;
			else if(MODE==1){MODE=0;DS1302_SetTime();}
		}
		switch(MODE)
		{
			case 0: TimeShow();break;
			case 1: TimeSet();break;
		}
		
	}
}
//显示
void TimeShow(){
	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);
}
//修改
void TimeSet(){
	//选择需要更改的位
	if(KeyNumber == 2)
	{
		TimeSetSelect++;
		TimeSetSelect%=6;
	}
	//增加更改位的数,并判断是否越界
	if(KeyNumber == 3)
	{
		DS1302_Time[TimeSetSelect]++;
		if(DS1302_Time[0]>99){DS1302_Time[0]=0;}
		if(DS1302_Time[1]>12){DS1302_Time[1]=1;}
		
		if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==31)
		{
			if(DS1302_Time[2]>31){DS1302_Time[2]=1;}
		}
		if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==30)
		{
			if(DS1302_Time[2]>30){DS1302_Time[2]=1;}
		}
		if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==29)
		{
			if(DS1302_Time[2]>29){DS1302_Time[2]=1;}
		}
		if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==28)
		{
			if(DS1302_Time[2]>28){DS1302_Time[2]=1;}
		}
		
		if(DS1302_Time[3]>24){DS1302_Time[3]=0;}
		if(DS1302_Time[4]>59){DS1302_Time[4]=0;}
		if(DS1302_Time[5]>59){DS1302_Time[5]=0;}
	}
	//减小更改位的数,并判断是否越界
	if(KeyNumber == 4)
	{
		DS1302_Time[TimeSetSelect]--;
		if(DS1302_Time[0]>100){DS1302_Time[0]=99;}
		if(DS1302_Time[1]<1){DS1302_Time[1]=12;}
		
		if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==31)
		{
			if(DS1302_Time[2]<1){DS1302_Time[2]=31;}
			if(DS1302_Time[2]>31){DS1302_Time[2]=1;}
		}
		if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==30)
		{
			if(DS1302_Time[2]<1){DS1302_Time[2]=30;}
			if(DS1302_Time[2]>30){DS1302_Time[2]=1;}
		}
		if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==29)
		{
			if(DS1302_Time[2]<1){DS1302_Time[2]=29;}
			if(DS1302_Time[2]>29){DS1302_Time[2]=1;}
		}
		if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==28)
		{
			if(DS1302_Time[2]<1){DS1302_Time[2]=28;}
			if(DS1302_Time[2]>28){DS1302_Time[2]=1;}
		}
		
		if(DS1302_Time[3]>100){DS1302_Time[3]=24;}
		if(DS1302_Time[4]>100){DS1302_Time[4]=59;}
		if(DS1302_Time[5]>100){DS1302_Time[5]=59;}
	}
	//显示更改后的数据
	if(TimeSetSelect==0 && TimeSetFlashFlag==1){LCD_ShowString(1,1,"  ");}
	else{LCD_ShowNum(1,1,DS1302_Time[0],2);}
	
	if(TimeSetSelect==1 && TimeSetFlashFlag==1){LCD_ShowString(1,4,"  ");}
	else{LCD_ShowNum(1,4,DS1302_Time[1],2);}
	
	if(TimeSetSelect==2 && TimeSetFlashFlag==1){LCD_ShowString(1,7,"  ");}
	else{LCD_ShowNum(1,7,DS1302_Time[2],2);}
	
	if(TimeSetSelect==3 && TimeSetFlashFlag==1){LCD_ShowString(2,1,"  ");}
	else{LCD_ShowNum(2,1,DS1302_Time[3],2);}
	
	if(TimeSetSelect==4 && TimeSetFlashFlag==1){LCD_ShowString(2,4,"  ");}
	else{LCD_ShowNum(2,4,DS1302_Time[4],2);}
	
	if(TimeSetSelect==5 && TimeSetFlashFlag==1){LCD_ShowString(2,7,"  ");}
	else{LCD_ShowNum(2,7,DS1302_Time[5],2);}

	/*LCD_ShowNum(2,10,TimeSetSelect,2);
	LCD_ShowNum(2,13,TimeSetFlashFlag,2);*/
}

//闰年判断,月份天数判断
unsigned char YEAR(unsigned char year,month){
	if(year%400==0||year%4==0&&year%100!=0)
	{
		if(month==2)
			return 29;
	}
	else
	{
		if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)
			return 31;
		else if(month==4||month==6||month==9||month==11)
			return 30;
		else
			return 28;
	}
	return 0;
}
//定时器
void Timer0_Routine() interrupt 1
{
	static unsigned int count0 = 0;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	count0++;
	if(count0 == 300){
		count0 = 0;
		TimeSetFlashFlag=!TimeSetFlashFlag;
	}
		
}

2.DS1302.c

#include <REGX52.H>

#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

sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;

unsigned char DS1302_Time[]={22,12,31,23,59,58,2}; 

/**
  * @brief BCD转10进制 
  * @param  
  * @retval 
  */

unsigned char BCD_10(unsigned char Num){
	unsigned char Temp;
	Temp = Num/10*16+Num%10;
	return Temp;
}

/**
  * @brief 10进制转BCD码 
  * @param  
  * @retval 
  */

unsigned char Ten_BCD(unsigned char Num){
	unsigned char Temp;
	Temp = Num/16*10+Num%16;
	return Temp;
}

/**
  * @brief  初始化DS1302
  * @param  
  * @retval 
  */

void DS1302_Init(){
	DS1302_SCLK=0;
	DS1302_CE=0;
}

/**
  * @brief  写入字节
  * @param  
  * @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  读取字节
  * @param  
  * @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;
	return Data;
}

/**
  * @brief  将数组内容写入
  * @param  
  * @retval 
  */

void DS1302_SetTime(){
	DS1302_WriteByte(DS1302_WP,0x00);
	DS1302_WriteByte(DS1302_YEAR,BCD_10(DS1302_Time[0]));
	DS1302_WriteByte(DS1302_MONTH,BCD_10(DS1302_Time[1]));
	DS1302_WriteByte(DS1302_DATE,BCD_10(DS1302_Time[2]));
	DS1302_WriteByte(DS1302_HOUR,BCD_10(DS1302_Time[3]));
	DS1302_WriteByte(DS1302_MINUTE,BCD_10(DS1302_Time[4]));
	DS1302_WriteByte(DS1302_SECOND,BCD_10(DS1302_Time[5]));
	DS1302_WriteByte(DS1302_DAY,BCD_10(DS1302_Time[6]));
	DS1302_WriteByte(DS1302_WP,0x80);
}

/**
  * @brief  读出数组内容
  * @param  
  * @retval 
  */

void DS1302_ReadTime(){
	
	DS1302_Time[0]=Ten_BCD(DS1302_ReadByte(DS1302_YEAR));
	DS1302_Time[1]=Ten_BCD(DS1302_ReadByte(DS1302_MONTH));
	DS1302_Time[2]=Ten_BCD(DS1302_ReadByte(DS1302_DATE));
	DS1302_Time[3]=Ten_BCD(DS1302_ReadByte(DS1302_HOUR));
	DS1302_Time[4]=Ten_BCD(DS1302_ReadByte(DS1302_MINUTE));
	DS1302_Time[5]=Ten_BCD(DS1302_ReadByte(DS1302_SECOND));
	DS1302_Time[6]=Ten_BCD(DS1302_ReadByte(DS1302_DAY));
}

3.DS1302.h

#ifndef __SD1302_H__
#define __SD1302_H__

extern unsigned char DS1302_Time[];

void DS1302_Init();
void DS1302_ReadTime();
void DS1302_SetTime();

#endif

4.?Delay.c


void Delay(unsigned int t)		//延时函数
{
	
	unsigned char i, j;
	while(t){
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
		t--;
	}

	
}

5.?Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__

void Delay(unsigned int t);

#endif

6.Key.c

#include <REGX52.H>
#include "Delay.h"

/**
  * @brief 获取独立按键键码 
  * @param  无
  * @retval KeyNumber 键码
  */

unsigned char Key(){
	unsigned char KeyNumber = 0;
	
	if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber = 1;}
	if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber = 2;}
	if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber = 3;}
	if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber = 4;}
	
	return KeyNumber;
}

7.Key.h

#ifndef __KEY_H__
#define __KEY_H__

unsigned char Key();

#endif

8.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');
	}
}

9.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

10.Timer0.c

#include <REGX52.H>

void Timer0_Init(void)		//1毫秒@12.000MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA = 1;
	PT0 = 0;
}

/* 定时器中断函数模板
void Timer0_Routine() interrupt 1
{
	static unsigned int count0 = 0;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	count0++;
	if(count0 == 1000){
		count0 = 0;
	}
		
}
*/

11.Timer0.h

#ifndef __TIMER0_H__
#define __TIMER0_H__

void Timer0_Init(void);	

#endif

模块化编程

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-10-22 21:31:28  更:2022-10-22 21:32:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 19:04:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码