DS3231高精度时钟,LCD1602显示,QXmini151版本「建议收藏」

本设计的主要任务是计时和显示。设计任务的具体要求如下:计时:第一种是通过单片机内部的定时器/计数器来实现为软时钟。第二种是通过专用的硬件时钟芯片来实现为硬时钟。 显示:第一种是数码管显示,分为静态显示和动态显示,动态显示需要占用cpu大量时间来运行,不需要复杂的驱动程序,制作成本不高。第二种是LCD1602液晶显示,能显示出较多的信息并且数字清晰,应用广泛,但是不便于观察。总设计思路阐述1.时钟方案设计及选择:目前有DS3231、DS302、DS12C887三种时钟芯片。本次设计选择DS32

大家好,又见面了,我是你们的朋友全栈君。

本设计的主要任务是计时和显示。

设计任务的具体要求如下:

  1. 计时:第一种是通过单片机内部的定时器/计数器来实现为软时钟。第二种是通过专用的硬件时钟芯片来实现为硬时钟。
  2. 显示:第一种是数码管显示,分为静态显示和动态显示,动态显示需要占用cpu大量时间来运行,不需要复杂的驱动程序,制作成本不高。第二种是LCD1602液晶显示,能显示出较多的信息并且数字清晰,应用广泛,但是不便于观察。

总设计思路阐述

1.时钟方案设计及选择:目前有DS3231、DS302、DS12C887三种时钟芯片。本次设计选择DS3231,

需要应用IC总线协议。

2.核心控制区设计方案:选用STC89C51作为核心控制单元。

3.显示原件:采用LCD1602液晶显示。

4.键盘设置:设计为时、分、秒的调整按键。

5.控制继电器:选择5V/1A继电器,驱动LCD液晶显示。

6.外围电路:复位电路,晶振。

7.时钟时序问题

代码如下:

/*******************************************************************************
实验名 :高精度时钟显示和控制
使用的IO  : P3^0  SDA
		    P3^1  SCL
实验效果:1602 显示时钟,按S4进入时钟设置并暂停时钟,按S1选择时钟设置的时分秒日月周年,按S3使时间加一
*******************************************************************************/

#include<reg51.h>
#include"lcd.h"
#include"ds3231.h"

sbit K1=P3^5;//按键IO口定义
sbit K2=P3^4;
sbit K3=P3^3;
sbit K4=P3^2;

void Int0Configuration();//外部中断初始化函数声明
void LcdDisplay();//LCD初始化函数声明
unsigned char SetState,SetPlace;
void Delay10ms(void);   //10ms延迟函数
/*******************************************************************************
* 函数名          : main
* 函数功能		  : 主函数
* 输入            : 无
* 输出            : 无
*******************************************************************************/

void main()
{
	unsigned char i;
	Int0Configuration();//外部中断初始化
	LcdInit();//LCD初始化
	DS3231_Init();//DS3231模块初始化
	while(1)
	{	
		if(SetState==0)//标志位为0时读取时间
		{
			DS3231_Read_time(); 
		}
		else
		{
			if(K1==0)		//检测按键K1是否按下
			{
				Delay10ms();	//消除抖动
				if(K1==0)
				{
					while(!K1);//检测是否松手
					SetPlace++;
					if(SetPlace>=7)
						SetPlace=0;					
				}
			}
			if(K2==0)		//检测按键K2是否按下
			{
				Delay10ms();	//消除抖动
				if(K2==0)
				{
					while(!K2);//松手检测
					TIME[SetPlace]++;
					if((TIME[SetPlace]>=60)&&(SetPlace<2))		//分秒只能到60
					{
						TIME[SetPlace]=0;
					}
					if((TIME[SetPlace]>=24)&&(SetPlace==2))		//小时只能到23
					{
						TIME[SetPlace]=0;
					}
					if((TIME[SetPlace]>=32)&&(SetPlace==3))		//日只能到31
					{
						TIME[SetPlace]=0;	
					}
					if((TIME[SetPlace]>=13)&&(SetPlace==4))		//月只能到12
					{
						TIME[SetPlace]=0;
					}	
					if((TIME[SetPlace]>=8)&&(SetPlace==5))		//周只能到7
					{
						TIME[SetPlace]=1;
					}		
				}
				
				while((i<50)&&(K2==0))	 //检测按键是否松开
				{
					Delay10ms();
					i++;
				}
				i=0;
				
			}						
		}
		LcdDisplay();	//LCD显示函数
	}
	
}
/*******************************************************************************
* 函数名         : LcdDisplay()
* 函数功能		 : 显示函数
* 输入            : 无
* 输出            : 无
*******************************************************************************/

