稼働中

マイクロビット(e_48)DS3231 の使い方を再考

DS3231 の再検討

以前、DS3231 RTCを搭載したリアルタイムクロックモジュールの使い方を記事(e_1718)で記載したのですが、複雑になってしまいスッキリしませんでした。そのため、再検討をしました。少しは簡略になったと思うので記載します。※24H表示のみに対応しています。
改善したスクリプトだけ記載します。DS3231の詳細は記事(e_1718)を参照してください。

カレンダ設定

write_Cal(l_cal)でカレンダデータを設定します。
設定するデータを「2022/06/16 17:08:56 Thu」なら l_cal=([2022, 06, 16, 17, 08, 56, 4]) のようにリストで与えるようにしました。
read_Cal()で設定値を読み出します。
24H表示のみに対応しています。

スクリプト


ds3231_rwCal_data_b.py
from microbit import *
#RTC DS3231 0x68(104)
adr_rtc=0x68

# 書込むデータを上位下位に分ける hex表示にすると読視できる
def s_dat(dat):
    s_dat=(dat//10 << 4) | (dat%10)
    return s_dat

# カレンダデータをリストデータ(l_data)で与える
def write_Cal(l_data): 
    dat=l_data 
    s_reg=bytearray(1)
    s_reg[0]=0x00        # write start regi
    # リストデータをバイトアレイに割り当てる
    buf=bytearray(7)
    # 0x00 seconds 
    buf[0]= s_dat(dat[5])
    # 0x01 minutes 
    buf[1]= s_dat(dat[4])
    # 0x02 hour 
    buf[2]= s_dat(dat[3])
    # 0x03 day of week
    buf[3]= s_dat(dat[6])
    # 0x04 date
    buf[4]= s_dat(dat[2])
    # 0x05  month  over century 
    buf[5]= s_dat(dat[1])
    # 0x06  year
    buf[6]= s_dat(dat[0]-2000)

    # writing to registers
    s_buf=bytearray(8)
    s_buf=s_reg+buf      # 開始レジスタ+データ
    i2c.write(adr_rtc,s_buf)

# 現在のカレンダデータを読み出す
def read_Cal():
    # read real time
    wday=['sun','mon','tue','wed','thu','fri','sat']
    s_reg=bytearray(1)
    s_reg[0]=0x00
    i2c.write(adr_rtc,s_reg)
    r_reg=i2c.read(adr_rtc,7) # 7bytes読込
        
    r_data=[]
    for i in range(7):
        a=hex(r_reg[i])[2:]    #a='0x36' a[2:]='36' 0xを除外して 読む
        if i==3:               # 0x03 曜日に
            a=wday[int(a)]
        if i==6:
            a=str(2000+int(a)) # 0x06 2000を足して西暦に
        r_data.append(a)
    
    # [::-1][0:3] [::-1][4:7] [::-1][3:4] 逆ソートしてから並べ替える
    ss=r_data[::-1][0:3]+r_data[::-1][4:7]+r_data[::-1][3:4]
    return ss

##-----------------------------------------
# Callender 24H display dayweek sun(0)
# 2022/06/16 17:08:56 thu ( 0:sun 1:mon 2:tue 3:wed...)
l_cal=([2022, 06, 16, 17, 08, 56, 4])

write_Cal(l_cal)

print(read_Cal())

実行結果

設定値の確認結果がThonnyのshellに表示されます。


>>> %Run ds3231_rwCal_data_b.py
['2022', '6', '16', '17', '8', '56', 'thu']  # 設定直後に読み込んでいるので設定値が表示されている

アラーム設定

write_Adata(set_ldata)
アラームデータを設定します。
設定するデータをset_ldata=[a1,a2,a1m,a2m,a1d,a2d] のようにリストで与えるようにしました。
各々のデータもリストデータです。※詳細はデータシート、記事を参照下さい。


a1、a2は時間のマッチデータ
a1=[59,59,23,30] # sec,min,hour,day/date
a2=[59,23,30]    #     min,hour,day/date
a1m、a2m、時間、a1d、a2dは日、曜日のマスクビット設定になります。
a1m=[0,1,1,1]   #alarm1 mask
a2m=[0,1,1]     #alarm1 mask
a1d=['']        #day/date '','0','1' 自動的に a1m=[0,0,0,0]
a2d=['']        #day/date '','0','1' 自動的に a2m=[0,0,0]

read_Adata()
アラーム設定データを読み出します。

スクリプト


ds3231_rwAlm_data_b.py
from microbit import *
#ds3231_test_02.py から関数化
#write_Adata(mach mask) read_Adata

#RTC DS3231 only 0x68(104) EEPROM(AT24C32)0x50~0x57
adr_rtc=0x68

# 書込むデータを上位下位に分ける hex表示にすると読視できる
def s_dat(dat):
    s_dat=(dat//10 << 4) | (dat%10)
    return s_dat
# 8bitの表示ゼロ穴埋
# zero padding 8-12bit
def z_padd(dat):  # int
    dat=bin(dat)  # str
    value='0b'+'0'*(8-len(dat[2:])) + dat[2:]      # str 8bit
    #value='0'*(12-len(dat[2:])) + dat[2:]         # str 12bit
    return value

# read 1-register 
def read_reg(reg):
    s_reg=bytearray(1)
    s_reg[0]=reg
    i2c.write(adr_rtc,s_reg)
    read_reg=i2c.read(adr_rtc,1)
    return read_reg

# アラームマッチデータ、マスクデータを書込む
# ldata=[a1,a2,a1m,a2m,a1d,a2d] a1など各々もリスト
def write_Adata(ldata):
    a1= ldata[0]
    a2= ldata[1]
    a1m=ldata[2]
    a2m=ldata[3]
    a1d=ldata[4]
    a2d=ldata[5]
    
    # write alarm data set-regi 0x07-0xd
    s_reg=bytearray(1)
    s_reg[0]=0x07              # write start regi-num

    buf=bytearray(7)
    for i in range(4):
        buf[i]=s_dat(a1[i])         #一致データを上位下位に変換 マッチデータ
        # mask bitを付加
        
        if a1d[0]=='':                      # DY/DTの設定が無い場合
            buf[i]=buf[i] | a1m[i]<< 7      # AM bit7
        else:
            buf[i]=buf[i] & 0x7f  # AM bit7= '0'にする
           
            if a1d[0]=='1':                 # DY(day)を設定する場合
                buf[3]=buf[3] | 0x40        # DY/DT bit '1' 
        
    for i in range(3):
        buf[i+4]=s_dat(a2[i])       #設定データを上位下位に変換する
        # mask bit 
        if a2d[0]=='':
            buf[i+4]=buf[i+4] | a2m[i]<< 7
        else:
            buf[i+4]=buf[i+4] & 0x7f  # AM bit7 '0'
           
        if a2d[0]=='1':
            buf[6]=buf[6] | 0x40  # DY/DT bit wo '1'

    # regi-addres,write-bytearray
    s_buf=s_reg+buf             # bytearrayは足し算できる 開始レジスタ+データ
    i2c.write(adr_rtc,s_buf)    # write mach data 

# read alarm data -------------------------
def read_Adata():
    s_reg=bytearray(1)
    s_reg[0]=0x07
    i2c.write(adr_rtc,s_reg)
    r_reg=i2c.read(adr_rtc,7)
    return r_reg

## -----------------------------------------
# mach data  設定するマッチデータ
a1=[59,59,23,30] # sec,min,hour,day/date
a2=[59,23,30]    #     min,hour,day/date

# ALARM MASK BITS 飛び設定は出来ない[1,0,1,0] マスクデータ(一致箇所)
a1m=[0,1,1,1]   #alarm1 mask(bit7)[1,1,1,1][0,1,1,1][0,0,1,1][0,0,0,1]
a2m=[0,1,1]     #alarm1 mask(bit7)[1,1,1][0,1,1][0,0,1]
a1d=['']        #day/date '','0','1' 自動的に a1m=[0,0,0,0]
a2d=['']        #day/date '','0','1' 自動的に a2m=[0,0,0]   

set_ldata=[a1,a2,a1m,a2m,a1d,a2d]
# wirte mach mask Adata
write_Adata(set_ldata)

# read Adata
r_reg=read_Adata()
for i in range(7):    
    print(hex(7+i),z_padd(r_reg[i]))

実行結果

設定値の確認結果がThonnyのshellに表示されます。


>>> %Run ds3231_rwAlm_data_b.py
0x7 0b01011001
0x8 0b11011001
0x9 0b10100011
0xa 0b10110000
0xb 0b11011001
0xc 0b10100011
0xd 0b10110000
>>>

フラグ・割込設定

以下のようにしました。
read_Aflg()
アラームフラグ|A2F|A1F|の状態を返します。
reset_Aflag()
アラームフラグ|A2F|A1F|をリセットします。
set_Aie(s_num=3)
|A2IE|A1IE|の割込み許可を設定します。デフォルトは|A2IE|A1IE|両方の3になります。
read_Aie()
|INTCN|A2IE|A1IE|の状態を返します。

スクリプト


ds3231_rwAie_data_b.py
from microbit import *
# Alarm Flag(read,reset) Ctrl-AIE(read,set)
# RTC DS3231 only 0x68(104) EEPROM(AT24C32)0x50~0x57
adr_rtc=0x68

# read 1-register
def read_reg(reg):
    s_reg=bytearray(1)
    s_reg[0]=reg
    i2c.write(adr_rtc,s_reg)
    read_reg=i2c.read(adr_rtc,1)
    return read_reg

## Alarm Flag
# read Alarm Flag |A2F|A1F|
def read_Aflg():
    a_flag=read_reg(0x0f)[0]& 0x03
    #print('Aflg=',bin(a_flag))
    return a_flag

# reset Alarm Flag |A2F|A1F| 
def reset_Aflag():
    r_reg=read_reg(0x0f)
    buf=bytearray(2)
    buf[0]=0x0f             # 0x0fを読出して|A2F|A1F|をリセットして書込む
    buf[1]=r_reg[0] & 0xfc  # 0b_1111_1100
    i2c.write(adr_rtc,buf)
    #print('reset 0x0f=',buf[1],bin(buf[1]))

## INTCON Alarm INT Enabel
# read |INTCN|A2IE|A1IE| Control/Status(0x0e)
def read_Aie():
    a_ie= read_reg(0x0e)[0] & 0x07
    #print('INT-AIE=',bin(a_ie))
    return a_ie

# write |A2IE|A1IE| Control/Status(0x0e)
def set_Aie(s_num=3):
    r_ie=read_reg(0x0e)[0] & 0xfc   #|A2IE|A1IE|をリセットして値を書込む

    aie=s_num # 00,01,10,11(0,1,2,3)
    buf=bytearray(2)
    buf[0]=0x0e
    buf[1]=r_ie | aie
    i2c.write(adr_rtc,buf)

## MAIN-----------------------------------------
# read_Aflg reset_Aflag  read_Aie  set_Aie
print('|A2F|A1F|=',bin(read_Aflg()))            #|A2F|A1F|の状態
print('|INTCN|A2IE|A1IE|=',bin(read_Aie()))     #|A2IE|A1IE|の状態
set_Aie(2)                                      #|A2IE|をセット
print('|INTCN|A2IE|A1IE|=',bin(read_Aie()))     #|A2IE|A1IE|の状態
reset_Aflag()                                   #|A2F|A1F|リセット
print('|A2F|A1F|=',bin(read_Aflg()))            #|A2F|A1F|の状態

実行結果

実行結果がThonnyのshellに表示されます。


>>> %Run 'ds3231_rwAie_data_b.py'
|A2F|A1F|= 0b11             # AlarmFlag状態
|INTCN|A2IE|A1IE|= 0b100    # 割込み許可の状態 |A2IE|A1IE|ともに無許可
|INTCN|A2IE|A1IE|= 0b110    # A2IEをセット 割込み許可
|A2F|A1F|= 0b0              #reset_Aflag()
>>> 

まとめ

前回よりかなり簡素になり分かりやすくなったように思います。