实时时钟DS1302实验
实验现象
通过DS1302的读取获取年,月,日,星期,时,分,秒的值,然后串口显示在PC上
通过4个按键设定当前的时间
按键1(设置):按一下进入设置状态,在按下退出设置状态
按键2(切换):按一下切换一种设置变量,分别可以设置年,月,日,星期,时,分,秒
按键3(加1):可以对当前的设置变量进行加1操作
按键4(减1):可以对当前的设置变量进行减1操作
理论学习
- DS1302 是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.0V~5.5V。采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。DS1302内部有一个31×8的用于临时性存放数据的RAM寄存器。DS1302是DS1202的升级产品,与DS1202兼容,但增加了主电源/后备电源双电源引脚,同时提供了对后备电源进行涓细电流充电的能力。
- DS1302的引脚排列,其中Vcc2为主电源,VCC1为后备电源。在主电源关闭的情况下,也能保持时钟的连续运行。DS1302由Vcc1或Vcc2两者中的较大者供电。当Vcc2大于Vcc1+0.2V时,Vcc2给DS1302供电。当Vcc2小于Vcc1时,DS1302由Vcc1供电。X1和X2是振荡源,外接32.768kHz晶振。RST是复位/片选线,通过把RST输入驱动置高电平来启动所有的数据传送。RST输入有两种功能:首先,RST接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST提供终止单字节或多字节数据传送的方法。当RST为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。如果在传送过程中RST置为低电平,则会终止此次数据传送,I/O引脚变为高阻态。上电运行时,在Vcc>2.0V之前,RST必须保持低电平。只有在SCLK为低电平时,才能将RST置为高电平。I/O为串行数据输入输出端(双向),后面有详细说明。SCLK为时钟输入端。 下图为DS1302的引脚功能图:
原理图
代码编写
#define RST 7
#define SCLK 6
#define IO 5
//#define L(item) digitalWrite((item),LOW)
//#define H(item) digitalWrite((item),HIGH)
#define uchar unsigned char
void setup() {
pinMode(RST,OUTPUT);
pinMode(SCLK,OUTPUT);
pinMode(IO,OUTPUT);
Serial.begin(9600);
attachInterrupt(0, settm, FALLING );
}
void writeData(unsigned char addr,unsigned char dat){
pinMode(IO,OUTPUT);
digitalWrite(RST,LOW); //下拉低,再拉高
digitalWrite(SCLK,LOW) ; //SCLK的上升沿, 芯片会读取IO端口
delayMicroseconds(1);
digitalWrite(RST,HIGH);
int i;
for(i =0;i<8;i++){
digitalWrite(SCLK,LOW);
digitalWrite(IO, addr&1);
addr =addr>>1;
digitalWrite(SCLK,HIGH);
delayMicroseconds(1);
}
for(i =0;i<8;i++){
digitalWrite(SCLK,LOW);
digitalWrite(IO, dat&1);
dat =dat>>1;
digitalWrite(SCLK,HIGH);
delayMicroseconds(1);
}
digitalWrite(RST,LOW);
}
uchar readData(uchar addr){
addr = addr | 1; //读操作最低位置为1
pinMode(IO,OUTPUT);
digitalWrite(RST,LOW); //下拉低,再拉高
digitalWrite(SCLK,LOW) ; //SCLK的上升沿, 芯片会读取IO端口
delayMicroseconds(1);
digitalWrite(RST,HIGH);
int i;
for(i =0;i<8;i++){
digitalWrite(SCLK,LOW);
digitalWrite(IO, addr&1);
addr =addr>>1;
digitalWrite(SCLK,HIGH);
delayMicroseconds(1);
}
pinMode(IO,INPUT);
int dat = 0;
for(i =0;i<8;i++){
digitalWrite(SCLK,LOW);
delayMicroseconds(10);
uchar b = digitalRead(IO);
dat = dat >>1; //先向右平移
dat = dat | (b<<7); //将所得放入最高位
digitalWrite(SCLK,HIGH);
delayMicroseconds(1);
}
digitalWrite(RST,LOW);
return dat ;
}
#define SECOND 0x80
#define MIN 0x82
#define HOUR 0x84
#define DAY 0x86
#define MONTH 0x88
#define YEAR 0x8C
#define WEEK 0x8A
void writeTimeUnit(uchar TYPE,uchar data){
uchar high = data / 10;
uchar low = data % 10;
uchar d = ((data /10) << 4) | (data % 10);
writeData(TYPE,data);
}
uchar readTimeUnit(uchar TYPE){
uchar r = readData(TYPE);
r = 10*(r >> 4)+ (r & 0xf);
return r;
}
void writeAllTm(uchar tm[]){
uchar s = SECOND;
for(uchar i=0;i<5;i++){
writeTimeUnit(s,tm[5-i]);
s+=2;
}
writeTimeUnit(YEAR,tm[0]);
}
void readAllTm(uchar tm[]){
uchar s = SECOND;
for(uchar i=0;i<5;i++){
tm[5-i] = readTimeUnit(s);
s+=2;
}
tm[0] = readTimeUnit(YEAR);
tm[6] = readTimeUnit(WEEK);
}
void printTm(uchar tm[]){
Serial.print(tm[0]);
Serial.print("-");
Serial.print(tm[1]);
Serial.print("-");
Serial.print(tm[2]);
Serial.print(" ");
Serial.print(tm[3]);
Serial.print(":");
Serial.print(tm[4]);
Serial.print(":");
Serial.print(tm[5]);
Serial.print(" week ");
Serial.print(tm[6]);
Serial.println();
}
uchar st = 0;
void loop() {
uchar tm[7] = {0};
readAllTm(tm);
printTm(tm);
delay(1000);
}
void settm()//中断函数
{
uchar tm[] = {11,12,13,4,5,6 ,0}; // 2011-12-22 3:4:1
Serial.println("set tm ...");
writeAllTm(tm);
}