MicroPythonのマイクロファン専用ファームウェア

ドライバとライブラリ

MicroPythonで入出力装置やセンサーを使用したプログラミングを行う際には、一般的に、あらかじめそれらを制御するドライバーやライブラリを開発ボードに組み込んでおく必要があります。このため、使用する入出力装置やセンサーに対応した適切なドライバーやライブラリを探して取得し、さらに開発ボードのファイルシステムに登録しておくことは、特に初心者にとっては面倒な作業になります。

マイクロファンは、このような面倒な準備作業を軽減できるように、マイクロファンの開発ボード専用のMicroPythonファームウェアを配布しています。このファームウェアには、マイクロファンの開発ボードで標準的に使用する入出力装置やセンサーなどのドライバーやライブラリがあらかじめ組み込まれており、開発ボードに専用ファームウェアを書き込めば、その開発ボードで使用する様々な入出力装置やセンサーを使用したプログラムをすぐに開発することができるようになります。

専用ファームウェア

マイクロファンの専用ファームウェアは以下のページから取得できるので、マイクロファンの開発ボードに書き込んでご利用ください。下記のページには、ドライバーやライブラリの組込み以外のマイクロファンの専用ファームウェアの追加機能なども記載されているのでご確認ください。


MicroPythonプログラミング

以下に、専用ファームウェアを書き込んだ開発ボードの使用法を説明します。専用ファームウェアの固有機能を使っている部分があるので、MicroPythonのオリジナルのファームウェアを書き込んだ開発ボードではここで示す方法では利用できないことがあります。

ここでのプログラム例の多くは、ESP32(-S3)-KEY-R2やESP32(-S3M)-SLIMにOLEDディスプレイが接続されていることを前提にしています。

また、センサー類や圧電スピーカーは、上記の開発ボードには装備されていませんが、SENSOR-PLUSを接続することで、ESP32-C3M-TRYと同様に利用することができます。

以下にMicroPythonのプログラム例を示しますが、合わせてMicroPythonのサイトのESP32用クイックリファレンスのページもご参照ください。


LED

LEDの点灯

マイクロファンのESP32開発ボードには、マイクロコントローラから点滅を指示できるLEDが搭載されています。そのLEDをMicroPythonで操作する方法を示します。

ESP32のMicroPythonでは、一般的にはLEDが接続されている端子番号を使用して、制御用端子の指定や制御を行います。マイクロファンのファームウェアでは、LED制御用の端子に、'LED'および'LED1'という機能名が付けられており、端子番号ではなく機能名で指定することができます。(もちろん、従来通り、端子番号で指定することもできます。)

from machine import Pin
import time

led1 = Pin('LED1', Pin.OUT)
led1.on() # 正論理の場合には点灯、負論理の場合には消灯
time.sleep_ms(1000) # 1000ms, 1秒待つ
led1.off()
time.sleep_ms(1000)
led1.on()

このプログラムは、単純に1秒ごとにLEDのON, OFFを行っています。

LEDは開発ボードにより、正論理(ONの際に点灯する)と負論理(OFFの際に点灯する)の構成があり、上記のプログラムでLEDが2回点灯するものは正論理のLED、1回だけ点灯するものは負論理のLEDであることが確認できます。(このプログラムを使わなくても、回路図を確認すればすぐわかることですが。。。)

マイクロファンはいくつかのESP32開発ボードを提供しており、開発ボードによってLEDが接続されている端子番号が異なります。このため、LEDの操作をしようとすると、LEDの端子番号を確認したり、プログラムを他の開発ボードに移植しようとすると、端子番号を変更する必要があります。

しかしながら、マイクロファンのMicroPythonファームウェアでは、このように機能名でLEDを指定できるので、端子番号を調べたり、移植の際に端子番号を変更したりする必要がありません。

LEDの点滅

LEDを一定間隔で点滅するプログラムを示します。

from machine import Pin
import time

led1 = Pin('LED1', Pin.OUT)
while True:
    led1.on()
    time.sleep_ms(1000) # 1000ms, 1秒待つ
    led1.off()
    time.sleep_ms(1000)

