稼働中

マイクロビット(e_18)DS3231 リアルタイムクロックモジュール(2)

RTC DS3231 アラーム

前回のDS3231を搭載したリアルタイムクロック(RTC)モジュールの続きです。DS3231は時刻アラームを2つ(A1、A2)設定できます。アラームの設定について記載します。

下表の0x07~0x0dのレジスタでアラーム時刻を設定します。0x0eのcontrolレジスタのbit0、1で各々アラームの割り込み許可を設定します。許可するとアラームによる割り込みが発生すると、A1、A2に対応する0x0fのStatusレジスタのbit0、1のアラームフラグがセットされ、割り込み出力のSQW端子(Pullup)がLOWになります。
Statusレジスタのアラームフラグは’0’を書込むまでセット状態を保ちます。※’1’を書込むことはできません。

レジスタマップ
※データシートからの引用に赤枠を付けてます。

設定できるアラームのパターンを選択します。全てが’1’ならA1は秒ごと、A2は分ごとにアラーム割り込みを出力します。下表に合わせて一致パターンを選択できます。
例えばA2M4、A2M3、A2M2が1、1、0の場合は、現在時刻の’分’が0x0bに設定した値と同じならアラーム割り込みが発生します。

アラームビット
※データシートからの引用です。

アラーム設定

アラーム設定の条件を時刻は24H表示のみ、day/dateは日付dateのみ、としてアラーム設定を行い、動作確認をしました。
以下のようなスクリプトにしました。
アラームを設定するには、スクリプト内にある am1、am2、msk1、msk2、set_AIE(?)を設定するアラームに合わせて変更する必要があります。


from microbit import *
# アラームのレジスタとマスク、割り込み許可の設定
#RTC DS3231 0x68(104)
adr_rtc=0x68

# write register  
def wr_reg(reg,wdata):
    buf=bytearray(2)
    buf[0]=reg
    buf[1]=wdata
    i2c.write(adr_rtc,buf)
    return buf    
# read register
def read_reg(reg,num):          # reg:読込むレジスタのアドレス、num:読込むバイト数
    buf=bytearray(1)
    buf[0]=reg
    i2c.write(adr_rtc,buf)      # 読込むレジスタのアドレスを送信
    sleep(5)
    r_reg=i2c.read(adr_rtc,num) # 設定バイト数のデータの読出し
    sleep(5)
    return r_reg                # 読出したデータを返す
