ESP-WROOM-02でMicroPythonを使い開発(色々編)

〔ESP32-WROOM-32E〕 〔マイコンのトップに戻る〕
[準備編] [module編] [GPIO編] [通信編] [ファイル編] [OLED編] [WiFi編] [メール編] [並行処理編]  


《タイマー》

タイマー機能は、設定した周期(ms)が経過した後に1回だけ実行される"Timer.ONE_SHOT"と、
設定した周期(ms)で定期的に実行する"Timer.PERIODIC"の2個が有ります。

@ ESP-WROOM-02ボードをUSBでPCに繋ぎます。
A "PyCharm"を起動させ、こちらのCを操作する必要が有ります。(起動時最初のみ設定)
B "main.py"を新規登録して下記スクリプトを"main.py"に貼り付けましょう。
  (登録済みなら上書き貼り付けでも行いましょう)
C ESP8266に書き込みます
  左側プロジェクトウインドウから"main.py"の文字を右クリックをして、[実行(U)'Flash main.py']を
  クリックします。
--------------------------------------------------------------------------------
import time
from machine import Timer, Pin

# LEDの点灯と消灯を交互に行う処理
def LedOnOff(t):
    if led.value() == 0: led.value(1)
    else: led.value(0)

led = Pin(16, Pin.OUT)  # ピン16番(GPIO16)をLED出力で割り付ける
# タイマーオブジェクトを作成し、1秒毎にコールバック関数を呼び出す様に初期化する
tim = Timer(-1)         # 仮想のタイマーなのでid=-1とする
tim.init(period=1000, mode=Timer.PERIODIC, callback=LedOnOff)

start_t = time.ticks_ms()
while True:
    delta = time.ticks_diff(time.ticks_ms(), start_t)
    if delta >= 10000: break  # 10秒で停止
led.value(1)  # LEDを消して置く
tim.deinit()  # タイマーを初期化し解除します
--------------------------------------------------------------------------------
動作は10秒後に終了します、その間に1秒毎にLEDの点灯と消去を繰り返すと言う物です。
注意は、"tim.deinit()"関数を記述し忘れるとコードは停止しているのにLEDの点滅が止まらない事です。
次の注意は、"def LedOnOff(t):"と引数を一つ受ける事です、t は殆ど意味を持たない引数でしょう。

machine.Timer
関数に意味を持たせた引数を与えたい場合は、以下の様にすると良いでしょう、たぶん。
tim.init(period=1000, mode=Timer.PERIODIC, callback=lambda t: LedOnOff(t))
"lambda"は匿名の関数らしい、ここをみましょう。(英語だけどね)

詳しい説明は、”クラス Timer -- ハードウェアタイマーの制御”を参照してください。

《ディープスリープ》

machine.deepsleep

ここでは、60秒後にディープスリープモードに入り10秒後に目覚めるサンプルです。

@ ピン16番(GPIO16)とリセットピンを接続して置きます。
  (ESP8266は、目覚める時に"alarm"がピン16番に出力するのでリセットさせる為です)
  又、ピン4番(GPIO4)にLEDを配線すれば解りやすいでしょう。
A ESP-WROOM-02ボードをUSBでPCに繋ぎます。
B "PyCharm"を起動させ、こちらのCを操作する必要が有ります。(起動時最初のみ設定)
C "main.py"を新規登録して下記スクリプトを"main.py"に貼り付けましょう。
  (登録済みなら上書き貼り付けでも行いましょう)
D ESP8266に書き込みます
  左側プロジェクトウインドウから"main.py"の文字を右クリックをして、[実行(U)'Flash main.py']を
  クリックします。
--------------------------------------------------------------------------------
import machine
import time

led = machine.Pin(4, machine.Pin.OUT)  # ピン4番(GPIO4)をLED出力で割り付ける
# RTCのオブジェクト作成とアラームによってトリガーされる irq オブジェクトの作成
rtc = machine.RTC()
rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP)
rtc.alarm(rtc.ALARM0, 70000)  # 70秒後におこす(sleepに入り10秒後)

print('\r\nStart')
cnt = 0
led.on()
while True:
    if cnt >= 600 :         # 約60秒後処理
        led.off()           # LED消灯
        print('Go to deepsleep')
        machine.deepsleep() # ディープスリープに入る
        print('pass')
    cnt = cnt + 1
    time.sleep_ms(100)      # 100msで繰り返す
--------------------------------------------------------------------------------
E 60秒以内に"PyCharm"のREPLを起動しましょう。
  コードが停止しているので[CTRL]+[D]で再起動します。
  "print"文が表示されて解かり易いと思います。