# CTRL-Cで中断

このプログラムの様に、点灯している期間と消えている期間が同じ設定だと、LEDが正論理か負論理かは関係ありませんが、異なる設定だと、点灯時間を長くするのか消灯時間を長くするのか、on(),off()と待ち時間の関係を間違えないようにする必要があります。

LEDの明暗制御

LEDはPWMを使用して、単純に点灯、消灯だけでなく、明暗の度合いを制御できます。

PWMを使用してLEDの明暗を制御するプログラムを示します。

from machine import Pin, PWM
import time

led1 = PWM(Pin('LED1'), freq=1000)

delta = 1
duty = 0
while True:
    duty += delta
    if duty == 1023:
        delta = -1
    elif duty == 0:
        delta = 1
    led1.duty(duty) # 0-1023
    time.sleep_ms(2)

# CTRL-Cで中断

LEDをPWMで制御するように初期化し、Whileループの中で、PWMのデューティー比を増減させて、LEDの明暗を変化させています。


スイッチ

スイッチによるLEDの点灯

ESP32開発ボードには、開発ボードをブートローダーモードに移行させるためのスイッチが搭載されていますが、そのスイッチを利用者のプログラムでも利用することができます。

このスイッチを使用して、スイッチを押したときにLEDが点灯し、スイッチを離したときにLEDが消灯するプログラムを以下に示します。

from machine import Pin

led1 = Pin('LED1', Pin.OUT)
sw1 = Pin('SW1', Pin.IN)
while True:
    led1.value(not sw1.value())

# CTRL-Cで中断

スイッチもLEDと同様に、端子番号で指定・制御することができますが、マイクロファンのファームウェアでは、SW1に'SW1'という機能名が割り当てられているため、その機能名で端子を指定することができます。

ESP32開発ボードのSW1は負論理となっており、スイッチが押されたときにoffもしくは0、離されている時にonもしくは1となります。このプログラムでは、正論理のLEDを接続している場合のもので、負論理のスイッチの読み取り結果を 'not' を付けて正論理に変換してLEDの引数としています。

開発ボードによりますが、LEDが負論理の場合には、'not'を削除してください。


圧電スピーカー

明るく光るLEDは出力装置として魅力的ですが、音を出す圧電スピーカーも電子工作では外せませんね。圧電スピーカーは圧電素子を使ったスピーカーで、ESP32-C3M-TRYなどに搭載されているものは直径が1センチ程度の小さなものです。

圧電スピーカーを操作するTONEドライバーは、マイクロファンのファームウェアにあらかじめ組み込まれているため、改めて導入する必要などはありません。

他の多くの開発ボードには、初期状態では搭載されていませんが、必要に応じて購入して適当な端子(出力端子)に接続して使用することができます。

異なる周波数の音の出力

周波数が100Hzから1000Hzまで、100Hzごとに周波数を上げて音を出力するプログラム例を示します。(実際に出力される音(の高さ)は、圧電スピーカーの特性によるのか、ちょっと違和感があります。)

圧電スピーカーをESP32-KEY-R2/SLIMの23番端子に接続した場合のプログラム例を示します。使用する端子は、入力専用の端子以外であれば変更することができます。

from tone import TONE
import time

snd = TONE(23) # 端子23とGNDに圧電スピーカーを接続した場合

for hz in range(100,1001,100): # 100Hz -1000Hz
    snd.on(hz)
    time.sleep_ms(500)
    
snd.off()

ESP32-C3M-TRY用のファームウェアを使用している場合、圧電スピーカーが接続されている端子には'SND'という機能名が割り当てられているので、23のような端子番号の代わりに、'SND'を指定できます。

スイッチによる音の出力

スイッチを押すと音が鳴るプログラム例を示します。

from machine import Pin
from tone import TONE
import time

snd=TONE(23) # 端子23とGNDに圧電スピーカーを接続した場合
sw1=Pin('SW1', Pin.IN)