# min sec date day month year>> register 
def d2reg(dat):                 # 秒、分、日付、曜日、月、年のレジスタに送るデータ
    s= (dat//10 << 4) | (dat%10) return s # 24hour >> register
def h24reg(dat):                # 時 24H形式でレジスタに送るデータ
    #p= (0<<6)|(dat//10 << 4) | (dat%10)
    p= (dat//10 << 4) | (dat%10)
    return p
# reg 07-0d read am_ no de-ta hyouzi 0x07~0x0dレジスタデータ表示
def am_DISP():
    reg=0x07
    for i in range(7):
        d=read_reg(reg,1)
        sleep(10)
        print(reg,d[0],hex(d[0]),bin(d[0]))
        reg=reg+1
# am_reg data set               A1、A2へ書込むデータに変換
def am_SET(am_set):
    d=am_set
    #date
    amd= (1 << 6)| d2reg(d[0])
    #hour
    amh=h24reg(d[1])
    #min
    amm=d2reg(d[2])
    #sec
    ams=d2reg(d[3])
    #wday
    amw=d2reg(d[4])
    #ここでレジスタ順に並べ変える
    am_d=[ams,amm,amh,amd,amw]
    return am_d

# A2IE A1IE alarm interrupt enable value= 0,1 ,2, 3 割り込み許可の設定
def set_AIE(value):
    print("pre ",end="") 
    reg=cont_reg()                  # 一度コントロールレジスタを読込んでから
    af= (reg[0] & 0xfc) | value     # 許可ビットを設定する
    wr_reg(0x0e,af)                 # 書込み
    sleep(10)
    #print(af,hex(af))
    print("set ",end="") 
    cont_reg()                      # コントロールレジスタの表示

#control reg 0x0e           コントロールレジスタの表示 アラームフラグ確認
def cont_reg():
    co=read_reg(0x0e,1)
    print('contrl_reg',co[0],hex(co[0]),bin(co[0]))
    return co

# アラーム設定 関係無いところも値を設定
# A1M マッチさせる 日付、24H、分、秒、曜日 秒だけのマッチ条件にするにしても他も設定
am1=([04, 16, 40, 10, 5])
# A2M マッチさせる 24H、分、曜日 99は秒のダミー
am2=([04, 16, 40, 99, 5])

# ここはレジスタ順に並んでいる
am1_dat=am_SET(am1)
am2_dat=am_SET(am2)
#print ('am1_dat',am1_dat)
#print ('am2_dat',am2_dat)

sleep(100)
#AM1,AM2 REG  DATA-TIME data write 先にレジスタに書込む
reg=0x07
for i in range(4):
    wr_reg(reg,am1_dat[i])
    sleep(10)
    reg=reg+1
reg=0x0b
for i in range(3):
    wr_reg(reg,am2_dat[i+1]) #秒は不要なので飛ばす
    sleep(10)
    reg=reg+1

am_DISP()

# マスクを設定する DY-DT は無い 日時データを書いた後でマスクする 
# 時間と秒のような飛び設定はできない mask表以外の設定はできない
# s,m,h,d  all=1 ha zen nichizi 秒、分、時、日
msk1=([0, 1, 1, 1])             # 左では 秒が一致のマスク
msk2=([1, 1, 1])                # 左では 分ごとのマスク
 
reg=0x07 
print('add mask reg data > Write')
for i in range(4):
    d=read_reg(reg,1)
    if msk1[i]==0:
        wr=d[0] | 0x00
    else:
        wr=d[0] | 0x80
    wr_reg(reg,wr)
    print('am1-reg',reg,wr,hex(wr),bin(wr))
    reg=reg+1

reg=0x0b
for i in range(3):
    d=read_reg(reg,1)
    if msk2[i]==0:
        wr=d[0] | 0x00
    else:
        wr=d[0] | 0x80
    wr_reg(reg,wr)
    print('am2-reg',reg,wr,hex(wr),bin(wr))
    reg=reg+1

am_DISP()               # データ表示

# Alarm INT bit setting ##################ここでアラーム割り込み許可の設定
# INT OUT ENABEL None(0) A1(1) A2(2) A1A2(3)
set_AIE(3)      # A1、A2 許可

例えば、以下にすると
set_AIE(3)                              # A1、A2 両方の割り込みを許可
am1=([04, 16, 40, 10, 5])  # A1M マッチさせる 日付、24H、分、、曜日
am2=([04, 16, 40, 99, 5]) # A2M マッチさせる 24H、分、曜日 99は秒のダミー
msk1=([0, 1, 1, 1])                 # が一致のマスク
msk2=([1, 1, 1])                     # 分ごとのマスク

アラーム1、2の割り込みを許可、A1、A2でINT/SQWを出力、A1は時刻が10秒で割り込み発生、A2は分上がりで発生する、ことになります。

アラーム動作確認

アラーム動作を確認するために、
前回のカレンダ日時設定で作成したスクリプトをループ化し追加してカレンダ日時表示とアラームフラグ(A2F、A1F)を表示するようにしました。


from microbit import *
# アラームの動作確認 実時間とフラグ
#RTC DS3231 0x68(104) EEPROM : 0x50~0x57
adr_rtc=0x68

# register >> min sec day month year
def reg2d(dat):
    H_bit=dat >> 4
    L_bit=dat & 0x0f
    d_num=H_bit*10+L_bit
    #return H_bit,L_bit,d_num
    return d_num
# register >> 24h
def reg24h(dat):
    H_bit=(dat >> 4)&0b0011
    L_bit=dat & 0x0f
    d_num=H_bit*10+L_bit
    #return H_bit,L_bit,d_num
    return d_num
# write register  
def wr_reg(reg,wdata):
    buf=bytearray(2)
    buf[0]=reg
    buf[1]=wdata
    i2c.write(adr_rtc,buf)
    sleep(5)
    return buf    
# read register
def read_reg(reg,num):
    buf=bytearray(1)
    buf[0]=reg
    i2c.write(adr_rtc,buf)
    sleep(5)
    r_reg=i2c.read(adr_rtc,num)
    sleep(5)
    return r_reg
#status reg 0x0f
def stat_reg():
    sr=read_reg(0x0f,1)
    print('staus_reg ',sr[0],hex(sr[0]),bin(sr[0]))
    return sr
def stat_rset():
    wr_reg(0x0f,0x88)
    print('staus_reset')
    sleep(5)
#control reg 0x0e
def cont_reg():
    co=read_reg(0x0e,1)
    print('contrl_reg',co[0],hex(co[0]),bin(co[0]))
    return co
def read_ds3231():    
    wday=['sun','mon','tue','wed','thu','fri','sat']
    #00h - 0x07h RTC-Data
    rtc_data=read_reg(0x00,7)
    
    r_yy=reg2d(rtc_data[6])+2000
    #05h Mounth
    r_mo=reg2d(rtc_data[5])
    #04h date
    r_dd=reg2d(rtc_data[4])
    #02h hour
    r_hh=reg24h(rtc_data[2])
    #01h min
    r_mm=reg2d(rtc_data[1])
    #00h sec
    r_ss=reg2d(rtc_data[0])
    #03h weekday
    r_ww=reg2d(rtc_data[3])
    r_wd=wday[r_ww]
    #print('DS3231 DATA READ')
    print(r_yy,'/',r_mo,'/',r_dd,' ',r_wd,' ',r_hh,':',r_mm,':',r_ss, end="")

def disp():
    while True:
        read_ds3231()
        # status reg bit 0,1 af1 af2
        sf=read_reg(0x0f,1)
        am_flg=sf[0] & 0x03  # af2 af1 のビットだけにする A1=1、A2=2、A1A2=3 になる 
        print('  af', hex(sf[0]), am_flg)
        sleep(1000)

stat_reg()      # Status レジスタの表示
#sleep(10)
stat_rset()     # Status レジスタのアラームフラグをリセット
sleep(10)
stat_reg()      # Status レジスタの表示
sleep(10)
cont_reg()      # Control レジスタの表示
disp()          # 現在のカレンダ時刻とアラームフラグの表示

実行結果(ThonnyのShellに表示されます)


>>> %Run 1204_ds3231_alarm_chk_0b.py
staus_reg  136 0x88 0b10001000
staus_reset
staus_reg  136 0x88 0b10001000
contrl_reg 28 0x1c 0b11100
2021 / 12 / 10   wed   18 : 33 : 52  af 0x88 0
2021 / 12 / 10   wed   18 : 33 : 53  af 0x88 0
2021 / 12 / 10   wed   18 : 33 : 54  af 0x88 0
2021 / 12 / 10   wed   18 : 33 : 55  af 0x88 0

動作確認
①アラームの条件を以下のように「A1は45秒で一致、A2は分ごと」にしました。
msk1=([0, 1, 1, 1])    が一致
msk2=([1, 1, 1])     分ごと

am1=([04, 14, 30, 45, 5])
am2=([04, 14, 30, 99, 5])

実行結果の抜粋(ThonnyのShellに表示されます)


>>> %Run 1204_ds3231_alarm_chk_0b.py
staus_reg  138 0x8a 0b10001010          #リセット前のアラームフラグ状態
staus_reset                             #リセット
staus_reg  136 0x88 0b10001000          #リセット後のフラグ状態 00
contrl_reg 31 0x1f 0b11111              # A1、A2 許可


2021 / 12 / 4   sat   14 : 26 : 39  af 0x88 0
2021 / 12 / 4   sat   14 : 26 : 40  af 0x88 0
2021 / 12 / 4   sat   14 : 26 : 41  af 0x88 0
2021 / 12 / 4   sat   14 : 26 : 42  af 0x88 0
2021 / 12 / 4   sat   14 : 26 : 43  af 0x88 0
2021 / 12 / 4   sat   14 : 26 : 44  af 0x88 0
2021 / 12 / 4   sat   14 : 26 : 45  af 0x89 1       #A1F 45秒で一致
2021 / 12 / 4   sat   14 : 26 : 46  af 0x89 1
2021 / 12 / 4   sat   14 : 26 : 47  af 0x89 1
・・
・・
2021 / 12 / 4   sat   14 : 26 : 58  af 0x89 1
2021 / 12 / 4   sat   14 : 26 : 59  af 0x89 1
2021 / 12 / 4   sat   14 : 27 : 0  af 0x8b 3        #A2F 分上がりで一致
2021 / 12 / 4   sat   14 : 27 : 1  af 0x8b 3
2021 / 12 / 4   sat   14 : 27 : 2  af 0x8b 3
2021 / 12 / 4   sat   14 : 27 : 3  af 0x8b 3
2021 / 12 / 4   sat   14 : 27 : 4

————————————————-
動作確認
②アラームの条件を以下のように「A1は39m05sで一致、A2は38分で一致」にしました。

msk1=([0, 0, 1, 1])   #分と秒が一致
msk2=([0, 1, 1])    #分が一致

am1=([04, 14, 39, 5, 5])   #39m05sでAF1
am2=([04, 14, 38, 99, 5])   #38分でAF2

実行結果の抜粋(ThonnyのShellに表示されます)


>>> %Run 1204_ds3231_alarm_chk_0b.py
staus_reg  139 0x8b 0b10001011
staus_reset
staus_reg  136 0x88 0b10001000
contrl_reg 31 0x1f 0b11111

2021 / 12 / 4   sat   14 : 37 : 57  af 0x88 0
2021 / 12 / 4   sat   14 : 37 : 58  af 0x88 0
2021 / 12 / 4   sat   14 : 37 : 59  af 0x88 0
2021 / 12 / 4   sat   14 : 38 : 0  af 0x8a 2            #A2F 38分で一致
2021 / 12 / 4   sat   14 : 38 : 1  af 0x8a 2
2021 / 12 / 4   sat   14 : 38 : 2  af 0x8a 2
2021 / 12 / 4   sat   14 : 38 : 3  af 0x8a 2
・・
・・
2021 / 12 / 4   sat   14 : 39 : 0  af 0x8a 2
2021 / 12 / 4   sat   14 : 39 : 1  af 0x8a 2
2021 / 12 / 4   sat   14 : 39 : 2  af 0x8a 2
2021 / 12 / 4   sat   14 : 39 : 3  af 0x8a 2
2021 / 12 / 4   sat   14 : 39 : 5  af 0x8b 3            #A1F 39m05sで一致
2021 / 12 / 4   sat   14 : 39 : 4  af 0x8b 3
2021 / 12 / 4   sat   14 : 39 : 6  af 0x8b 3
2021 / 12 / 4   sat   14 : 39 : 7  af 0x8b 3
2021 / 12 / 4   sat   14 : 39 : 8  af 0x8b 3
2021 / 12 / 4   sat   14 : 39 : 9  af 0x8b 3

以上のように、設定したマスクで割り込みアラームの動作が確認できたと思います。

まとめ

アラームの設定用に作成したスクリプトが複雑になってしまい不満が残りましたが、DS3231モジュールのアラーム設定はどうにかできたと思います。これでmicro:bitビットでカレンダ日時の割り込み処理ができると思います。