Playing with Raspberry Pi (22) - DS1302 Hardware Clock Practice

Playing with Raspberry Pi (22) - DS1302 Hardware Clock Practice

I don't know if you have noticed that when we use the computer, except for the first time we need to synchronize the time, that is, there is no network connection. After the power is turned off and restarted, the computer's time is still accurate. This is because there is a hardware clock module with its own power supply inside the computer host. After the current time is written into the module when synchronizing the time, the hardware clock module will automatically maintain the accurate current time. There is no hardware clock module inside the Raspberry Pi itself, but in some non-networked demand scenarios, we need to accurately record the current date and time. For example, we have introduced many weather-related sensors before. The exact time at that time needs to be recorded.

1. Introduction to DS1302 module

DS1302 is a trickle charging timing chip. It has a real-time clock that can calculate years, months, days, hours, minutes, seconds, weeks and other information, and the available time interval is between 2000 and 2100. In addition, it also has a 31*8-bit general-purpose temporary RAM to store some temporary logical data. DS1302 adopts synchronous serial communication, which simplifies the interface of the processor. In theory, in addition to the power supply, the main need to connect three lines to realize the communication function, namely CE line, I/O line and SCLK serial clock line.

The DS1302 chip has 8 pins, and the working circuit structure is shown in the following figure:

The role of each pin is as follows:

DS1302 uses an 8-bit instruction command word. Before each communication, it needs to use the command word to start. The command word structure is as follows:

As shown in the figure above, the 7th bit is the valid control bit for writing. When it is 0, the writing is invalid, and when it is 1, it is allowed to write. This bit must be set to 1 each time data transmission is performed. Generally, we are using the instruction , this is forcibly set to 1.

The 6th bit controls the function of the chip. When it is 0, it means using the clock data, and when it is 1, it means using the RAM data.

Bits 1 to 5 are register selection bits, which select the register to be operated.

The 0th bit is the read and write control bit. When it is 0, it means to write data to the register, and when it is 1, it means to read data from the register.

Knowing the instruction structure of DS1302, to use it, we also need to have a simple understanding of the function of the register. In this experiment, we mainly use the clock function of DS1302. There are 7 registers related to the clock function. The chip manual gives an example. ,as follows:

Below we introduce the functions and usage of these registers.

First of all, there are 5 bits in the instruction to identify the address of the register to be operated. The above figure directly gives me the read and write instructions to operate the register.

The address of the first register is 0b0, so its read instruction is 0b1000 0001, and its write instruction is 0b1000 0000, which is converted into hexadecimal, that is, 0x81 and 0x80 in the above figure. The highest bit CH of this register is a flag bit. After each power-on, we can read this bit. If it is 1, it means that the system has stopped working after the power is turned off. We need to recalibrate the time. If it is 0, it means Backup power is normal and always continues to function normally. The 4th to 6th digits are used to represent the ten-digit data of the time second, and the 0th to 3rd digits are used to represent the one-digit data of the second, because the tens-digit data of the second is at most 5, and 3 binary digits are enough.

The address of the second register is 0b1, and its highest bit is a reserved bit, which is currently useless. The 4th to 6th bits are used to despise the tens of minutes, and the 0th to 3rd bits represent the ones of the minute. Ten-bit data is up to 5, and 3 binary bits are sufficient.

The address of the third register is 0b10, the highest bit is 1, which means that the current 12-hour format is used, and the highest bit is 0, which means that the 24-hour format is used. Bit 6 is fixed at 0 and has no meaning. The 5th digit is in the 12-hour clock mode, 1 means afternoon, 0 means morning. In 24-hour clock mode, the 4th and 5th digits together represent the tens of the hour. Digits 0 to 3 represent the units digit of the hour.

The address of the 4th register is 0b11, and its 7th and 6th bits are fixed 0, which is meaningless. The 5th and 4th digits together represent the tens of the date, and the 0th to 3rd digits represent the ones of the date.

The address of the 5th register is 0b100, and its 5th to 7th bits are fixed 0, which is meaningless. The 4th digit represents the tens of the month, and the 0th to 3rd digits represent the ones of the month.

The address of the sixth register is 0b101, and its upper 5 bits are fixed to 0, which is meaningless. The 3rd digit indicates the day of the week.

