本次学习DS1302时钟芯片.
DS1302芯片采用SPI 3线通信, 分别是SCLK, I/O,CE三根线.
由于比赛时给出DS1302的SPI协议的文件, 所以这次重点介绍其寄存器.
DS1302有一个控制寄存器,12个日历.时钟寄存器和31个RAM.可读写.
控制寄存器:
如果R/W为0为则是写模式, 如果R/W为1则是读模式.
日历.时钟寄存器:
(1). 数据在寄存器中以BCD码形式存在
(2). 小时寄存器的D7为12小时制和24小时制的选择位,为1时是12小时制,为0时是24小时制; D5的1是上午,0是下午; 当24小时制时,D5,D4为小时的十位
(3). 秒寄存器中的CH位是时钟暂停位,当为1时钟暂停, 为0时钟开始
(4). 写保护寄存器中的WP为写保护位,当WP=1,写保护,当WP=0未写保护,当对日历、时钟寄存器或片内RAM进行写时WP应清零,当对日历、时钟寄存器或片内RAM进行读时WP一般置1。
(5). 慢充电寄存器的TCS位为控制慢充电的选择,当它为1010才能使慢充电工作。DS为二极管选择位。DS为01选择一个二极管,DS为10选择二个二极管,DS为11或00充电器被禁止,与TCS无关。RS用于选择连接在VCC2与VCC1之间的电阻,RS为00,充电器被禁止,与TCS无关,电阻选择情况见表.
片内RAM不介绍.
下面介绍程序流程:
首先我们利用竞赛时给的ds1302.c,进行DS1302的初始化,也就是关闭写保护寄存器, 并在日历寄存器里面写入命令和初始化时间.然后开启写保护, 最后再读取日历寄存器中的时间,并再数码管上显示:
贴上代码ds1302.c:
#include "ds1302.h"
uchar Write_Ds1302_addr[]={0x80,0x82,0x84}; //秒分时
uchar Read_Ds1302_addr[]={0x81,0x83,0x85}; //秒分时
uchar TIME[7] = {0, 0x12, 0x12}; //秒分时
/********************************************************************/
/*单字节写入一字节数据*/
void Write_Ds1302_Byte(unsigned char dat)
{
unsigned char i;
SCK = 0;
for (i=0;i<8;i++)
{
if (dat & 0x01) // 等价于if((addr & 0x01) ==1)
{
SDA_SET; //#define SDA_SET SDA=1 /*电平置高*/
}
else
{
SDA_CLR; //#define SDA_CLR SDA=0 /*电平置低*/
}
SCK_SET;
SCK_CLR;
dat = dat >> 1;
}
}
/********************************************************************/
/*单字节读出一字节数据*/
unsigned char Read_Ds1302_Byte(void)
{
unsigned char i, dat=0;
for (i=0;i<8;i++)
{
dat = dat >> 1;
if (SDA_R) //等价于if(SDA_R==1) #define SDA_R SDA /*电平读取*/
{
dat |= 0x80;
}
else
{
dat &= 0x7F;
}
SCK_SET;
SCK_CLR;
}
SDA_CLR; //以下为DS1302复位的稳定时间,必须的。
return dat;
}
/********************************************************************/
/*向DS1302 单字节写入一字节数据*/
void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat)
{
RST_CLR; /*RST脚置低,实现DS1302的初始化*/
SCK_CLR; /*SCK脚置低,实现DS1302的初始化*/
RST_SET; /*启动DS1302总线,RST=1电平置高 */
addr = addr & 0xFE;
Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是写操作,写之前将最低位置零*/
Write_Ds1302_Byte(dat); /*写入数据:dat*/
RST_CLR; /*停止DS1302总线*/
}
/********************************************************************/
/*从DS1302单字节读出一字节数据*/
unsigned char Ds1302_Single_Byte_Read(unsigned char addr)
{
unsigned char temp;
RST_CLR; /*RST脚置低,实现DS1302的初始化*/
SCK_CLR; /*SCK脚置低,实现DS1302的初始化*/
RST_SET; /*启动DS1302总线,RST=1电平置高 */
addr = addr | 0x01;
Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是读操作,写之前将最低位置高*/
temp=Read_Ds1302_Byte(); /*从DS1302中读出一个字节的数据*/
RST_CLR; /*停止DS1302总线*/
return temp;
}
void DS1302Init()
{
uchar i;
Ds1302_Single_Byte_Write(0x8e,0x00); //0x00关闭写保护
for (i=0;i<3;i++)
{
Ds1302_Single_Byte_Write(Write_Ds1302_addr[i],TIME[i]);
}
Ds1302_Single_Byte_Write(0x8e,0x80); //0x80写保护
}
void DS1302ReadTime()
{
uchar i;
for (i=0;i<3;i++)
{
TIME[i]=Ds1302_Single_Byte_Read(Read_Ds1302_addr[i]);
}
}
ds1302.h:
#ifndef __DS1302_H__
#define __DS1302_H__
#include<reg52.h>
#include<intrins.h>
/********************************************************************/
sbit SCK=P1^7;
sbit SD=P2^3;
sbit RST=P1^3;
typedef unsigned char uchar;
typedef unsigned int uint;
/********************************************************************/
/*复位脚*/
#define RST_CLR RST=0 /*电平置低*/
#define RST_SET RST=1 /*电平置高*/
/*双向数据*/
#define SDA_CLR SD=0 /*电平置低*/
#define SDA_SET SD=1 /*电平置高*/
#define SDA_R SD /*电平读取*/
/*时钟信号*/
#define SCK_CLR SCK=0 /*时钟信号*/
#define SCK_SET SCK=1 /*电平置高*/
/********************************************************************/
#define ds1302_sec_addr 0x80 //秒数据地址
#define ds1302_min_addr 0x82 //分数据地址
#define ds1302_hr_addr 0x84 //时数据地址
#define ds1302_date_addr 0x86 //日数据地址
#define ds1302_month_addr 0x88 //月数据地址
#define ds1302_day_addr 0x8A //星期数据地址
#define ds1302_year_addr 0x8C //年数据地址
#define ds1302_control_addr 0x8Ee //写保护命令字单元地址
#define ds1302_charger_addr 0x90 //涓电流充电命令字地址
#define ds1302_clkburst_addr 0xBE //日历、时钟突发模式命令字地址
/********************************************************************/
/********************************************************************/
/*单字节写入一字节数据*/
extern void Write_Ds1302_Byte(unsigned char dat);
/********************************************************************/
/*单字节读出一字节数据*/
extern unsigned char Read_Ds1302_Byte(void);
/********************************************************************/
/********************************************************************/
/*向DS1302单字节写入一字节数据*/
extern void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat);
/********************************************************************/
/*从DS1302单字节读出一字节数据*/
extern unsigned char Ds1302_Single_Byte_Read(unsigned char addr);
extern uchar TIME[7];
void DS1302ReadTime();
void DS1302Init();
#endif
/********************************************************************/
// END FILE
/********************************************************************/
下面是main.c:
#include <reg52.h>
#include "ds1302.h"
sbit BUZZ=P0^6;
sbit RELAY=P0^4;
uchar discom;
uchar DisplayData[8];
uchar code table[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
void Display();
void TimePros();
void CloseBUZZ();
void CloseLED();
void main()
{
DS1302Init();
CloseBUZZ();
CloseLED();
while (1)
{
TimePros();
Display();
}
}
void CloseBUZZ()
{
BUZZ=0;
RELAY=0;
P2=(P2&0x1f)|0xa0;
P2&=0x1f;
}
void CloseLED()
{
P0=0xff;
P2=(P2&0x1f)|0x80;
P2&=0x1f;
}
void TimePros()
{
DS1302ReadTime();
DisplayData[0] = table[TIME[2]/16]; //时
DisplayData[1] = table[TIME[2]&0x0f];
DisplayData[2] = 0xbf;
DisplayData[3] = table[TIME[1]/16]; //分
DisplayData[4] = table[TIME[1]&0x0f];
DisplayData[5] = 0xbf;
DisplayData[6] = table[TIME[0]/16]; //秒
DisplayData[7] = table[TIME[0]&0x0f];
}
void Display()
{
P0=0xff;
P2=(P2&0x1f)|0xe0;
P2&=0x1f;
P0=(1<<discom);
P2=(P2&0x1f)|0xc0;
P2&=0x1f;
P0=DisplayData[discom];
P2=(P2&0x1f)|0xe0;
P2&=0x1f;
discom++;
if (discom==8)
discom=0;
}
实现的效果为:在数码管上从 12:12:00开始显示时间.