LoginSignup
7
4

More than 1 year has passed since last update.

MicroPython「machine」モジュールを調べてみる

Posted at

はじめに

本当はRaspberry Pi 4 Model Bあたりが欲しかったのですが、昨今の半導体不足等のせいで手に入らず、仕方なくPicoを購入しました。
しかし、できることは限られるので、この際だからMicroPythonを使ってみることにしました。

目的

とりあえずは、Raspberry Pi PicoをMicroPythonで動かすこと。
便利そうなら、他のマイコンもMiroPythonで動かすことを考えたいです。

今回やること

どうやら「machine」モジュールが肝となっていそうなので、その理解を進めます。

ぶっちゃけ、公式ドキュメントのまとめになります。
https://micropython-docs-ja.readthedocs.io/ja/latest/library/machine.html

「machine」モジュール

  • 特定のボード上のハードウェアに関連する固有の関数を含んでいる
  • いくつかの「関数」と「定数」と「クラス」を持っている

以降、良く使うそうな機能だけをざっくりと説明していきます。

関数

  • リセット関連
    • リセット:reset()
    • ソフトリセット:soft_reset()
    • リセットの原因の取得:reset_cause()
    • ブートローダーの起動:bootloader()
  • 割り込み関連
    • 無効化/有効化:disable_irq()/enable_irq()
  • 電力関連
    • CPU周波数の取得:freq()
    • アイドリング:idle()
    • スリープ(長期/短期):lightsleep()/deepsleep()
    • 起床の原因の取得:wake_reason()
  • その他
    • ボード/SoCのIDの取得:unique_id()
    • パルスの持続時間の取得:time_pulse_us()
    • ビット送信:bitstream()
    • 乱数の取得:rng()

定数

※省略

クラス

用意されているのは、以下の14クラス。

  • Pin:I/Oピンの制御
  • Signal:外部I/Oデバイスの制御
  • ADC:アナログ-デジタル変換
  • ADCBlock:ADCペリフェラルの制御
  • PWM:パルス幅変調
  • UART:二重シリアル通信バス
  • SPI:シリアルペリフェラルインターフェースバスプロトコル(コントローラ側)
  • I2C:2線式シリアルプロトコル
  • I2S:IC間(Inter-IC Sound)サウンドバスプロトコル
  • RTC:リアルタイムクロック
  • Timer:ハードウェアタイマーの制御
  • WDT:ウォッチドッグタイマー
  • SD:セキュアデジタルメモリカード
  • SDCard:SDメモリカード

このうち、重要そうなもの(赤文字)だけ説明します。

Pinクラス

GPIOピンへのデジタル制御(ON/OFF)で使用。
(例)LEDの点灯

  • ピン番号(+入出力)を指定して、インスタンス(オブジェクト)を生成
  • ON/OFFを入出力
from machine import Pin

# ピン #0 を出力ピンとして作成
p0 = Pin(0, Pin.OUT)

# 値をロー、ハイと順に設定
p0.value(0)
p0.value(1)

# ピン #2 をプルアップ抵抗付きの入力ピンとして作成
p2 = Pin(2, Pin.IN, Pin.PULL_UP)

# ピンの値を読み込んで表示
print(p2.value())

# ピン #0 を入力モード&プルダウン抵抗指定で再設定
p0.init(p0.IN, p0.PULL_DOWN)

# irq コールバックを設定
p0.irq(lambda p:print(p))

ADCクラス

アナログ値(電圧の変動)をデジタル値に変換して取得。
(例)ボリューム値の取得

  • チャンネル(ピン)を指定してインスタンス(オブジェクト)を生成
    • 各チャンネルがどのGPIOピンに割り当てられているのかは、ハードウェアによる
  • 現在値の読み込み
    • uint(0~65,535でスケーリング)、または、マイクロボルト値
from machine import ADC

adc = ADC(pin)        # 指定のピンで動作する ADC オブジェクトを作成
val = adc.read_u16()  # 生のアナログ値を 0-65535 の範囲で読込み
val = adc.read_uv()   # アナログ値をマイクロボルトで読込み

PWMクラス

パルス幅を変調した信号を出力。
(例)LEDの明るさの制御

  • ピンを指定して、インスタンス(オブジェクト)を生成
  • 周波数、パルス幅を指定
from machine import PWM

pwm = PWM(pin)          # 指定のピンの PWM オブジェクトを作成
pwm.duty_u16(32768)     # パルス幅を 50% に設定

# 200us の周期、デューティ比を 5us で再初期化
pwm.init(freq=5000, duty_ns=5000)