void LcdDisplay()
{
	LcdWriteCom(0x80+0X40);
	LcdWriteData('0'+TIME[2]/10);				//时
	LcdWriteData('0'+(TIME[2]%10));				 
	LcdWriteData('-');
	LcdWriteData('0'+TIME[1]/10);				//分
	LcdWriteData('0'+(TIME[1]%10));	
	LcdWriteData('-');
	LcdWriteData('0'+TIME[0]/10);				//秒
	LcdWriteData('0'+(TIME[0]%10));

	LcdWriteCom(0x80);
	LcdWriteData('2');
	LcdWriteData('0');
	LcdWriteData('0'+TIME[6]/10);			//年
	LcdWriteData('0'+(TIME[6]%10));
	LcdWriteData('-');
	LcdWriteData('0'+TIME[4]/10);			//月
	LcdWriteData('0'+(TIME[4]%10));
	LcdWriteData('-');
	LcdWriteData('0'+TIME[3]/10);			//日
	LcdWriteData('0'+(TIME[3]%10));
	LcdWriteCom(0x8D);
	LcdWriteData('0'+(TIME[5]%10));	//星期			 
}
/*******************************************************************************
* 函数名         : Int0Configuration()
* 函数功能		 : 配置外部中断0
* 输入            : 无
* 输出            : 无
*******************************************************************************/

void Int0Configuration()
{
	//设置INIT0
	IT0=1;//跳边沿触发方式(下降沿)
	EX0=1;//打开INT0中断允许
	EA=1;//	打开总中断
}
/*******************************************************************************
* 函数名         : Int0()
* 函数功能		 : 外部中断0中断服务函数
* 输入            : 无
* 输出            : 无
*******************************************************************************/

void Int0() interrupt 0 using 1
{
	Delay10ms();
	if(K4==0)
	{
		while(!K4);//松手检测
		SetState=~SetState;//标志位取反
		SetPlace=0;
		DS3231_Init();//DS3231初始化
	}
}
/*******************************************************************************
* 函数名         : Delay10ms()
* 函数功能		 : 延迟函数,延时10ms
* 输入            : 无
* 输出            : 无
*******************************************************************************/
void Delay10ms(void)   //Îó²î 0us
{
    unsigned char a,b,c;
    for(c=1;c>0;c--)
        for(b=38;b>0;b--)
            for(a=130;a>0;a--);
}
/**********************************************************************************





**********************************************************************************/
#ifndef __DS3231_H_
#define __DS3231_H_

//---包含头文件---//
#include<reg51.h>
#include<intrins.h>

//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint 
#define uint unsigned int
#endif

//---定义ds1302使用的IO口---//
sbit DS3231_IIC_SDA=P3^0;
sbit DS3231_IIC_SCL=P3^1;

//---定义全局函数---//                                                               //时基、走时函数
void DS3231_Read_time();                                                 //读取时间
void DS3231_write_time();                                                 //写入时间
void DS3231_Init();                                                                 //时间模块初始化

//---加入全局变量--//
extern uchar TIME[7];	//加入全局变量

#endif
/**********************************************************************************





**********************************************************************************/
#include"ds3231.h"

//---DS3231写入和读取时分秒的地址命令//
//---秒分时日月周年最低读写位;-------//
uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d}; 
uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
uchar code rtc_address[7]={0x00,0x01,0x02,0x04,0x05,0x03,0x06};//秒分时日月周年最低读写位
uchar RTC_Data[8];
uchar RTC_Data1[8];
uchar RTC_Set_ID;
bit T0_Flag;                                                                       
bit Open_Flag;                                                                     
bit shezhi_display_flag;
//---DS3231初始化时间格式为2021年6月28日星期一22点00分00秒---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
uchar TIME[7] = {0, 0, 0x22, 0x28, 0x06, 0x01, 0x21};

/*******************************************************************************
* 函数名         : Ds3231Write
* 函数功能		 : 向DS3231命令(地址+数据)
* 输入            : addr,dat
* 输出            : 无
*******************************************************************************/