while True:
    if (sw1.value() == 0): # スイッチが押されたとき
        snd.on(400)
    else:
        snd.off()
    time.sleep_ms(100)

# CTRL-Cで中断

OLEDディスプレイ

OLEDディスプレイを使用するためには、そのドライバーが必要ですが、マイクロファンのMicroPythonファームウェアには、あらかじめOLEDディスプレイ用のドライバーが内蔵されているので、そのインストール作業などを行うことなく利用することができます。

ここで使用例を示すssd1306の説明書を以下に示すので、参考にしてください。

OLEDディスプレイ表示用のドライバは、FrameBufferというクラスをベースに作成されています。したがって、OLEDディスプレイ表示用のドライバで使用できるメソッド(文字の表示やグラフィックス)の多くは、FrameBufferの説明書で確認することができます。以下にFrameBufferの説明書を示すので、参考にしてください。

OLEDディスプレイへの文字表示

コントローラにSSD1306を使用した0.96インチのOLEDディスプレイに文字列を表示するプログラム例を示します。

I2Cの引数には、一般的にはコメントで書いている例のように、それぞれのMCUやボードの端子の設定に合わせたSCL,SDA端子の指定が必要です。しかしながら、マイクロファンのファームウェアを使用している場合には、ファームウェアの中に端子情報が埋め込まれているため、明示的に端子を指定する必要はありません。このため、異なる開発ボードを使用する場合でも、I2Cの初期化処理の端子設定など、開発ボードごとの個別の情報に惑わされずプログラムを書くことができます。

from machine import Pin, I2C
from ssd1306 import SSD1306_I2C

i2c = I2C(0)
# i2c = I2C(0, scl=Pin(9), sda=Pin(8), freq=400000) # ESP32-S3, ESP32-C3
# i2c = I2C(0, scl=Pin(22), sda=Pin(21), freq=400000) # ESP32
# i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000) # ESP8266
# i2c = I2C(0, scl=Pin(13), sda=Pin(12), freq=400000) # RP2040
oled = SSD1306_I2C(128, 64, i2c)

oled.text('- SENSOR-PLUS -', 8, 0) # 第二引数は文字を出力する横のピクセル座標、第三引数は縦のピクセル座標
oled.text('MicroFan', 32, 8)
oled.text('OLED Display', 0, 16)
oled.text('Piezo Speaker', 0, 24)
oled.text('Brightness SNSR', 0, 32)
oled.text('Temp. Hum. SNSR ', 0, 40)
oled.text('Accelerometer', 0, 48)
oled.text('WS2812 RGB LED', 0, 56)
oled.show() # 操作結果を画面に反映させる

ssd1306での文字出力は、文字を出力する座標を毎回指定する必要があります。グラフィックス表示と合わせて文字表示をする場合には役立ちますが、文字だけを出力する場合には、少々面倒です。

また、文字もグラフィックスも、表示の指示をしただけではOLEDディスプレイの画面に表示されず、show()メソッドを呼び出した時点で初めてすべての表示指示が画面に反映されます。

OLEDディスプレイへのコンソール的文字表示

何を言っているかわかりにくいのですが、OLEDディスプレイに文字を表示する際に、文字を表示する座標を明示せずに出力できる機能を備えたドライバを作成しました。oledcsもマイクロファンのMicroPythonファームウェアに組み込まれているので、導入作業などをせずに利用できます。

利用法は簡単で、単に出力したい文字列をprintln()あるいはprint()メソッドで出力するだけです。文字の出力位置は、ドライバが自動的に管理してくれますし、いちいちshow()メソッドを利用する必要もありません。

メッセージやデータをOLEDディスプレイに表示する場合には、ssd1306を使用するよりも、oledcsを使用したほうが手軽で便利でしょう。なお、oledcsはssd1306を継承して作成されているため、ssd1306の機能もそのまま利用できます。

from machine import I2C
from oledcs import OLEDCS_I2C
import time

i2c = I2C(0)
oled = OLEDCS_I2C(128, 64, i2c)

oled.println('123456789012345678901234567890')
time.sleep(3)

