DS1302电子时钟模块——树莓派

DS1302电子时钟模块——树莓派

DS1302电子时钟模块

结构

通俗地说,这就是一个电子表。时间存放在里面的寄存器中,我们需要读取或修改里面的内容。
具体应用如下图,右侧是DS1302模块,一共八个管腿儿。

  1. VCC1、VCC2都是供电电源,有一个是后备不隐藏电源(可充电纽扣电池),GND接地。
  2. X1、X2接一个32.768kHz的晶振。32768是215,分频15次后是1Hz,周期为1s。这个数也是工程师的实践经验。
  3. CE是一个输入信号,为高时才能进行读写操作。之前也被称作 RST ‾ \overline{\text{RST}} RST
  4. I/O是数据输入输出线。
  5. SCLK是串行时钟线,为输入。

在这里插入图片描述
仔细分析这八个管脚,会发现我们真正需要操作的只有CE、I/O、SCLK三条线。

逻辑

CE拉高允许数据进行传输,拉低禁止数据传输。
DS1302在时钟上升沿写入数据,在时钟下降沿输出数据。传输开始的第一个字节是写入的,称为命令字节(command byte)。而且不管输入输出,数据都是先发送最低有效位,即最低位。
命令字节如下图:
在这里插入图片描述
最高位固定为1。
第6位没搞懂什么意思,后面暂时使用0。
5-1位是要操作的寄存器地址。DS1302共有31个寄存器,从0到30。如果地址写入31即全1,是突发传输模式,写入一个命令字后,可以连续对所有寄存器操作。
第0位,表示是要进行读操作还是写操作。

单字节输入输出

即一次只对一个寄存器进行操作,需要一个命令字节+数据字节

  1. 单字节写入
    一个命令字节+一个准备写入的数据字节。每一位都是写入操作,所以需要16个上升沿(16个时钟周期)。在时钟上升前,准备好数据。
    在这里插入图片描述
  2. 单字节读取
    写入一个字节+读取一个字节。需要八个上升沿和八个下降沿,但是要注意中间是共用一个周期的,所以需要15个周期。在时钟沿下降后,进行数据的读取。
    在这里插入图片描述
  3. 时序
    在进行数据传输的时候,还需要参考官方手册的要求。一些信号的变化和保持,都需要符合要求。听一些课程讲单片机的指令是微秒级别的,这里不主动延时也符合要求。
    在这里插入图片描述在这里插入图片描述
  4. 寄存器
    对于时间的读取和设置,实际上只需要操作八个寄存器,如下图,从上到下对应的0-7号寄存器。每个字段的含义也已经标出来了。7号寄存器的WP是写保护位,如果需要修改寄存器内容时,一定要把这个位设置为0。0号寄存器CH(bit 7)是暂停标志,设置之后就不走秒了。3号寄存器的最高位表示是使用的是12小时计时还是24小时计时。其它字段看单词含义就很清楚了。
    另外,每个字段都是用BCD码表示的,实际效果相当于使用十六进制的字面值来表示10进制,所以使用时可以不用编写转换函数,按十六进制操作即可。
    在这里插入图片描述

树莓派准备

软件基础

需要使用到的函数:

//初始化函数,必须调用
int wiringPiSetup(void);
//设置管脚输入输出模式
void pinMode(int pin,int mode);
//设置管脚输出高低电平
void digitalWrite(int pin,int value);
//读取管脚的高低电平
int digitalRead(int pin);

设计和实现思路

简单地实现字节写入和字节读取的功能,从而实现设置时间和读取时间的功能。
实现按照时序图进行操作即可。

实际遇到的问题

  1. 读取数据和预期不相符
    接收字节的时候位操作不当,把最低位和最高位弄反了。
  2. 数据循环读取仅第一次值符合预期,其余值为0
    这个错误找了好久,最后才发现是读取数据的时候将管脚设置为输入模式后,没有将其恢复成输出模式,影响下一次数据的写入。
    所以要特别注意输入输出模式,最好在需要进行操作前对管脚进行一下设置。或者在操作后将管脚恢复成默认状态(这个容易忘…)。
  3. 时钟不走秒,停在一个数
    CH标志位为0但时钟就是不走秒,百度发现大概率是晶振的问题,经维修(物理掰动晶振)后正常。

附测试代码:

#include <wiringPi.h>
#include <stdio.h>

#define CLK 1
#define DAT 28 
#define CE 24

typedef unsigned char u8;

void init()
{
    wiringPiSetup();
    pinMode(CE,OUTPUT);
    pinMode(CLK,OUTPUT);
    pinMode(DAT,OUTPUT);

    digitalWrite(CE,LOW);
    digitalWrite(CLK,LOW);
}

u8 read_reg(u8 reg)
{
    u8 cmd=(reg<<1)|0x81;
    u8 temp;
    digitalWrite(CE,HIGH);
    for(int i=0;i<8;i++)
    {
		temp=cmd&0x1;
		cmd=cmd>>1;
		if(temp==1) digitalWrite(DAT,HIGH);
		else digitalWrite(DAT,LOW);
        digitalWrite(CLK,LOW);
		digitalWrite(CLK,HIGH);
    }
    pinMode(DAT,INPUT);
    for(int i=0;i<8;i++)
    {
        digitalWrite(CLK,LOW);
		if(digitalRead(DAT)==HIGH) temp|=0x1<<7;
		else temp|=0x0<<7;
        if(i!=7) temp=temp>>1;
        if(i!=7) digitalWrite(CLK,HIGH);
    }
    digitalWrite(CE,LOW);
    pinMode(DAT,OUTPUT);
    return temp;
}
u8 write_reg(u8 reg,u8 data)
{
    u8 cmd=(reg<<1)|0x80;
    u8 temp;
    digitalWrite(CE,HIGH);
    for(int i=0;i<8;i++)
    {
		temp=cmd&0x1;
		cmd=cmd>>1;
		if(temp==1) digitalWrite(DAT,HIGH);
		else digitalWrite(DAT,LOW);
        digitalWrite(CLK,LOW);
		digitalWrite(CLK,HIGH);
    }
    for(int i=0;i<8;i++)
    {
		temp=data&0x1;
		data=data>>1;
        if(temp==1) digitalWrite(DAT,HIGH);
		else digitalWrite(DAT,LOW);
        digitalWrite(CLK,LOW);
        digitalWrite(CLK,HIGH);
    }
    digitalWrite(CLK,LOW);
    digitalWrite(CE,LOW);
    return 0;
}

    
int main()
{
    init();
    int i;
    write_reg(7,0);
    
    write_reg(0,0x80);
    write_reg(6,0x21);
    write_reg(5,0x07);
    write_reg(4,0x11);
    write_reg(3,0x14);
    write_reg(2,0x20);
    write_reg(1,0x10);
    write_reg(0,0x1);

	while(1){
	    delay(1000);
	    for(int i=7;i>=0;i--)
	    {
		printf("%x:",read_reg(i));
	    }
	    printf("\n");
	}
    return 0;
}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值