おそらくぅ"rtc.alarm()"は"machine.deepsleep()"のみしか起こせない様です
詳しい説明は、ここ、RTCはここをを参照しましょう。
又、"Pin.irq()"には"wake"オプションは使えないのでピンの外部割込みで起こせないでしょう

※ 注意は、ディープスリープ中はUARTもシャットダウンしているのでプログラム書き込み等の操作は
  できません

  (リセットボタンON後、プログラム起動してLEDが点灯している間に書き込みましょう)
  (又は、LEDが点灯している間に"main.py"を削除しましょう)
  (或いは"machine.deepsleep(10000)")とか記述して10秒後に目覚めさせる?)

esp.deepsleep

今度は"esp"モジュールでのディープスリープ、60秒後にディープスリープモードに入り30秒後に
目覚めるサンプルです、但し、ピン16番(GPIO16)とリセットピンは接続して置きますよ、
そうしなかった場合は、手動でリセットボタンを押すまでは永遠に眠ったままです
--------------------------------------------------------------------------------
from machine import Pin
import esp
import time

led = Pin(4, Pin.OUT)  # ピン4番(GPIO4)をLED出力で割り付ける

print('\r\nStart')
cnt = 0
led.on()
while True:
    if cnt >= 600 :         # 約60秒後処理
        led.off()           # LED消灯
        print('Go to deepsleep')
        # ディープスリープに入り30秒後に目覚める
        esp.deepsleep(30000000)
        print('pass')
    cnt = cnt + 1
    time.sleep_ms(100)      # 100msで繰り返す
--------------------------------------------------------------------------------
こちらはRTCの設定はいらないおそらく"esp.deepsleep"内で設定しているのでしょう?。
スリープに入るまで少し時間が要るのかも"print('pass')"が実行されている
"esp"モジュールの詳しい説明は、ここを参照してください。

《RTCとntptime》

REPLでhelp(RTC)操作
 どうやら2000年1月1日 00:00:00 UTC のエポックを
 使っている様です。

 datetime()は、
 [年][月][日][曜日(土)][時][分][秒][マイクロ秒]
 曜日は、"0"が月曜から"6"の日曜までのかんじぃ
 因みにtime.localtime()は、
 [年][月][日][時][分][秒][曜日(土)][経過日数]です。

memory()は、
"RTC.memory('Hello')"とかメモリにb'Hello'と保存されます、
電源がON中はリセットされても残っている(リセットの内容によってはクリアされる場合が有る)
電源切れても残っていないとぉ意味ねぇ〜
クラス RTC -- リアルタイムクロックを見ましょう。

RTC.alarm

RTC.irq()は、" handler"が使えない様だエラーが出る"wake=machine.DEEPSLEEP"は使えそう。
RTC.alarm()の"repeat=True"も使えない、"time"指定のみの様に思えます、
なので、何日何時の時間にコールバック関数を起動とかダメですたぶん、
おそらくぅDEEPSLEEP起動にしか使えない様な気がしています。
(ああでもない、こうでもないと1日潰したぞぉ!! あ、ESP8266だけかもね)

ntptime

REPLでhelp(ntptime)操作  NTPサーバーに接続して現在時刻を得る事が
 出来る様ですねチョットぉやってみます。
 サーバーの接続先は"pool.ntp.org"です、
 接続先は変更できます。
 NTPサーバーは1900年1月1日00:00:00(UTC)
 からの経過秒数で送ってきます、
 ESP8266は、2000年1月1日 00:00:00ですね
 だからESPに合わせる為の経過秒数が
 NTP_DELTAの値です。

@ ESP-WROOM-02ボードをUSBでPCに繋ぎます。
A "PyCharm"を起動させ、こちらのCを操作する必要が有ります。(起動時最初のみ設定)
B "main.py"を新規登録して下記スクリプトを"main.py"に貼り付けましょう。
  (登録済みなら上書き貼り付けでも行いましょう)
C コード内に記述している"ESSID"/"Password"は自分ちのルータ等のアクセスポイントに変更します
D ESP8266に書き込みます
  左側プロジェクトウインドウから"main.py"の文字を右クリックをして、[実行(U)'Flash main.py']を
  クリックします。
--------------------------------------------------------------------------------
import time
from machine import RTC
import network
import ntptime

time.sleep(30)  # 30秒後に開始するこの間にREPLを起動しましょう。

ESSID = "BBUser"
Password = ""
# Wi-Fi 接続を設定する為にクライアントオブジェクトのインターフェースを作成する
sta_if = network.WLAN(network.STA_IF)
if not sta_if.isconnected():
    sta_if.active(True)
    sta_if.connect(ESSID, Password)  # ステーションインターフェイスを有効にする
    while not sta_if.isconnected():  # WiFiネットワークに接続する
        pass