The address of the seventh register is 0b110, the upper 4 bits represent the tens of the year, and the 4th bit represents the ones of the year, which can represent values ​​between 0 and 99, that is, from 2000 to 2099.

The address of the 8th register is 0b111, which is a control register. When writing data, the highest bit WP of this register must be 0. If this bit is 1, the write operation to other registers will be prohibited. Protect.

If you want to use the RAM function, the first two bits of the instruction must be 11, so the read and write instructions for the first register of the RAM are 0b1100 0000 or 0b1100 0001, that is, 0xC0 and 0xC1. There are 31 RAM storage registers, the addresses are 0x00 to 0x1F, and the corresponding command words are from 0xC0 to 0xFF.

Whether it is clock mode or RAM mode, DS1302 supports the use of pulse train to read and write data. The clock pulse train command is 0xBF and 0xBE, and the RAM pulse train is 0xFF and 0xFE. Data is written and read sequentially in the order of the registers.

After understanding the use logic of instructions and registers, there is one more thing left to be clear, that is how to input and read data. The RST pin is used to control data read and write, and RTS changes from a low level to a high level to trigger a data transfer process.

2. Experimental connection

In this experiment, we use the packaged DS1302 module, as shown in the following figure:

Among them, CLK corresponds to the SCLK pin, DAT is the IO function pin, and RST corresponds to the CE function pin. We choose pins 16, 18 and 22 in the Raspberry Pi (physical code, corresponding to 23, 24 and 25 of BCM code respectively), and the connections are as follows:

DS1302 raspberry pie
VCC 3.3V
GND GND
CLK GPIO23 (BCM encoding)
WHICH GPIO24 (BCM encoding)
RST GPIO25 (BCM encoding)

3. Experiment coding

Now, we just need to code according to the module usage introduced earlier, the sample code is as follows:

#coding:utf-8

import time
import RPi.GPIO
from datetime import datetime

# 使用物理编码
SCL = 16
IO = 18
RST = 22

# 数据读写的间隔
CLK_PERIOD = 0.00001

# 关闭GPIO警告
RPi.GPIO.setwarnings(False)
# 配置树莓派GPIO接口 使用物理编码
RPi.GPIO.setmode(RPi.GPIO.BOARD)

# 写入一个字节的数据
def writeByte(Byte):
    for Count in range(8):
        # 将SCL置为低电平 开启一次传输
        time.sleep(CLK_PERIOD)
        RPi.GPIO.output(SCL, 0)
        # 取一位数据进行写入
        Bit = Byte % 2
        Byte = int(Byte / 2)
        # 通过IO引脚进行写入
        time.sleep(CLK_PERIOD)
        RPi.GPIO.output(IO, Bit)
        # 将SCL置为高电平 结束一次传输
        time.sleep(CLK_PERIOD)
        RPi.GPIO.output(SCL, 1)

# 读取一个字节的数据
def readByte():
    # 将IO引脚设置为输入
    RPi.GPIO.setup(IO, RPi.GPIO.IN, pull_up_down=RPi.GPIO.PUD_DOWN)
    Byte = 0
    for Count in range(8):
        # 先将SCL重置为高电平 
        time.sleep(CLK_PERIOD)
        RPi.GPIO.output(SCL, 1)
        # 将SCL置为低电平 开启一次传输
        time.sleep(CLK_PERIOD)
        RPi.GPIO.output(SCL, 0)
        # 读取一位数据
        time.sleep(CLK_PERIOD)
        Bit = RPi.GPIO.input(IO)
        Byte |= ((2 ** Count) * Bit)
    return Byte

# 重置一些数据
def resetDS1302():
    # SCL引脚设置为输出
    RPi.GPIO.setup(SCL, RPi.GPIO.OUT, initial=0)
    # RST引脚设置为输出
    RPi.GPIO.setup(RST, RPi.GPIO.OUT, initial=0)
    # IO引脚设置为输出
    RPi.GPIO.setup(IO, RPi.GPIO.OUT, initial=0)
    # SCL和IO都置为低电平
    RPi.GPIO.output(SCL, 0)
    RPi.GPIO.output(IO, 0)
    time.sleep(CLK_PERIOD)
    # RST置为高电平
    RPi.GPIO.output(RST, 1)