void DS3231_IIC_delay()//IIC延迟函数
{
        _nop_();_nop_();_nop_();_nop_();
}

void DS3231_IIC_start()//起始信号
{   
     DS3231_IIC_SDA=1;
     DS3231_IIC_SCL=1;
     DS3231_IIC_delay();
     DS3231_IIC_SDA=0;
     DS3231_IIC_delay();
     DS3231_IIC_SCL=0;
}

void DS3231_IIC_stop()//停止信号
{
    DS3231_IIC_SDA=0;
    DS3231_IIC_delay();
    DS3231_IIC_SCL=1;
    DS3231_IIC_delay();
    DS3231_IIC_SDA=1;
    DS3231_IIC_delay();
}

bit DS3231_IIC_Tack()//接收应答
{
    bit ack;
    DS3231_IIC_SDA=1;
    DS3231_IIC_delay();
    DS3231_IIC_SCL=1;
    DS3231_IIC_delay();
    ack=DS3231_IIC_SDA;
    DS3231_IIC_delay();
    DS3231_IIC_SCL=0;
    DS3231_IIC_delay();
    return ack;
}

void DS3231_IIC_write_byte(uchar Data)//写入数据函数
{
        uchar i;
        for(i=0;i<8;i++)
        {
                if(Data&0x80)
                DS3231_IIC_SDA=1;
                else
                DS3231_IIC_SDA = 0;
                DS3231_IIC_delay();
                DS3231_IIC_SCL=1;
                DS3231_IIC_delay();
                DS3231_IIC_SCL=0;
                DS3231_IIC_delay();
                Data=Data<<1;
        }
}

uchar DS3231_IIC_read_byte()//读取数字函数
{
    uchar i;
    uchar Data;      
    for(i=0;i<8;i++)
    {
        DS3231_IIC_SCL=1;
        DS3231_IIC_delay();
        Data=Data<<1;
        DS3231_IIC_delay();
      
        if(DS3231_IIC_SDA)
        Data=Data|0x01;
        DS3231_IIC_SCL=0;
        DS3231_IIC_delay();
    }
    return Data;
}

void DS3231_IIC_single_byte_write(uchar Waddr,uchar Data)//写入数据函数
{
    DS3231_IIC_start();
    DS3231_IIC_write_byte(0xd0);
    DS3231_IIC_Tack();
    DS3231_IIC_write_byte(Waddr);
    DS3231_IIC_Tack();
    DS3231_IIC_write_byte(Data);
    DS3231_IIC_Tack();
    DS3231_IIC_stop();
}

uchar DS3231_IIC_single_byte_read(uchar Waddr)//读取数字函数
{
    uchar Data;
    DS3231_IIC_start();
    DS3231_IIC_write_byte(0xd0);
    DS3231_IIC_Tack();
    DS3231_IIC_write_byte(Waddr);
    DS3231_IIC_Tack();
    DS3231_IIC_stop();
    DS3231_IIC_start();
    DS3231_IIC_write_byte(0xd1);
    DS3231_IIC_Tack();
    Data=DS3231_IIC_read_byte();
    DS3231_IIC_delay();
    DS3231_IIC_stop();
    return Data;
}

void DS3231_Read_time()//读取时间
{
    uchar i,tmp,tmp1,tmp2;         
    for(i=0;i<7;i++)
    {
            tmp = DS3231_IIC_single_byte_read(rtc_address[i]);
            tmp1 = tmp/16;
            tmp2 = tmp%16;
                TIME[i]=tmp1*10+tmp2;
    }  
}

void DS3231_write_time()//写入时间
{
    uchar i,tmp;
    for(i=0;i<8;i++)
    {      
        tmp=RTC_Data[i]/10;//BCD??
        RTC_Data1[i]=RTC_Data[i]%10;
        RTC_Data1[i]=RTC_Data1[i]+tmp*16;
    }
    for(i=0;i<7;i++)
    {
        DS3231_IIC_single_byte_write(rtc_address[i],RTC_Data1[i]);
    }
    DS3231_IIC_single_byte_write(0x0e,0x0c);
}