print('\r\n[network config]\r\n', sta_if.ifconfig())

rtc = RTC()                     # RTCのオブジェクト作成
# (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60
ntptime.NTP_DELTA = 3155641200  # 更にタイムゾーンを引いた値
# "pool.ntp.org"サーバーに接続している
# 他のサーバーに接続したいなら(例:host = "ntp.nict.jp")とする
ntptime.settime()               # サーバからの日時を rtc に設定
print('Finished setting to RTC')
sta_if.active(False)            # Wi-Fi 接続を切る

while True:
    print(rtc.datetime())       # 日時を UTC で取得
    time.sleep((1))
--------------------------------------------------------------------------------
動作は30秒後に起動します、この間にREPLを動かしましょう。
こんなに簡単すぎて良いのだろうか?...あぁ、PICが遠くに感じられる。(´-`).。oO(..pic..C...)

※ RTCの既知の問題としてこんな問題があるそうです、ぜひ読みましょう。

≪おまけ≫

"ntptimeGET.zip"をダウンロードし解凍後、ESP8266の"/"か"lib/"の下に書き込んで置きましょう。
あ、"ESSID"/"Password"は書き換えますよ!
>>> import ntptimeGET
とREPLで操作するだけでRTCに現在時刻が設定されて便利ですよ、とっても! v( ̄∇ ̄)v

《CPU 周波数の変更》

REPLで周波数の変更操作  ESP8266は、クロック周波数が80Mhzと160MHz
 切り替えができるらしい、デフォルトは80MHzです。

 160MHzに切り替えても起動時は80MHzに戻ります

《jsonファイル読書き》

json型式ファイルの読み書き操作を行ってみます。
この話は、”JSON のエンコードとデコード”とここを参照しましょう。
それとぉ、ここ(Python)とここここを参考にしましょう。

@ "SKesplib.zip"をダウンロードし解凍後しましょう。
A ESP8266の"/"か"lib/"の下に書き込んで置きましょう。

ConfigPUT/GET

SKesplib.py
このスクリプトの中にコンフィグファイル(jsonファイル型式)の読み書きを行う関数が含まれています。
コンフィグファイルは、ESP8266の初期設定値やセンサー値等の保存(EEPROM替り?)に役立つと思います

 ・ConfigPUT(key, val)
  コンフィグファイル(jsonファイル型式)に[キー][値]を書き込みます。
  ファイル(SKconfig.json)が存在しない時は、指定値で作成されます。
  指定の[キー]値が有れば変更され、無ければ追加されます。
  key = キー値(文字列でなければなりません)
  val = 値(文字列か数値、又はTrue/False)

 ・ConfigGET(key)
  コンフィグファイル(jsonファイル型式)から指定[キー]値の値を得ます
  key = 読み込む値のキー値(文字列でなければなりません)
  return = キーに対する値を返します、キー値が無い場合は"None"が返ります。
       又、ファイルが存在しない場合も"None"が返ります。

《FIFOバッファ》

"ucollections"モジュールの”コレクションとコンテナのデータ型”を利用すればFIFO型のバッファが
出来そうです、"ucollections.deque()"クラスを使います。
"deque.append()"メソッドでデータを入れて、"deque.popleft()"メソッドでデータを取出す感じです。

REPLでucollectionsを操作
例は3個のバッファを作っているので、
4個目のデータが入ったら古い1個目のデータは破棄されています。
でぇ、取り出しデータが無い時は"IndexError"が発生しているようですね。

これが出来ると、通信等でバッファにデータを溜める事が可能ですじゃ〜、
出来たらデータが溜まっているのかの関数等が欲しかったわい。

《データベース》

こちらの”単純な BTree データベース”をもう少し扱いやすくしたライブラリを作成してみました。
これは、有名な BerkelyDB ライブラリ、バージョン 1.xx をベースにしてあるらしい。
作成したライブラリは"BDBクラスSKesplib.py"に入れています。

REPLでBDB操作1
ファイルが存在しない場合は作成されます。
"BDB()"だと"put"時に指定したキーが存在する場合は上書きされます、デフォルトです。
"BDB(BDB.NOOVERWRITE)"は上書きされず、例外エラー(KeyError:The key exists)を発生させます

REPLでBDB操作2
"put(key,data)"は、文字列で設定します、読み込み時も文字列で返します。
データは昇順に並び替えて読み込めます。

REPLでBDB操作3
"get()"も"delete()"も存在しないキーを指定した場合は"None"が返されます。

REPLでBDB操作4
最後は必ずクローズしましょう。




[並行処理編へ] [ページ上へ]


【きむ茶工房ガレージハウス】
Copyright (C) 2006-2021 Shigehiro Kimura All Rights Reserved.