# 结束操作
def endDS1302():
    # SCL引脚设置为输出
    RPi.GPIO.setup(SCL, RPi.GPIO.OUT, initial=0)
    # RST引脚设置为输出
    RPi.GPIO.setup(RST, RPi.GPIO.OUT, initial=0)
    # IO引脚设置为输出
    RPi.GPIO.setup(IO, RPi.GPIO.OUT, initial=0)
    # SCL和IO都置为低电平
    RPi.GPIO.output(SCL, 0)
    RPi.GPIO.output(IO, 0)
    time.sleep(CLK_PERIOD)
    # RST置为低电平
    RPi.GPIO.output(RST, 0)


# 进行时间校准
def setDatetime(year, month, day,  hour, minute, second, dayOfWeek):
    # 引脚重置
    resetDS1302()
    # 设置写始终数据脉冲指令
    writeByte(int("10111110", 2))

    # 开始依次写数据
    # 写入秒数据,*16的作用是把十位右移4位 下面同
    writeByte((second % 10) | int(second / 10) * 16)
    # 写入分钟数据
    writeByte((minute % 10) | int(minute / 10) * 16)
    # 写入小时数据
    writeByte((hour % 10) | int(hour / 10) * 16)
    # 写入日期数据
    writeByte((day % 10) | int(day / 10) * 16)
    # 写入月份数据
    writeByte((month % 10) | int(month / 10) * 16)
    # 写入星期数据
    writeByte(dayOfWeek)
    # 写入年份数据
    writeByte((year % 100 % 10) | int(year % 100 / 10) * 16)
    # 结束数据写入
    writeByte(int("00000000", 2))
    # 结束任务
    endDS1302()

# 获取DS1302硬件时钟实践
def getDatetime():
    # 重置引脚
    resetDS1302()
    # 0xBF指令,开始时钟脉冲串读取数据
    writeByte(int("10111111", 2))

    Data = ""
    
    # 依次读取
    # 先读出秒数据
    Byte = readByte()
    second = (Byte % 16) + int(Byte / 16) * 10
    # 分钟数据
    Byte = readByte()
    minute = (Byte % 16) + int(Byte / 16) * 10
    # 小时数据
    Byte = readByte()
    hour = (Byte % 16) + int(Byte / 16) * 10
    # 日期数据
    Byte = readByte()
    day = (Byte % 16) + int(Byte / 16) * 10
    # 月份数据
    Byte = readByte()
    month = (Byte % 16) + int(Byte / 16) * 10
    # 星期数据
    Byte = readByte()
    day_of_week = (Byte % 16)
    # 年数据
    Byte = readByte()
    year = (Byte % 16) + int(Byte / 16) * 10 + 2000

    # 结束任务
    endDS1302()
    return datetime(year, month, day, hour, minute, second)

# 时间格式化
def format_time(dt):
    if dt is None:
        return ""
    fmt = "%m/%d/%Y %H:%M"
    return dt.strftime(fmt)
    
def parse_time(s):
    fmt = "%m/%d/%Y %H:%M"
    return datetime.strptime(s, fmt)



# 初始化工作

resetDS1302()

# 写保护已关闭。
writeByte(int("10001110", 2))
# 结束指令执行
writeByte(int("00000000", 2))
# 涓流充电模式被关闭。
writeByte(int("10010000", 2))
# 结束指令执行
writeByte(int("00000000", 2))
#结束任务
endDS1302()
        

current = datetime.now()

year = current.year
month = current.month
day = current.day
hour = current.hour
minute = current.minute
second = current.second
week = current.weekday()

setDatetime(year,month,day,hour,minute,second,week)

while True:
    time.sleep(1)
    dt = getDatetime()
    print(dt)


In the above sample code, whether it is reading data or writing data, we all use the communication mode of the clock pulse train, so that we only need to set the command once, and the required data can be read out on demand, which is very convenient. Run the above code on the Raspberry Pi, the effect is as shown below:

4. Think about it

Following the above idea, can it be changed to a non-clock pulse train communication method to obtain date and time information? Try it!

Focus on technology, understand love, be willing to share, be a friend

QQ:316045346

{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/2340880/blog/5330619