×
单片机 > 单片机程序设计 > 详情

PIC单片机之DS1302时钟

发布时间:2020-12-23 发布时间:
|

大家好,通过前一期的学习,我们已经对ICD2 仿真烧写器和增强型PIC 实验板的使用方法及学习方式有所了解与熟悉,学会了如何用单片机来控制发光管、继电器、蜂鸣器、按键、数码管、RS232串口、步进电机、温度传感器、I2C 总线、SPI 总线等资源,体会到了学习板的易用性与易学性,这一期我们将介绍市面上常见的时钟芯片DS1302 的应用。


一、DS1302时钟芯片简介


DS1302 是DALLAS 公司推出的涓流充电时钟芯片,内含一个实时时钟/ 日历和31 字节静态RAM,可以通过串行接口与单片机进行通信。实时时钟/ 日历电路提供秒、分、时、日、星期、月、年的信息,每个月的天数和闰年的天数可自动调整,时钟操作可通过AM/PM 标志位决定采用24 或12 小时时间格式。DS1302 与单片机之间能简单地采用同步串行的方式进行通信,仅需三根I/O 线:复位(RST)、I/O 数据线、串行时钟(SCLK)。时钟/RAM 的读/写数据以一字节或多达31 字节的字符组方式通信。


DS1302 工作时功耗很低,保持数据和时钟信息时,功耗小于1mW。


1. DS1302 的内部结构


DS1302 的外部引脚功能说明如图1 所示。



图1 DS1302封装图


DS1302 的内部结构如图2 所示,主要组成部分为:移位寄存器、控制逻辑、振荡器、实时时钟以及RAM。虽然数据分成两种,但是对单片机的程序而言,其实是一样的,就是对特定的地址进行读写操作。



图2 DS1302的内部结构图


DS1302 含充电电路,可以对作为后备电源的可充电电池充电,并可选择充电使能和串入的二极管数目,以调节电池充电电压。不过对我们目前而言,最需要熟悉的是和时钟相关部分的功能,对于其它参数请参阅数据手册。


2. DS1302 的工作原理


DS1302 工作时为了对任何数据传送进行初始化,需要将复位脚(RST)置为高电平且将8 位地址和命令信息装入移位寄存器。数据在时钟(SCLK)的上升沿串行输入,前8 位指定访问地址,命令字装入移位寄存器后,在之后的时钟周期,读操作时输出数据,写操作时输出数据。时钟脉冲的个数在单字节方式下为8+8(8 位地址+8 位数据),在多字节方式下为8 加最多可达248 的数据。


3. DS1302 的寄存器和控制命令


对DS1302 的操作就是对其内部寄存器的操作,DS1302 内部共有12 个寄存器,其中有7 个寄存器与日历、时钟相关,存放的数据位为BCD 码形式。


此外,DS1302 还有年份寄存器、控制寄存器、充电寄存器、时钟突发寄存器及与RAM 相关的寄存器等。


时钟突发寄存器可一次性顺序读写除充电寄存器以外的寄存器。日历、时间寄存器及控制字如表1 所示。


表1 日历、时钟寄存器与控制字对照表



最后一位RD/W 为“0”时表示进行写操作,为“1”时表示读操作。


DS1302 内部寄存器列表如表2 所示。


DS1302 内部的RAM 分为两类,一类是单个RAM 单元,共31 个,每个单元为一个8 位的字节,其命令控制字为COH~FDH,其中奇数为读操作,偶数为写操作;再一类为突发方式下的RAM,此方式下可一次性读写所有的RAM 的31 个字节,命令控制字为FEH(写)、FFH(读)。


表2 DS14302内部主要寄存器分布表



我们现在已经知道了控制寄存器和RAM 的逻辑地址,接着就需要知道如何通过外部接口来访问这些资源。单片机是通过简单的同步串行通讯与DS1302通讯的,每次通讯都必须由单片机发起,无论是读还是写操作,单片机都必须先向DS1302 写入一个命令帧,最高位BIT7 固定为1,BIT6 决定操作是针对RAM 还是时钟寄存器,接着的5 个BIT 是RAM或时钟寄存器在DS1302 的内部地址,最后一个BIT表示这次操作是读操作抑或是写操作。


物理上,DS1302 的通讯接口由3 个口线组成,即RST,SCLK,I/O。其中RST 从低电平变成高电平启动一次数据传输过程,SCLK 是时钟线,I/O 是数据线。具体的读写时序参考图3,但是请注意,无论是哪种同步通讯类型的串行接口,都是对时钟信号敏感的,而且一般数据写入有效是在上升沿,读出有效是在下降沿(DS1302 正是如此的,但是在芯片手册里没有明确说明),如果不是特别确定,则把程序设计成这样:平时SCLK 保持低电平,在时钟变动前设置数据,在时钟变动后读取数据,即数据操作总是在SCLK 保持为低电平的时候,相邻的操作之间间隔有一个上升沿和一个下降沿。



图3 DS1302的命令字结构