void DS3231_Init()//DS3231初始化函数
{
		uchar n;
    DS3231_IIC_SDA=1;
    DS3231_IIC_SCL=1;
    DS3231_IIC_single_byte_write(0x0e,0x0c);
		for (n=0; n<7; n++)//дÈë7¸ö×Ö½ÚµÄʱÖÓÐźţº·ÖÃëʱÈÕÔÂÖÜÄê
	{
		DS3231_IIC_single_byte_write(rtc_address[n],TIME[n]);	
	}
	DS3231_IIC_single_byte_write(0x8E,0x80);		 //´ò¿ªÐ´±£»¤¹¦ÄÜ
}
/**********************************************************************************





**********************************************************************************/
#ifndef __LCD_H_
#define __LCD_H_
/**********************************
当使用的是4位数据传输的时候定义,
使用8位取消这个定义
**********************************/
//#define LCD1602_4PINS

/**********************************
包含头文件
**********************************/
#include<reg51.h>

//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint 
#define uint unsigned int
#endif

/**********************************
PIN口定义
**********************************/
#define LCD1602_DATAPINS P2
sbit LCD1602_E=P0^5;
sbit LCD1602_RW=P0^6;
sbit LCD1602_RS=P0^7;

/**********************************
函数声明
**********************************/
/*在51单片机12MHZ时钟下的延时函数*/
void Lcd1602_Delay1ms(uint c);   //误差 0us
/*LCD1602写入8位命令子函数*/
void LcdWriteCom(uchar com);
/*LCD1602写入8位数据子函数*/	
void LcdWriteData(uchar dat)	;
/*LCD1602初始化子程序*/		
void LcdInit();						  

#endif
/**********************************************************************************





**********************************************************************************/
#include"lcd.h"

/*******************************************************************************
* 函 数 名         : Lcd1602_Delay1ms
* 函数功能		   : 延时函数,延时1ms
* 输    入         : c
* 输    出         : 无
* 说    名         : 该函数是在12MHZ晶振下,12分频单片机的延时。
*******************************************************************************/

void Lcd1602_Delay1ms(uint c)   //误差 0us
{
    uchar a,b;
	for (; c>0; c--)
	{
		 for (b=199;b>0;b--)
		 {
		  	for(a=1;a>0;a--);
		 }      
	}
    	
}

