51单片机第8篇章-实时时钟

51单片机第8篇章-实时时钟追求以通俗的语言让小白可以更容易上手学单片机,在此同时巩固知识(很多图片来自江科大和普中,作者也是学这个来的,只是通过自己的语言想把它复述出来)。 何为实时时钟 简单介绍 下图为其芯片结构图 (这种图

追求以通俗的语言让小白可以更容易上手学单片机,在此同时巩固知识(很多图片来自江科大和普中,作者也是学这个来的,只是通过自己的语言想把它复述出来)。

何为实时时钟

通过外接晶振以冲激的方式每隔固定时间给出高/低电平,从而使芯片有了计时计数的功能。本文章主要介绍实时时钟的一个芯片DS1302.

微信图片_20221118212457.png

简单介绍

下图为其芯片结构图

Snipaste_2022-11-18_21-26-02.png

  1. 这个芯片有两个vcc,引脚1的VCC为外接电源引脚;引脚8的VCC为芯片配的备用电源(可以在无外电源的情况下提供一定的工作能力,比如电脑关机了,但可能还能计时就是因为其含有备用电源)不过本项目用的实验板是没有配备备用电源,因此我们可以跳过,大概了解这个点就行。
    
  2. X1和X2外接的是晶振,其作用是提供固定频率(即每隔固定的时间会提供一个冲激使得这个芯片计时或者计数),也是这块芯片的独特之处。
    
  3. SCLK属于时序的范畴。其作用是帮助该芯片写读指令或者数据。当上升沿时为写,下降沿时为读。后面会详细讲。 
    
  4. CE也属于时序的范畴,当他为高电平时,启动时钟的读写功能,低电平时停止/闲置。
    
  5. I/O即数据的输入输出,包括地址码和数据码。
    

Snipaste_2022-11-18_21-39-38.png (这种图才是熟悉的感jio) 可知该芯片在单片机中占用的三个引脚分别为

P3_4 为I/O;
P3_5 为CE;
P3_6 为SLCK

也就是说在后面写代的码时候,你必定能看到这仨的出现

实时时钟用来干什么

做项目时我们常常会有时间上的处理,比如计时器。如果你想做个计时器,那你肯定不能少了时钟模块,可见其价值如此。

实现计时

记住51中,实现时钟的读写数据,就必须靠时序来实现

核心

控制寄存器

即我们输入命令,控制该芯片什么工作模式–开启/停止/读/写 Snipaste_2022-11-18_21-53-27.png 下图是上图的细化,在控制启动,读/写的基础上,加上了日历寄存器的选择,通过表中的输入地址码,我们可以控制时钟来寄存什么数据。 Snipaste_2022-11-18_21-56-23.png

日历寄存器

微信图片_20221118220519.png 看了图,你会晕,这些寄存器,上面不是也有吗?确实,你没有看错,确实再次出现了。不过这里的寄存器和上面的要区分开,这里的是数据的写入,上面的是模式的选择/或者你可以用选择寄存器地址来理解。

该图展示了取值范围,和位/值的输入及一些说明,值得注意的是,这里的数据写入是通过BCD码来键入的
0000~1001代表1~9,而四位一体的码0X?? 可保证了更大数值的输入。可输入00~99的数值。

控制时序

这是最最重要的,单看前面的,你也没办法入手,必须有个先后顺序才能切入问题。

Snipaste_2022-11-18_22-13-33.png 这里分为两种情况,够我们新手实现很多东西了,你想想:我们要实现计时,不就是给一个时间开始计时或者读取一个时间吗? 对于该时序图的解读如下

单字节写:
1.要在工作之前将CE置高电平,工作之后将CE置低电平(这就属于初始化的范畴了)。
2.看I/O左边是指地址的选择,我们选择了写并选择了哪个寄存器。右边为数据的输入
3.要实现输入(包括地址/数据),就必须一个一个来,且按照低位在先原则,每输入一个数,就给一个上升沿。代码上怎么理解呢?我们写一个值,然后将SCLK置1,给一个延时函数,此时已经输入了该位数据,再置0,便可以开始下一位的输入。
单字节读:
同上面的前两点
3.左边要输入,右边要读取(输出)。左边按照上面3的做法,输入工作模式(记得是读!!!),读到最后一位,上升沿下降后,再置高,再下降沿(这时才有数据的读取)。相当于空了一个下降沿。

我怎么利用实时时钟来做一些事情

小例子–使用DS1302实现时钟功能

主函数

#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"
#include "Delay.h"
unsigned char Second;unsigned char Min;
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);   
}
}

延时函数

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

DS1302写入和读取 要写的函数包括 设置时间,读取时间,输入,读取数据

  #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 char DS1302_Time[]={19,11,16,12,59,55,6};//输入的时间(以数组形式)
void DS1302_Init() {//初始化
        DS1302_CE=0;//把CE给清除状态,这里不是CE=1,我们将CE=1放在设置时间和读取时间那里就可,
DS1302_SCLK=0;//把SCLK清除状态
}
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;
}
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);}//获取数据通过IO,用并集
}
DS1302_CE=0;
DS1302_IO=0; 
return Data;
}
void DS1302_SetTime(void)//设置时间
{
DS1302_WriteByte(DS1302_WP,0x00);
DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);//写数字,将10进制转为BCD
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);
}

void DS1302_ReadTime(void)//获取时间
{
unsigned char Temp;
Temp=DS1302_ReadByte(DS1302_YEAR);
DS1302_Time[0]=Temp/16*10+Temp%16;//BCD码转化为10进制
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;
}

今天的文章51单片机第8篇章-实时时钟分享到此就结束了,感谢您的阅读。

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

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注