for i in range(1,20):
    oled.print('OLED-')
    oled.println('{:.3f}'.format(1/i))
time.sleep(3)

oled.println('OLEDCS Driver for MicroPython')

oledcsの詳細は、以下のページをご参照ください。

OLEDディスプレイへの日本語表示

OLEDディスプレイに日本語列を表示するプログラム例です。

日本語表示機能を持ったOLEDドライバoledjpや日本語フォントは、MicroPythonのファームウェアにあらかじめ組み込まれていますので、それらの導入作業をしなくても、プログラムを動かすことができます。

oledjpは、ssd1306の上位互換ドライバとなっていますので、ssd1306ドライバを使っているプログラムでは、日本語を使っていなくてもssd1306をoledjpに置き換えてもかまいません。

from machine import I2C
from oledjp import OLEDJP_I2C

i2c = I2C(0)
oled = OLEDJP_I2C(128, 64, i2c) # 日本語表示機能付きOLEDドライバ
oled.setFont(OLEDJP_I2C.MISAKI) # 日本語フォントの利用設定

str = "マイクロファンのESP32開発ボードには、OLEDディスプレイを接続でき、開発ボード単体でセンサやネットワークなどの様々な情報を手軽に表示できます。また、日本語表示が行えるMicroPython用ライブラリも提供しています。"
oled.print(str)

OLEDドライバoledjpに関しては以下のページをご参照ください。

OLEDディスプレイへのグラフィックス表示

コントローラにSSD1306を使用した0.96インチのOLEDディスプレイにグラフィックス表示するプログラム例です。

from machine import I2C
from ssd1306 import SSD1306_I2C
import time

i2c = I2C(0)
oled = SSD1306_I2C(128, 64, i2c)

oled.fill(0) # 画面のクリア
for y in range(0,64,8):
    oled.line(0,0,127,y,1) # 斜線
    oled.show()

for x in range(127,0,-8):
    oled.line(0,0,x,63,1) # 斜線
    oled.show()

time.sleep_ms(500)

oled.fill(0) # 画面のクリア
for n in range(0,32,4):
    oled.rect(64-n*2,32-n,n*4,n*2,1) # 方形
    oled.show()

time.sleep_ms(500)

oled.fill(0) # 画面のクリア
for n in range(0,32,2):
    oled.fill_rect(64-n*2,32-n,n*4,n*2,1) # 塗潰し方形
    oled.show()

time.sleep_ms(500)

oled.fill(0) # 画面のクリア
for n in range(2,32,2):
    oled.ellipse(64,32,n*4,n*2,1) # 楕円
    oled.show()

time.sleep_ms(500)

oled.fill(0) # 画面のクリア
for n in range(2,18,2):
    oled.ellipse(64,32,n*4,n*2,1,True) # 塗潰し楕円
    oled.show()

WS2812カラーLED

ESP32-S3-KEY-R2は3個のカラーLEDを実装しています。

RGB表示

3個のWS2812タイプのカラーLEDに赤、緑、青色を出力するプログラム例です。

各LEDの明るさは、0-255の範囲で指定できますが、LEDの点灯確認目的であれば、10程度の明るさ指定でも十分な明るさで発光します。

# Ws2812 カラーLEDの点灯
from neopixel import NeoPixel
from machine import Pin

rgb = NeoPixel(Pin('RGB', Pin.OUT), 3)
rgb[0] = (10,0,0) # 赤
rgb[1] = (0,10,0) # 緑
rgb[2] = (0,0,10) # 青
rgb.write() # 全ピクセルにデータ書込み

neopixelライブラリの利用法は、以下のページをご参照ください。

1/fゆらぎを利用したLEDキャンドル

1/fゆらぎを利用して、1個のカラーLEDをキャンドルの様に光らせるプログラム例です。

ESP32-S3-KEY-R2では、下記ページのプログラムでNeoPixelコンストラクタの引数として指定するLEDの端子機能名は、’RGB’に変更してください。


WiFi

WiFi機能の利用は、ESP32の本領発揮ですね。

アクセスポイントの確認