/*******************************************************************************
* 函 数 名         : LcdWriteCom
* 函数功能		   : 向LCD写入一个字节的命令
* 输    入         : com
* 输    出         : 无
*******************************************************************************/
#ifndef 	LCD1602_4PINS	 //当没有定义这个LCD1602_4PINS时
void LcdWriteCom(uchar com)	  //写入命令
{
	LCD1602_E = 0;     //使能
	LCD1602_RS = 0;	   //选择发送命令
	LCD1602_RW = 0;	   //选择写入
	
	LCD1602_DATAPINS = com;     //放入命令
	Lcd1602_Delay1ms(1);		//等待数据稳定

	LCD1602_E = 1;	          //写入时序
	Lcd1602_Delay1ms(5);	  //保持时间
	LCD1602_E = 0;
}
#else 
void LcdWriteCom(uchar com)	  //写入命令
{
	LCD1602_E = 0;	 //使能清零
	LCD1602_RS = 0;	 //选择写入命令
	LCD1602_RW = 0;	 //选择写入

	LCD1602_DATAPINS = com;	//由于4位的接线是接到P0口的高四位,所以传送高四位不用改
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	 //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;

//	Lcd1602_Delay1ms(1);
	LCD1602_DATAPINS = com << 4; //发送低四位
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	 //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 数 名         : LcdWriteData
* 函数功能		   : 向LCD写入一个字节的数据
* 输    入         : dat
* 输    出         : 无
*******************************************************************************/		   
#ifndef 	LCD1602_4PINS		   
void LcdWriteData(uchar dat)			//写入数据
{
	LCD1602_E = 0;	//使能清零
	LCD1602_RS = 1;	//选择输入数据
	LCD1602_RW = 0;	//选择写入

	LCD1602_DATAPINS = dat; //写入数据
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;   //写入时序
	Lcd1602_Delay1ms(5);   //保持时间
	LCD1602_E = 0;
}
#else
void LcdWriteData(uchar dat)			//写入数据
{
	LCD1602_E = 0;	  //使能清零
	LCD1602_RS = 1;	  //选择写入数据
	LCD1602_RW = 0;	  //选择写入

	LCD1602_DATAPINS = dat;	//由于4位的接线是接到P0口的高四位,所以传送高四位不用改
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	  //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;

	LCD1602_DATAPINS = dat << 4; //写入低四位
	Lcd1602_Delay1ms(1);

	LCD1602_E = 1;	  //写入时序
	Lcd1602_Delay1ms(5);
	LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 数 名       : LcdInit()
* 函数功能		 : 初始化LCD屏
* 输    入       : 无
* 输    出       : 无
*******************************************************************************/		   
#ifndef		LCD1602_4PINS
void LcdInit()						  //LCD初始化子程序
{
 	LcdWriteCom(0x38);  //开显示
	LcdWriteCom(0x0c);  //开显示不显示光标
	LcdWriteCom(0x06);  //写一个指针加1
	LcdWriteCom(0x01);  //清屏
	LcdWriteCom(0x80);  //设置数据指针起点
}
#else
void LcdInit()						  //LCD初始化子程序
{
	LcdWriteCom(0x32);	 //将8位总线转为4位总线
	LcdWriteCom(0x28);	 //在四位线下的初始化
	LcdWriteCom(0x0c);  //开显示不显示光标
	LcdWriteCom(0x06);  //写一个指针加1
	LcdWriteCom(0x01);  //清屏
	LcdWriteCom(0x80);  //设置数据指针起点
}
#endif

效果如下:

DS3231高精度时钟,LCD1602显示,QXmini151版本「建议收藏」

 

 

 

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/129315.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 计算机原码反码补码怎么算_-35的原码反码补码

    计算机原码反码补码怎么算_-35的原码反码补码最近花了点时间对计算机的原码,反码和补码进行了研究,对为什么要有反码和补码以及他们这么设计的原因有了一定的理解机器数一个数在计算机中的表现形式叫做机器数,这个数有正负之分,在计算机中用一个数的最高位(符号位)用来表示它的正负,其中0表示正数,1表示负数。例如正数7,在计算机中用一个8位的二进制数来表示,是00000111,而负数-7,则用10000111表示,这里的00000111和1…

  • GOland2021 激活码破解方法

    GOland2021 激活码破解方法,https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • java入门编程(菜鸟教程)

    java入门编程(菜鸟教程)1.创建一个java程序的步骤a打开editplus软件,选择左上角的file选项,在弹出来的菜单中选择new然后再从弹出来的菜单中选择normaltextb按住ctrl+s快捷键,保存。1选择要保存的位置2给文件命名(以大写的字母开头)3选择文件的后缀,以.java后缀结尾c进行代码的编写,所有字符我们必须都是英文输入状态下的d打开控制台(win+r在弹出左下角的命令行中输入cmd)e找到java源文件的位置,我们使用cd命令定位到我们源文件的文件夹(我们可以在打开的源文件文件夹地址栏

  • 创建线程池的方法_java引用就是对象本身

    创建线程池的方法_java引用就是对象本身创建线程池的方法一、创建线程池的三种方法Executors.newSingleThreadExecutor();//单个线程Executors.newFixedThreadPool(5);//创建一个固定的线程池Executors.newCachedThreadPool();//创建一个可伸缩的线程池1.newSingleThreadExecutorimportjava.util.concurrent.ExecutorService;importjava.util.concurr

  • 激活pycharm方法(采用激活码激活)

    激活pycharm方法(采用激活码激活)1.在C:\Windows\System32\drivers\etc目录下hosts文件中最后一行加入:0.0.0.0account.jetbrains.com2.打开PyCharm选择Activationcode激活,然后复制下面的激活码点击激活。K71U8DBPNE-eyJsaWNlbnNlSWQiOiJLNzFVOERCUE5FIiwibGljZW5zZWVOYW1lIjoi…

    2022年10月22日
  • Ntp校时客户端小工具

    Ntp校时客户端小工具Ntp校对时间是常用的计算机时间同步的方式之一,但是网上偏偏下载不到一个不带广告,且操作简单暴力的软件,其实我要的功能无非就是1:开机自动校对时间2:每隔一段时间校对时间3:可配置ntp服务器地址和校对间隔但是就是找不到一款合适自己用的工具,无奈啊,只好自己手写一个配置文件是ini,一看就懂软件下载地址:https://download.csdn.net/download/li…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号