通过前文的原理介绍,我们已经对DS1302 时钟芯片的特性以及工作原理有了大致地了解,但当我们拿到一个时钟器件时要正确地应用它还是一时不知如何下手,比如我们要做一个简单的时间显示,需要怎么办呢?首先,时钟芯片与单片机的连接非常简单,一般来说,我们只需要将IIC 器件的复位“RST”、数据“I/O”、时钟“SCLK”端与单片机的I/O 口相连,就可以进行时间、日期数据的写入或读取了。现在,我们来一起看一个使用DS1302 做时间显示的例子,通过一个实例,相信会给大家带来一个感性的认识。


首先, 我们来看一下增强型PIC 实验板上DS1302 器件的接口电路,因为我们需要将软件和硬件相结合进行考虑如何来编程,完成该实验的硬件原理图如图4 所示,U2 为实验板上DS1302 芯片,“I/O”


与单片机的RB5 口相连,“SCLK”与单片机RB6 相连,“RST”与单片机RB7 相连,七段数码管D5、D7、D8 组成了显示单元,字形码的数据通过RC 口送入,各数码管的显示片选信号分别不同的RA 口进行控制。



图4 硬件原理图


对于单机软件的编程,我们使用MPLab IDE 软件来进行C 语言编程,它是我们的编程环境,同时我们可以通过使用ICD2 仿真烧写器和增强型PIC 实验板连接进行程序的仿真调试和烧写步骤,具体的操作步骤,我们已经在前几期做了详细的说明和介绍,在此就不再重复说明,读者朋友可以参阅以前的文章或直接登陆我们的网站查看资料。现在我们可以输入程序代码进行调试了,我们在MPLab IDE 软件中新建工程,加入源程序代码,同时进行芯片型号的选择和配置位的设置,我们实验所用的芯片型号为PIC16F877A。编写的程序代码如下,其中程序流程图如图5 所示,实际运行效果如图6 所示。



图5 软件流程



图6 DS1302 实验演示图




二、软件代码


/*************************************************/


/*DS1302 读写演示程序 */


/* 目标器件:PIC16F877A */


/* 晶振:4.0MHZ */


/* 编译环境:MPLAB V7.51 */


/**************************************************/


#include


#define i_o RB5


#define sclk RB6


#define rst RB7


unsigned char time_rx @ 0x30;


// 定义接收寄存器


static volatile bit time_rx7 @ (unsigned)&time_rx*8+7;


// 接收寄存器的最高位


/***************************************************


子函数定义


**************************************************/


void port_init(); // 申明引脚初始化函数


void ds1302_init(); // 申明DS1302 初始化函数


void set_time(); // 申明设置时间函数


void get_time(); // 申明读取时间函数


void display(); // 申明显示函数


void time_write_1(unsigned char time_tx);


// 申明写一个字节函数


unsigned char time_read_1();


// 申明读一个字节函数


void delay(); // 申明延时函数


/***************************************************


时间和日期存放表


**************************************************/


const char table[]={0x00,0x30,0x12,0x8,0x3,0x06,0x06,0x00};


char table1[7];


/**************************************************


共阴LED 段码表


**************************************************/


const char table2[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};


void main()


{


port_init(); // 调用引脚初始化函数


TRISC =0x00;


ds1302_init(); // 调用DS1302 初始化函数


set_time(); // 调用设置时间函数


while(1)


{


get_time(); // 调用取时间函数


display(); // 调用显示函数


}


}


void ds1302_init() // DS1302 初始化函数子程序


{


sclk=0; // 拉低时钟信号


rst =0; // 复位DS1302


rst=1; // 使能DS1302


time_write_1(0x8e); // 发控制命令


time_write_1(0); // 允许写DS1302


rst=0; // 复位


}


void set_time() // 设置时间函数子程序


{


int i; // 定义循环变量


rst=1; // 使能DS1302


time_write_1(0xbe); // 时钟多字节写命令


for(i=0;i<8;i++) // 连续写8 个字节数据


{


time_write_1(table[i]); // 调用写一个字节函数


delay();


}


rst=0; // 复位


}


void get_time() // 读取时间函数子程序


{


int i; // 设置循环变量


rst=1; // 使能DS1302


time_write_1(0xbf); // 发送多字节读取命令


for(i=0;i<7;i++) // 连续读取7 个字节数据


{


table1[i]=time_read_1();


// 调用读取1 个字节数据的函数


delay();


}


rst=0; // 复位DS1302


}


void time_write_1(unsigned char time_tx)


{


int j; // 设置循环变量


for(j=0;j<8;j++) // 连续写8bit


{


i_o=0; // 先设置数据为0


sclk=0; // 时钟信号拉低


if(time_tx&0x01) // 判断待发送的数据位是0 或1


{


i_o=1; // 待发送数据位是1


}


time_tx=time_tx》1; // 待发送的数据右移1 位


sclk=1; // 拉高时钟信号


}


sclk=0; // 写完一个字节,拉低时钟信号


}


unsigned char time_read_1()


{


int j; // 设置循环变量


TRISB5=1; // 设置数据口方向为输入


for(j=0;j<8;j++) // 连续读取8bit


{


sclk=0; // 拉低时钟信号


time_rx=time_rx》1; // 接收寄存器右移1 位


time_rx7=i_o;


// 把接收到的数据放到接收


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
MSP432学习笔记:ADC14