ESP32のWiFi機能を有効化して、周辺のアクセスポイントをリスト表示するプログラム例です。

import network

wifi = network.WLAN(network.STA_IF) # クライアントとして設定
wifi.active(True) # WiFiを有効化

sta = wifi.scan() # アクセスポイントをスキャン
# print(sta)

authmodes = ['Open', 'WEP', 'WPA-PSK' 'WPA2-PSK', 'WPA/WPA2-PSK', '?5', '?6', '?7', '?8', '?9', ]
for (ssid, mac, channel, rssi, auth, hidden) in sta:
    name = ssid.decode()
    print("*", name if name != "" else "???")
    print("  - Auth:", authmodes[auth])
    print("  - Channel:", channel)
    print("  - RSSI:", rssi)
    print("  - MAC: {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}".format(*mac))
    print()

このプログラムは、アクセスポイントをスキャンするだけなのでSSIDやパスワードは不要です。

NTPを使用した時刻同期

NTPプロトコルを使用して、RTCを設定するプログラムです。

ESP32は目が覚めた時は今何時なのかわかってないのですが、バッテリーバックアップされたRTCがなくてもいつでも正確な時間を利用できるので、ネットワークが使えると便利ですね。

import network
import ntptime
import utime
import time
from machine import RTC

ssid = 'YOUR_SSID'
passwd = 'YOUR_PASSWD'

def wifi_connect(ssid, passwd): # アクセスポイントへの接続
    wifi = network.WLAN(network.STA_IF)
    wifi.active(True)
    if not wifi.isconnected():
        print('connecting to network...')
        wifi.connect(ssid, passwd)
        while not wifi.isconnected():
            print('.',end='')
            time.sleep_ms(500)
        print()
    return wifi

wifi = wifi_connect(ssid, passwd)
print('network config:', wifi.ifconfig()) # 接続時のIP情報表示

rtc = RTC() # リアルタイムクロックを取得
print("RTC初期値:", rtc.datetime()) # 2000/1/1になっていなければ、Thonnyの設定オプションが有効

print('--- NTP同期')
ntptime.settime() # RTCをNTPと同期
print("utime:", utime.localtime()) # 設定された時刻はグリニッジ標準時相当:任本の時間JSTじゃない
print("RTC設定値:", rtc.datetime()) # 同上:データの順序と内容が微妙に違う。。。

print('--- RTCをJSTに')
JST_OFFSET = 9 * 60 * 60 # 9時間(32400秒)
ut = utime.localtime(utime.time() + JST_OFFSET)
rtc.datetime((ut[0], ut[1], ut[2], ut[6]+1, ut[3], ut[4], ut[5], 0))
print("RTC(JST):", rtc.datetime())

天気予報

気象庁が提供する天気予報データを利用するプログラム例です。

import network
import urequests
import ujson
import time

ssid = 'YOUR_SSID'
passwd = 'YOUR_PASSWD'

def wifi_connect(ssid, passwd): # アクセスポイントへの接続
    wifi = network.WLAN(network.STA_IF)
    wifi.active(True)
    if not wifi.isconnected():
        print('connecting to network...')
        wifi.connect(ssid, passwd)
        while not wifi.isconnected():
            print('.',end='')
            time.sleep_ms(500)
        print()
    return wifi

wifi = wifi_connect(ssid, passwd)
# print('network config:', wifi.ifconfig())

# 気象庁予報データの取得:福岡県
jma_url = "https://www.jma.go.jp/bosai/forecast/data/forecast/400000.json"
forecast_json = urequests.get(jma_url).json()

forecast_major = forecast_json[0]["timeSeries"][0] # 参照データセットの選択
forecast_date = forecast_major["timeDefines"][0] # 0:福岡県の最初の地域:福岡地方
forecast_weather = forecast_major["areas"][0]["weathers"][0]
forecast_wind = forecast_major["areas"][0]["winds"][0]

print(forecast_date)
print(forecast_weather.replace(' ', '')) # 全角スペースを削除して表示
print(forecast_wind.replace(' ', '')) # 全角スペースを削除して表示