pwm.duty_ns(3000)       # 3us のパルス幅を設定

pwm.deinit()

UARTクラス

二重(送受信)シリアル通信を実装。
バイトデータ(文字など)をやり取りする感じ。
image.png
(例)CO2センサー(MH-Z19Cなど)との通信

  • ピンを指定して、インスタンス(オブジェクト)を生成
  • 通信速度、ビット数などを設定
  • 複数バイトを送受信
from machine import UART

uart = UART(1, 9600)                         # 与えたボーレートで初期化
uart.init(9600, bits=8, parity=None, stop=1) # 与えたパラメータで初期化

uart.read(10)       # 10文字を読み込んで、bytes 型オブジェクトを返す
uart.read()         # 可能な限り文字を読み込む
uart.readline()     # 1行を読み込む
uart.readinto(buf)  # 読み込んで、与えたバッファに格納
uart.write('abc')   # 3文字を書き込む

SPIクラス(SoftSPIクラス)

同期通信を実装。
バイナリデータをやり取りする感じ。
ソフトウェアSPIも可。
image.png
(例)OLEDディスプレイ(SSD1306など)との通信

  • IDを指定して、インスタンス(オブジェクト)を生成
    • 各IDがどのGPIOピンに割り当てられているのかは、ハードウェアによる
  • 通信速度、ビット数などを設定
  • 複数バイトを送受信
from machine import SPI, Pin

spi = SPI(0, baudrate=400000)           # 周波数 400kHz で SPI ペリフェラル 0 を作成
                                        # ユースケースによっては、追加のパラメータが必要な場合があります。使用するバスの
                                        # 特性やピンを選択するための追加のパラメータが必要になる場合があります。
cs = Pin(4, mode=Pin.OUT, value=1)      # ピン 4 でチップセレクトを作成。

try:
    cs(0)                               # ペリフェラルを選択。
    spi.write(b"12345678")            # 8 バイトを書き出し、受信データについては無視。
finally:
    cs(1)                               # ペリフェラルを選択解除。

try:
    cs(0)                               # ペリフェラルを選択。
    rxdata = spi.read(8, 0x42)          # 0x42 をバイトごとに書き出しながら、合計 8 バイトを読み込む。
finally:
    cs(1)                               # ペリフェラルを選択解除。

rxdata = bytearray(8)
try:
    cs(0)                               # ペリフェラルを選択。
    spi.readinto(rxdata, 0x42)          # 0x42 をバイトごとに書き出しながら、合計 8 バイトを指定場所に読み込む。
finally:
    cs(1)                               # ペリフェラルを選択解除。

txdata = b"12345678"
rxdata = bytearray(len(txdata))
try:
    cs(0)                               # ペリフェラルを選択。
    spi.write_readinto(txdata, rxdata)  # バイト列の書出しと読込みを同時に行う。
finally:
    cs(1)                               # ペリフェラルを選択解除。

I2Cクラス

2線式プロトコルでの通信を実装。
使い方的にはSPIと似た感じ。
image.png
(例)加速度センサー(ADXL345など)との通信

  • インスタンス(オブジェクト)を生成
    • 生成時には特にID等は指定しない
  • 通信速度、ビット数などを設定
  • 複数バイトを送受信
    • 送受信時に、相手(ID)を指定
from machine import I2C

i2c = I2C(freq=400000)          # ポートに依存して 400kHz の周波数でI2Cペリフェラルを
                                # 作成します。使用するペリフェラルやピンを選択するために
                                # 追加のパラメータが必要になる場合があります

i2c.scan()                      # ペリフェラルをスキャンし、7ビットアドレスのリストを返します

i2c.writeto(42, b'123')         # 7ビットアドレス 42 のペリフェラルに3バイトを書き込みます
i2c.readfrom(42, 4)             # 7ビットアドレス 42 のペリフェラルから4バイトを読み込みます

i2c.readfrom_mem(42, 8, 3)      # スレーブ 42 のメモリから、ペリフェラルのメモリアドレス 8 で
                                #   始まる3バイトを読み込みます
i2c.writeto_mem(42, 2, b'\x10') # スレーブ 42 のメモリの、ペリフェラルのメモリアドレス 2 で
                                #   始まるところに2バイトを書き込みます

最後に

machineモジュール以外にも、ファイルアクセスやネットワーク関連のモジュールのことも知っておいた方がいいけど、ここではここまでにしておきます。

おまけ

C/C++党だけど、何かと(環境構築とか)楽なので、Python派に流れそう...
しかも、ESP32もMicroPythonが動くのね。知らなかった。

7
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4