この記事のフォローになります
8日間程度のデータですが、
こんな感じです、ソーラー電圧は日中の光を受けて電力発生している時間帯にはピークが見えます、この先継続しても12.4V程度は下回りそうにないので十分に効果はあると言えそうです、発電量が一番低下するのは太陽の高度から冬至の頃だからその頃に再度ログ取ってみようかと思う
但し真夏の太陽と違って、晴れてもバッテリーを満充電にするようなパワーはない模様
admin

la vie libre
この記事のフォローになります
8日間程度のデータですが、
こんな感じです、ソーラー電圧は日中の光を受けて電力発生している時間帯にはピークが見えます、この先継続しても12.4V程度は下回りそうにないので十分に効果はあると言えそうです、発電量が一番低下するのは太陽の高度から冬至の頃だからその頃に再度ログ取ってみようかと思う
但し真夏の太陽と違って、晴れてもバッテリーを満充電にするようなパワーはない模様
admin
ようやくそれらしいデータが取れた、何しろ省電力有効にすると電池寿命長くなるから、時間かかると言えば当然と言えば当然ですが
<条件>
・電池:NiH電池の二直、容量1000mAH
・ラズピコ:rp2040のWi-Fi無しモデル
・サンプル周期:10分間隔で電池電圧をSDカードに記録
電池の放電電圧の開始電圧は比較のため合わせてあります(省電力有効は満充電から、省電力無効は放電途中からの測定だから)
SDカードのファイルの見え方、
10月7日の午後から今日の午後までの実行結果、大勢に影響ないけどファイルの日付がなぜこうなるかは理解できていない
青は省電力がほぼ効かない状態での測定、緑はlighsleepをデータサンプリング間隔(10分)で設定してとったデータ
電流測定では22mA vs 4mAだったけど、電池電圧の変化はそれ以上に見えてます、なぜだろう?
admin
ラズピコのmicroPythonで以下のようなコードではRTC割り込み受け付けられません
つまりlight sleep()で無限に待つ設定にして、RTC割り込みを受けようとしてもラズピコのmicroPython実装では、lightsleep中は他の割り込み受け付けは機能しません
try:
while True:
if alarm_triggered:
alarm_triggered = False
clear_alarm_flag()
time.sleep_ms(5)
set_alarm()
value1 = round((adc0.read_u16() >> 4) * 3.3 * 3 / 4096, 2)
value2 = round((adc1.read_u16() >> 4) * 3.3 * 2 / 4096, 2)
print(value1, value2)
if value2 > 2.0:
logger.write(rtc, value1, value2)
machine.lightsleep()
except KeyboardInterrupt:
print("terminated")従って、やりたい機能を実装しようとすると、
machine.lightsleep()でRTC割り込みと同等の値(最大値)を設定してやらないとダメ、電池寿命計ろうと思って無限待ちにしたら最初のRTC割り込みしか実行されず、それ以降のRTC割り込みは発生しなくなってしまった
まあラズピコの実装レベルはその程度のようです
admin
ラズピコのデータロガーの使い道で温度の記録は主要な用途かも知れないけど、屋外で使うには防水性が必要
ds18x20は1-wire製品で単品では防水性はないけれども、それを金属管に入れて防水性を確保したものが安く販売されているので購入、Amazonで3本セットで販売のもの
SHT30との測定値の差を見るために以下のコードを使用、GP2は推奨の4.7KΩでプルアップ、プルアップしなくてもそれらしい値は出てくるけど、本来的にはかりそめだと思った方が良い、特に複数本つなぐとそれなりに静電容量も増加するし
import time
import machine, onewire, ds18x20
from machine import Pin, I2C
# I2C1 (SDA=GP6, SCL=GP7)
i2c = I2C(1, scl=Pin(7), sda=Pin(6), freq=100000)
# --- SHT30 定義 ---
SHT30_ADDR = 0x44
SHT30_CMD_MEASURE = b'\x2C\x10' # set to highspeed response mode
def read_sht30():
i2c.writeto(SHT30_ADDR, SHT30_CMD_MEASURE)
time.sleep(0.008)
data = i2c.readfrom(SHT30_ADDR, 6)
temp_raw = data[0] << 8 | data[1]
hum_raw = data[3] << 8 | data[4]
temperature = -45 + (175 * temp_raw / 65535)
humidity = 100 * hum_raw / 65535
return temperature, humidity
# 1-Wire の設定(例: GP2)
dat = machine.Pin(2)
# 1-Wire バス作成
ow = onewire.OneWire(dat)
ds = ds18x20.DS18X20(ow)
# バス上のデバイスをスキャン(複数のDS18B20が繋がっている場合あり)
roms = ds.scan()
print('Found DS devices:', roms)
while True:
# 温度変換開始
ds.convert_temp()
time.sleep_ms(750) # 最大分解能(12bit)の変換待ち時間
for rom in roms:
temp = ds.read_temp(rom)
print('Device', rom, 'Temp={:.1f} C'.format(temp))
print('-' * 40)
try:
t, h = read_sht30()
print("SHT30 Temp={:.1f} C Hum={:.0f} %".format(t, h))
print("-" * 40)
except Exception as e:
print("Error:", e)
time.sleep(2)
<実行結果>
今回使用のセンサーのIDもプリントアウトするようにしてます、複数箇所の測定をする時にはセンサーで見て分かる識別手段が必要
測定値で1.5℃ぐらい差があるけども、これはアプリによっては許容範囲、おそらく3本それぞれでもばらつきはあるはず
ロガー自体をケースに入れて、センサーを複数本使ってログを取るような形式になるはず
admin
Switch scienceで販売されてる、ラズピコ用のグローブシールド
https://www.switch-science.com/products/7109?_pos=11&_sid=85b9241fd&_ss=r
数年前に買ったけど初めて使ってみた、但しちゃんとした回路図が見つからないから実物で追っかけないとi2cの接続先わからなかった
以下のコードの、
i2c = I2C(1, scl=Pin(7), sda=Pin(6), freq=100000)
がI2C1の接続先になってます
import time
import machine, onewire, ds18x20
from machine import Pin, I2C
# I2C1 (SDA=GP6, SCL=GP7)
i2c = I2C(1, scl=Pin(7), sda=Pin(6), freq=100000)
# --- SHT30 定義 ---
SHT30_ADDR = 0x44
SHT30_CMD_MEASURE = b'\x2C\x10' # set to highspeed response mode
def read_sht30():
i2c.writeto(SHT30_ADDR, SHT30_CMD_MEASURE)
time.sleep(0.008)
data = i2c.readfrom(SHT30_ADDR, 6)
temp_raw = data[0] << 8 | data[1]
hum_raw = data[3] << 8 | data[4]
temperature = -45 + (175 * temp_raw / 65535)
humidity = 100 * hum_raw / 65535
return temperature, humidity
# --- メイン ---
while True:
try:
t, h = read_sht30()
print("SHT30 Temp={:.1f} C Hum={:.0f} %".format(t, h))
print("-" * 40)
except Exception as e:
print("Error:", e)
time.sleep(2)
こんな感じで吐き出してきます
SHT30 Temp=28.5 C Hum=62 %
----------------------------------------
SHT30 Temp=28.6 C Hum=62 %
----------------------------------------アプリケーションは防水機能のある温度センサーが必要で、ポピュラーなのはds18x20の先端がsusパイプで覆われたやつが使えそうです
インターフェースが1-wireなので、増設も並列につなげていけばできるけど読み出し時間はかなりかかるらしい、なぜ増設した時に個体識別できるかはds18x20が出荷時点で固有のIDが付与される、つまりMACアドレスなどと同じ理屈、から可能ということ
admin
結局ラズピコ2は、
① microPythonはlightsleepもdeepsleepも実装が不完全
② pico-sdkはSDカードアクセスライブラリが無いぽい
③ Arduino IDEはi2cの設定Wire()関数でUSBの通信が切れる
ということで、ラズピコ2はまだ環境がイマイチなので、ラズピコでやってみた
<結果>
① ラズピコはおそらく周辺回路のデザインによるだろうけど、lightsleepでもdeepsleepでもスリープ状態の電流は4mA程度(単三電池2本使用で)だから、電池容量1,000mAでほぼ10日がmax
② deepsleep使うアプリ書き込んでしまうと、ThonnyやVScodeのようなUSBシリアル使うツールは使えなくなる、リセットするにはdeskモードにして、
% picotool erase
Erasing: [==============================] 100%picotoolで初期化が必要
③ 消費電流に差がなくて、余計な初期化処理が走るdeepsleepにラズピコでは使い道がなさそうだ
ラズピコでもGrove経由で色々なセンサーへの接続はできるので、サンプリング対象を変えればロガーとして使うことはできる
ということで、当初の目論見の数ヶ月を単三電池2本でというのはラズピコでは無知というのが結論、アプリ次第で一週間もてば十分なケースもあるし、電池容量増やせば期間延長もできるわけだけども
admin
microPython用のIDE、具体的にはThonny、VScodeの拡張機能MicroPicoを使ってのいくつかの気づき
・IDEとはUSB経由での通信だけど、例えばVScode上でのコード実行は実際はRAM上に展開して実行される、従ってラズピコにmain.pyがすでに存在している時には、実行(run)も無効だし、ラズピコ側も動作停止する(USBシリアル使っている時には競合するから、停止ということ)
・ラズピコへのコード(***.py)の転送はThonnyが直感的で便利、但しここでもUSBは共有できないからVScodeは終了しておかないとダメ
・したがって、microPythonへファームさえ書き込んでしまえば、それ以降はIDEにはファイルに見せる操作は不要
ラズピコ2はいろんな機能がいまだサポートされてないようだから、今回のプロジェクトは前世代のラズピコに変えるつもり、それならmicroPythonのmichine.lightsleepやdeepsleepも動作するだろうからそれで十分だよ
admin
タイトル通りですが、最初の割り込みは上がってきますが、次の割り込みは上がっってこない、おそらくmicroPythonのファームの問題だろうと思うから、やはり実装はpico-sdkでやるけれどもその前に電源電流測定をしてみる
構成は電池はNiH二直に2.2Ωの電流測定用の抵抗経由でラズピコのVSYSに供給
VBUSとVSUSを今は計測してますが、USBは未接続なのでVBUSはほぼ0Vになってます
抵抗(2.2Ω)の両端をテスターで測定すると48mV程度、つまりos.sleep状態の電流はおよそ22mA消費している、十秒に一回はSD書き込みで跳ね上がる
VBUS/VSYSの計測値は以下、USBは未接続だからほぼ0V(VSYSは2.2Ω抵抗をシリーズでその分ドロップ(2.2*22mV)してるはず)
0.01,2.55
0.01,2.55
抵抗両端の電圧測定、つまり電流波形はこんな感じ、1000mAHの電池なら一日半ぐらいは動作可能、ほぼ予測通り
<現時点のPythonコード>
RTC関連のクラスがあるので、SD書き込み関連のクラスを追加して見通しをよくした、前回との違いはSDカードの電源供給を書き込み時点だけオンにしている点、時間待ち0.2秒は今少し短くても良さそうだ、システムはアクティブなので信号線からの回り込みでSDカードの電源線の電圧は2V以上はあるからSDへのダメージ対策として、SDへの書き込み終わったらSPIを無効化後に入力High-Zにして回り込みをソフト的に抑制するようにした
#!/usr/bin/python
# -*- coding: utf-8 -*-
from machine import Pin, I2C, ADC, SPI
import time
import binascii
import machine, sdcard, uos
I2C_PORT = 0
I2C_SDA = 20
I2C_SCL = 21
SD_ON = 22
ALARM_PIN = 3
alarm_triggered = False
adc0 = ADC(Pin(26)) # ADC0
adc1 = ADC(Pin(27)) # ADC1
# -----------------------------
# RTC ds3231 class
# -----------------------------
class ds3231():
w = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
address = 0x68
start_reg = 0x00
alarm1_reg = 0x07
control_reg = 0x0e
status_reg = 0x0f
def __init__(self,i2c_port,i2c_scl,i2c_sda):
self.bus = I2C(i2c_port,scl=Pin(i2c_scl),sda=Pin(i2c_sda))
self.alarm_pin = Pin(ALARM_PIN, Pin.IN, Pin.PULL_UP)
self.alarm_pin.irq(handler=self.alarm_irq_handler, trigger=Pin.IRQ_FALLING)
def set_time(self,new_time):
hour = new_time[0] + new_time[1]
minute = new_time[3] + new_time[4]
second = new_time[6] + new_time[7]
week = "0" + str(self.w.index(new_time.split(",",2)[1])+1)
year = new_time.split(",",2)[2][2] + new_time.split(",",2)[2][3]
month = new_time.split(",",2)[2][5] + new_time.split(",",2)[2][6]
day = new_time.split(",",2)[2][8] + new_time.split(",",2)[2][9]
now_time = binascii.unhexlify((second + " " + minute + " " + hour + " " + week + " " + day + " " + month + " " + year).replace(' ',''))
self.bus.writeto_mem(int(self.address),int(self.start_reg),now_time)
def alarm_irq_handler(self, pin):
global alarm_triggered
alarm_triggered = True
def set_alarm_time(self, alarm_time):
self.alarm_pin = Pin(ALARM_PIN, Pin.IN, Pin.PULL_UP)
self.alarm_pin.irq(handler=self.alarm_irq_handler, trigger=Pin.IRQ_FALLING)
# ステータスフラグクリア
status = rtc.bus.readfrom_mem(rtc.address, rtc.status_reg, 1)
rtc.bus.writeto_mem(rtc.address, rtc.status_reg, bytes([status[0] & 0xFE]))
# コントロールレジスタ設定
self.bus.writeto_mem(self.address, self.control_reg, b'\x07')
# アラーム時刻設定
hour = alarm_time[0] + alarm_time[1]
minute = alarm_time[3] + alarm_time[4]
second = alarm_time[6] + alarm_time[7]
date = alarm_time.split(",", 2)[2][8] + alarm_time.split(",", 2)[2][9]
now_time = binascii.unhexlify((second + minute + hour + date).replace(' ', ''))
self.bus.writeto_mem(self.address, self.alarm1_reg, now_time)
def get_date(self):
t = self.bus.readfrom_mem(self.address, self.start_reg, 7)
year = 2000 + bcd2dec(t[6])
month = bcd2dec(t[5])
day = bcd2dec(t[4])
return year, month, day
def bcd2dec(bcd):
return ((bcd >> 4) * 10) + (bcd & 0x0F)
# -----------------------------
# SDLoggerVFS class (SPI + Hi-Z安全化)
# -----------------------------
class SDLoggerVFS:
def __init__(self, spi_id, cs_pin, power_pin):
self.spi_id = spi_id
self.cs_pin = cs_pin
self.power_pin = Pin(power_pin, Pin.OUT)
self.mount_point = '/sd'
self.spi = None
# SPIピン番号
self.SCK_PIN = 18
self.MOSI_PIN = 17
self.MISO_PIN = 16
def power_on(self):
self.power_pin.value(0)
time.sleep(0.2)
def power_off(self):
self.power_pin.value(1)
def spi_init(self):
self.spi = SPI(self.spi_id, baudrate=1_000_000, polarity=0, phase=0)
def spi_deinit_and_hiz(self):
if self.spi:
self.spi.deinit()
self.spi = None
# ピンをHi-Z入力に戻してpull-down
Pin(self.MOSI_PIN, Pin.IN, Pin.PULL_DOWN)
Pin(self.MISO_PIN, Pin.IN, Pin.PULL_DOWN)
Pin(self.SCK_PIN, Pin.IN, Pin.PULL_DOWN)
def write(self, rtc, value1, value2):
# SDカード電源ON
self.power_on()
# SPI初期化
self.spi_init()
# SDCardライブラリ初期化
sd = sdcard.SDCard(self.spi, Pin(self.cs_pin))
# マウント
uos.mount(sd, self.mount_point)
# ファイル書き込み
year, month, day = rtc.get_date()
filename = f"{self.mount_point}/{year:04d}-{month:02d}-{day:02d}.txt"
with open(filename, 'a') as f:
f.write(f"{value1},{value2}\n")
# アンマウント
uos.umount(self.mount_point)
# SPI停止 + Hi-Z化
self.spi_deinit_and_hiz()
# SDカード電源OFF
self.power_off()
# -----------------------------
# RTC時間加算用
# -----------------------------
def add_time_period_to_rtc_time(rtc):
t = rtc.bus.readfrom_mem(rtc.address, rtc.start_reg, 7)
year = 2000 + bcd2dec(t[6])
month = bcd2dec(t[5] & 0x1F)
day = bcd2dec(t[4] & 0x3F)
hour = bcd2dec(t[2] & 0x3F)
minute = bcd2dec(t[1] & 0x7F)
second = bcd2dec(t[0] & 0x7F)
weekday = t[3] & 0x07
def is_leap(year):
return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
def days_in_month(y, m):
mdays = [31, 29 if is_leap(y) else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
return mdays[m-1]
second += 10
if second >= 60:
second -= 60
minute += 1
if minute >= 60:
minute = 0
hour += 1
if hour >= 24:
hour = 0
day += 1
weekday = weekday + 1 if weekday < 7 else 1 if day > days_in_month(year, month):
day = 1
month += 1
if month > 12:
month = 1
year += 1
w = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]
weekday_str = w[weekday-1]
alarm_time_str = "{:02d}:{:02d}:{:02d},{},{:04d}-{:02d}-{:02d}".format(
hour, minute, second, weekday_str, year, month, day)
return alarm_time_str
def set_alarm():
alarm_time_later = add_time_period_to_rtc_time(rtc)
print("Alarm time 10 sec later:", alarm_time_later)
rtc.set_alarm_time(alarm_time_later)
rtc.alarm_pin = Pin(ALARM_PIN, Pin.IN, Pin.PULL_UP)
def clear_alarm_flag():
status = rtc.bus.readfrom_mem(rtc.address, rtc.status_reg, 1)
rtc.bus.writeto_mem(rtc.address, rtc.status_reg, bytes([status[0] & 0xFE]))
# -----------------------------
# main
# -----------------------------
if __name__ == '__main__':
rtc = ds3231(I2C_PORT,I2C_SCL,I2C_SDA)
set_alarm()
logger = SDLoggerVFS(0, 17, SD_ON)
value1 = round((adc0.read_u16() >> 4) * 3.3 * 3 / 4096, 2)
value2 = round((adc1.read_u16() >> 4) * 3.3 * 2 / 4096, 2)
print(value1, value2)
logger.write(rtc, value1, value2)
try:
while True:
if alarm_triggered:
alarm_triggered = False
clear_alarm_flag()
time.sleep_ms(5)
set_alarm()
value1 = round((adc0.read_u16() >> 4) * 3.3 * 3 / 4096, 2)
value2 = round((adc1.read_u16() >> 4) * 3.3 * 2 / 4096, 2)
print(value1, value2)
if value2 > 1.8:
logger.write(rtc, value1, value2)
time.sleep(10)
except KeyboardInterrupt:
print("terminated")
admin
次の要素はSPIバスにつながるSDカードへのアクセスです
<microPythonのSDカードアクセスライブラリと動作確認>
https://github.com/micropython/micropython-lib/tree/master/micropython
ここから持ってきました、
ライブラリの転送はVScodeでは面倒ぽいので、Thonnyを使って転送、ライブラリは一度ピコに書き込めばVScodeでもそのまま有効です、ただしVScodeですでにUSBシリアル使ってるとThonnyは接続できないから、VScode側は終了しないと競合してしまいます、逆も真也
実行時のVScodeのコンソール出力、上段はmicroSD未挿入だからエラーが出る、カードがラズパイ用のSDカードシステムなので。それらしきファイルが見えます、ファイル形式はおそらくFAT32しか扱えないと思う
———————————————————
MicroPython v1.26.0 on 2025-08-09; Raspberry Pi Pico2 with RP2350
Type "help()" for more information or .help for custom vREPL commands.
>>>
Traceback (most recent call last):
File "", line 7, in
File "sdcard.py", line 54, in __init__
File "sdcard.py", line 82, in init_card
OSError: no SD card
>>>
2025/09/12 17:18:00 Friday
alarm1 time is up
———————————————————
os.listdir(‘/sd’) の結果を格納して出力(以下のコード)すると、
files = os.listdir('/sd') # set to mount point
for file in files:
print(file)
>>>
overlays
bcm2708-rpi-b-plus.dtb
LICENCE.broadcom
issue.txt
~~~ 以下省略(ラズパイのシステムディスクだからこんな中身) 一応カード検出機能もGPIOに入れてるけど、SDカードにアクセスできなきゃこうなる、実際の運用ではカード検出できなかったら例えばLEDを高速点滅とかの手段だろうね
<タイマー割り込み設定>
タイマーIC(DS3231)のタイマー割り込み設定は絶対時間指定しかできないから、西暦以降全ての指定が必要、ただしタイマーICはデータ形式がBCD(Binary Code Decimal)、例えば十進21は15hではなく21hのような形式だから、内部で都度変換処理が必要、全部生成AIでコード作成したけどね
仮にUSB電源電圧を1分ごとにログするようにしてみた結果はこんな感じ、絶対時間で指定だから、相対時間指定のように段々処理時間が加算されて時間がずれていくようなことはない
Alarm time 1 min later: 20:28:31,Sunday,2025-09-14
5.09
Alarm time 1 min later: 20:29:31,Sunday,2025-09-14
5.09
Alarm time 1 min later: 20:30:31,Sunday,2025-09-14
5.1
Alarm time 1 min later: 20:31:31,Sunday,2025-09-14
5.09
Alarm time 1 min later: 20:32:31,Sunday,2025-09-14
5.1
<ファイルへの書き込み>
アナログ的に入力電圧を抵抗分割で1/3しているからリアルの電圧に換算してSDカードに書き込み、書き込みデータの最後の方はこんな風になってます
5.09
5.1
5.09
5.1
5.09
5.1
5.07次は電源制御だね、広義にはmicroPythonでどこまで省電力動作できるかどうかということ
<今現在のコード>
おそらく冗長になってると思う、
#!/usr/bin/python
# -*- coding: utf-8 -*-
from machine import Pin, I2C, ADC
import time
import binascii
import machine, sdcard, os
# https://www.waveshare.net/w/upload/0/08/Pico-RTC-DS3231_Sch.pdf
I2C_PORT = 0
I2C_SDA = 20
I2C_SCL = 21
SD_ON = 22
ALARM_PIN = 3
alarm_triggered = False
adc = ADC(Pin(26)) # ADC0 pin
class ds3231():
# 13:45:00 Mon 24 May 2021
# the register value is the binary-coded decimal (BCD) format
# sec min hour week day month year
NowTime = b'\x00\x45\x13\x02\x24\x05\x21'
w = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
address = 0x68
start_reg = 0x00
alarm1_reg = 0x07
control_reg = 0x0e
status_reg = 0x0f
def __init__(self,i2c_port,i2c_scl,i2c_sda):
self.bus = I2C(i2c_port,scl=Pin(i2c_scl),sda=Pin(i2c_sda))
def set_time(self,new_time):
hour = new_time[0] + new_time[1]
minute = new_time[3] + new_time[4]
second = new_time[6] + new_time[7]
week = "0" + str(self.w.index(new_time.split(",",2)[1])+1)
year = new_time.split(",",2)[2][2] + new_time.split(",",2)[2][3]
month = new_time.split(",",2)[2][5] + new_time.split(",",2)[2][6]
day = new_time.split(",",2)[2][8] + new_time.split(",",2)[2][9]
now_time = binascii.unhexlify((second + " " + minute + " " + hour + " " + week + " " + day + " " + month + " " + year).replace(' ',''))
#print(binascii.unhexlify((second + " " + minute + " " + hour + " " + week + " " + day + " " + month + " " + year).replace(' ','')))
#print(self.NowTime)
self.bus.writeto_mem(int(self.address),int(self.start_reg),now_time)
def alarm_irq_handler(self, pin):
global alarm_triggered
alarm_triggered = True
def set_alarm_time(self, alarm_time):
self.alarm_pin = Pin(ALARM_PIN, Pin.IN, Pin.PULL_UP)
self.alarm_pin.irq(handler=self.alarm_irq_handler, trigger=Pin.IRQ_FALLING)
# ステータスフラグクリア
status = self.bus.readfrom_mem(self.address, self.status_reg, 1)
self.bus.writeto_mem(self.address, self.status_reg, bytes([status[0] & 0xFE]))
# コントロールレジスタ設定 (INTCN=1, A1IE=1)
self.bus.writeto_mem(self.address, self.control_reg, b'\x07')
# アラーム時刻設定
hour = alarm_time[0] + alarm_time[1]
minute = alarm_time[3] + alarm_time[4]
second = alarm_time[6] + alarm_time[7]
date = alarm_time.split(",", 2)[2][8] + alarm_time.split(",", 2)[2][9]
now_time = binascii.unhexlify((second + minute + hour + date).replace(' ', ''))
self.bus.writeto_mem(self.address, self.alarm1_reg, now_time)
def get_date(self):
t = self.bus.readfrom_mem(self.address, self.start_reg, 7)
year = 2000 + bcd2dec(t[6])
month = bcd2dec(t[5])
day = bcd2dec(t[4])
return year, month, day
# time format conversion
def bcd2dec(bcd):
return ((bcd >> 4) * 10) + (bcd & 0x0F)
def sdmount_getlist():
sd = sdcard.SDCard(machine.SPI(0), machine.Pin(17))
os.mount(sd, '/sd')
files = os.listdir('/sd') # set to mount point
for file in files:
print(file)
def get_adc_write(filename):
value = round((adc.read_u16() >> 4) * 3.3 * 3 / 4096, 2) # calculate real voltage and round to 2 degits below decimal point
print(value)
with open(filename, 'a') as f:
f.write("{}\n".format(value))
def add_one_minute_to_rtc_time(rtc):
# RTCから生の7バイトを取得(BCD形式)
t = rtc.bus.readfrom_mem(rtc.address, rtc.start_reg, 7)
year = 2000 + bcd2dec(t[6])
month = bcd2dec(t[5] & 0x1F)
day = bcd2dec(t[4] & 0x3F)
hour = bcd2dec(t[2] & 0x3F)
minute = bcd2dec(t[1] & 0x7F)
second = bcd2dec(t[0] & 0x7F)
weekday = t[3] & 0x07 # 1-7
# 月ごとの日数 (うるう年考慮)
def is_leap(year):
return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
def days_in_month(y, m):
mdays = [31, 29 if is_leap(y) else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
return mdays[m-1]
# 1分加算
minute += 1
if minute >= 60:
minute = 0
hour += 1
if hour >= 24:
hour = 0
day += 1
weekday = weekday + 1 if weekday < 7 else 1 if day > days_in_month(year, month):
day = 1
month += 1
if month > 12:
month = 1
year += 1
# 曜日文字列
w = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]
weekday_str = w[weekday-1]
# alarm_time 文字列形式 'HH:MM:SS,Weekday,YYYY-MM-DD'
alarm_time_str = "{:02d}:{:02d}:{:02d},{},{:04d}-{:02d}-{:02d}".format(
hour, minute, second, weekday_str, year, month, day)
return alarm_time_str
# set alrm time period
def set_alarm():
alarm_time_1min_later = add_one_minute_to_rtc_time(rtc)
print("Alarm time 1 min later:", alarm_time_1min_later)
rtc.set_alarm_time(alarm_time_1min_later)
if __name__ == '__main__':
# SD card power control
pow_pin = Pin(SD_ON, Pin.OUT)
pow_pin.value(0)
sdmount_getlist()
# make RTC instance
rtc = ds3231(I2C_PORT,I2C_SCL,I2C_SDA)
#rtc.set_time('15:38:00,Sunday,2025-09-14')
set_alarm()
# create file if not exists or open for append later
year, month, day = rtc.get_date()
filename = "/sd/{:04d}-{:02d}-{:02d}.txt".format(year, month, day)
with open(filename, 'a') as f:
pass # to create if not exist
get_adc_write(filename)
try:
while True:
if alarm_triggered:
alarm_triggered = False
set_alarm()
get_adc_write(filename)
except KeyboardInterrupt:
print("terminated")<写真>
表裏です、裏はもりそばです
admin
部品一式揃ったので、まずはRTC周りの動作確認
パーツだけは載せてみた、配線はまだ終わってないけどRTC動作確認はできる状態
VScodeでのmicroPython使い方としては以下を参考
https://kousaku-prog.com/vscode-micropython/
・拡張機能(MicroPico:VScodeの拡張機能として最も一般的)をインスト、実際はインスト済みであった
・プロジェクト初期化(メニューから以下の画像の機能を選択)して、以下から持ってきたmicroPythonのサンプルプロジェクトを置いとく
% wget -P ~/pico https://files.waveshare.com/upload/5/5a/Pico-rtc-ds3231_code.zip
・microPythonのファーム(2025.8.9版:v1.26.0)をダウンロードしてきて、ディスクモードでラズピコに書き込むと接続状態になる(VScode下端のステータス表示)
・VScodeのターミナルでrunをクリックすると実行される
日時はPythonソースで設定されているだけ
・割り込み処理の受け側がないのでそれを追加、同時に割り込みが配線されてないからハードも修正(汚いけどR5相当をはんだブリッジした、これでGPIO3番につながる)
R5相当をジャンパーしたところ
コード(set_alarm_time())も元のコードでは割り込み待ち処理ないし、割り込み要因も適切じゃないので修正必要で、それは生成A.Iで修正、
#!/usr/bin/python
# -*- coding: utf-8 -*-
from machine import Pin, I2C
import time
import binascii
# the first version use i2c1
#I2C_PORT = 1
#I2C_SDA = 6
#I2C_SCL = 7
# the new version use i2c0,if it dont work,try to uncomment the line 14 and comment line 17
# it should solder the R3 with 0R resistor if want to use alarm function,please refer to the Sch file on waveshare Pico-RTC-DS3231 wiki
# https://www.waveshare.net/w/upload/0/08/Pico-RTC-DS3231_Sch.pdf
I2C_PORT = 0
I2C_SDA = 20
I2C_SCL = 21
ALARM_PIN = 3
class ds3231(object):
# 13:45:00 Mon 24 May 2021
# the register value is the binary-coded decimal (BCD) format
# sec min hour week day month year
NowTime = b'\x00\x45\x13\x02\x24\x05\x21'
w = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
address = 0x68
start_reg = 0x00
alarm1_reg = 0x07
control_reg = 0x0e
status_reg = 0x0f
def __init__(self,i2c_port,i2c_scl,i2c_sda):
self.bus = I2C(i2c_port,scl=Pin(i2c_scl),sda=Pin(i2c_sda))
def set_time(self,new_time):
hour = new_time[0] + new_time[1]
minute = new_time[3] + new_time[4]
second = new_time[6] + new_time[7]
week = "0" + str(self.w.index(new_time.split(",",2)[1])+1)
year = new_time.split(",",2)[2][2] + new_time.split(",",2)[2][3]
month = new_time.split(",",2)[2][5] + new_time.split(",",2)[2][6]
day = new_time.split(",",2)[2][8] + new_time.split(",",2)[2][9]
now_time = binascii.unhexlify((second + " " + minute + " " + hour + " " + week + " " + day + " " + month + " " + year).replace(' ',''))
#print(binascii.unhexlify((second + " " + minute + " " + hour + " " + week + " " + day + " " + month + " " + year).replace(' ','')))
#print(self.NowTime)
self.bus.writeto_mem(int(self.address),int(self.start_reg),now_time)
def read_time(self):
t = self.bus.readfrom_mem(int(self.address),int(self.start_reg),7)
a = t[0]&0x7F #second
b = t[1]&0x7F #minute
c = t[2]&0x3F #hour
d = t[3]&0x07 #week
e = t[4]&0x3F #day
f = t[5]&0x1F #month
print("20%x/%02x/%02x %02x:%02x:%02x %s" %(t[6],t[5],t[4],t[2],t[1],t[0],self.w[t[3]-1]))
def set_alarm_time(self, alarm_time):
self.alarm_pin = Pin(ALARM_PIN, Pin.IN, Pin.PULL_UP)
self.alarm_pin.irq(lambda pin: print("alarm1 time is up"), Pin.IRQ_FALLING)
# ステータスフラグクリア
status = self.bus.readfrom_mem(self.address, self.status_reg, 1)
self.bus.writeto_mem(self.address, self.status_reg, bytes([status[0] & 0xFE]))
# コントロールレジスタ設定 (INTCN=1, A1IE=1)
self.bus.writeto_mem(self.address, self.control_reg, b'\x07')
# アラーム時刻設定
hour = alarm_time[0] + alarm_time[1]
minute = alarm_time[3] + alarm_time[4]
second = alarm_time[6] + alarm_time[7]
date = alarm_time.split(",", 2)[2][8] + alarm_time.split(",", 2)[2][9]
now_time = binascii.unhexlify((second + minute + hour + date).replace(' ', ''))
self.bus.writeto_mem(self.address, self.alarm1_reg, now_time)
if __name__ == '__main__':
rtc = ds3231(I2C_PORT,I2C_SCL,I2C_SDA)
rtc.set_time('17:18:00,Friday,2025-09-12')
rtc.read_time()
rtc.set_alarm_time('17:18:10,Friday,2025-09-12')
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("terminated")割り込み処理が実行できました、
<今の回路図>
前回から手直し、特にRTC周りをオプションの回路図から書き写し
microPythonではdeepsleepとかちゃんと動かないらしいので、microPythonはプロトタイピングで本番はpico-sdkになるかな
admin