このページの目次
CircuitPythonファームウエア
TRYGEARの各開発ボードには下記のCircuitPythonファームウェアを書き込んでご利用ください。
- TRYGEAR-DASH RP2350A
- Pico 2用のファームウェアをご利用ください
- https://circuitpython.org/board/raspberry_pi_pico2/
- TRYGEAR-VIZ RP2350B
- WeAct Studio RP2350B Core用のファームウェアをご利用ください
- https://circuitpython.org/board/weact_studio_rp2350b_core/
- TRYGEAR-NET ESP32-S3
- ESP32-S3-DevKitC-1用のファームウェアをご利用ください
- https://circuitpython.org/board/espressif_esp32s3_devkitc_1_n8r8/
また、ライブラリバンドルの/libフォルダの内容をボードの/libフォルダにコピーしてご利用ください。
フラッシュの容量は4MB以上あるので、必要なライブラリを選別することなく、すべてのライブラリをコピーできます。
端子割り当て
TRYGEARシリーズの開発ボードは、機能や性能により、いくつかのメーカーのMCUを採用しています。このため、使用しているMCUが異なる開発ボードごとに端子の呼び名や配置が異なっています。このため、特段の配慮がない場合、同じ機能のプログラムでも開発ボードごとに使用する端子名が異なってしまい、同じ機能のプログラムでも異なる開発ボードで共通に利用できないという問題があります。
TRYGEARシリーズの開発ボードでは、機能や配置が共通する端子の名前を異なる開発ボードでも同じ名前で使用できるようにライブラリファイル trygear.py を提供しています。trygear.pyを開発ボードの/libフォルダに格納し、プログラムの先頭にimport trygearと記述して使用してください。
from microcontroller import pin
import os
# 実行環境の自動判定
try:
_sysname = os.uname().sysname
except:
_sysname = "unknown"
if "rp2350b" in _sysname:
# --- Viz (RP2350B) Pin Definitions ---
BOARD_NAME = "VIZ RP2350B"
# Digital Pins (UNO Mapping)
D0, D1, D2, D3 = pin.GPIO1, pin.GPIO0, pin.GPIO2, pin.GPIO3
D4, D5, D6, D7 = pin.GPIO4, pin.GPIO5, pin.GPIO6, pin.GPIO7
D8, D9 = pin.GPIO22, pin.GPIO23
D10, D11, D12, D13 = pin.GPIO9, pin.GPIO11, pin.GPIO8, pin.GPIO10
# Analog Pins
A0, A1, A2, A3, A4, A5 = pin.GPIO40, pin.GPIO41, pin.GPIO42, pin.GPIO43, pin.GPIO46, pin.GPIO47
# Input Functions
SW1, SW2, SW3 = pin.GPIO29, pin.GPIO30, pin.GPIO31
# Output Functions
LED1 = D13 # SCK_S(GP13)と共用
LED2, LED3 = pin.GPIO32, pin.GPIO33
LED4 = pin.GPIO25
SRV1, SRV2 = LED2, LED3
RGB_LED = LED3
SPK = pin.GPIO26
# I2C Bus
SCL, SDA = pin.GPIO21, pin.GPIO20
SCL_A, SDA_A = A5, A4
# SPI Bus (Display: TFT_, Storage: SD_)
TFT_SCK, TFT_MOSI, TFT_MISO, TFT_CS = pin.GPIO38, pin.GPIO39, pin.GPIO36, pin.GPIO37
TFT_DC = TFT_MISO
SD_SCK, SD_MOSI, SD_MISO, SD_CS = D13, D11, D12, pin.GPIO24
# USB HOST
USBHP, USBHM = pin.GPIO34, pin.GPIO35
elif "ESP32S3" in _sysname:
# --- NET (ESP32-S3) Pin Definitions ---
BOARD_NAME = "NET ESP32-S3"
# Digital Pins (UNO Mapping)
D0, D1, D2, D3 = pin.GPIO44, pin.GPIO43, pin.GPIO1, pin.GPIO2
D4, D5, D6, D7 = pin.GPIO3, pin.GPIO38, pin.GPIO39, pin.GPIO40
D8, D9 = pin.GPIO41, pin.GPIO42
D10, D11, D12, D13 = pin.GPIO10, pin.GPIO11, pin.GPIO13, pin.GPIO12
# Analog Pins
A0, A1, A2, A3 = pin.GPIO4, pin.GPIO5, pin.GPIO6, pin.GPIO7
A4, A5 = pin.GPIO8, pin.GPIO9
# Input Functions
SW1, SW2, SW3 = pin.GPIO1, pin.GPIO47, pin.GPIO48
SW5 = pin.GPIO0
# Output Functions
LED1 = D13 # SCK_S(IO13)と共用
LED2, LED3 = pin.GPIO45, pin.GPIO46
SRV1, SRV2 = LED2, LED3
RGB_LED = LED3
SPK = pin.GPIO21
# I2C Bus
SCL = pin.GPIO9 # A5と共用
SDA = pin.GPIO8 # A4と共用
# SPI Bus (Display: TFT_, Storage: SD_)
TFT_SCK, TFT_MOSI, TFT_MISO, TFT_CS = pin.GPIO15, pin.GPIO16, pin.GPIO17, pin.GPIO18
TFT_DC = TFT_MISO
SD_SCK, SD_MOSI, SD_MISO, SD_CS = D13, D11, D12, pin.GPIO16
# CAN Bus
CAN_TX = pin.GPIO48
CAN_RX = pin.GPIO47
elif ("rp2350a" in _sysname) or ("rp2040" in _sysname):
# --- DASH (RP2350A) Pin Definitions ---
BOARD_NAME = "DASH/LITE/CORE RP2350A" if ("rp2350a" in _sysname) else "DASH/LITE/CORE RP2040"
# Digital Pins (UNO Mapping)
D0, D1, D2, D3 = pin.GPIO1, pin.GPIO0, pin.GPIO2, pin.GPIO3
D4, D5, D6, D7 = pin.GPIO4, pin.GPIO5, pin.GPIO6, pin.GPIO7
D8, D9 = pin.GPIO8, pin.GPIO9
D10, D11, D12, D13 = pin.GPIO13, pin.GPIO11, pin.GPIO12, pin.GPIO10
# Analog Pins
A0, A1, A2, A3 = pin.GPIO26, pin.GPIO27, pin.GPIO28, pin.GPIO29
# Input Functions
SW1, SW2, SW3 = pin.GPIO14, pin.GPIO15, pin.GPIO22
# Output Functions
LED1 = D13 # SCK_S(GP13)と共用
LED2, LED3 = D0, D1
LED4 = pin.GPIO25
SRV1, SRV2 = LED2, LED3
RGB_LED = LED3
SPK = pin.GPIO23
# I2C Bus
SCL = pin.GPIO21 # A5と共用
SDA = pin.GPIO20 # S4と共用
# SPI Bus (Display: TFT_, Storage: SD_)
TFT_SCK, TFT_MOSI, TFT_MISO, TFT_CS = pin.GPIO18, pin.GPIO19, pin.GPIO16, pin.GPIO17
TFT_DC = TFT_MISO
SD_SCK, SD_MOSI, SD_MISO, SD_CS = D13, D11, D12, pin.GPIO24
else:
BOARD_NAME = "Unknown microcontroller"LED
LEDの点灯
TRYGEARには3,4個のLEDが装備されており、LED1,LED2,LED3などの名前が付けられています。それらのLEDをCircuitPythonで操作する方法を示します。
CircuitPythonでは、一般的にはLEDが接続されている端子名(GP25)を使用して、制御用端子の指定や制御を行います。Raspberry Pi PICO用のCircuitPythonでは、'GP25'の他に'LED'の端子名がLEDに割り当てられているため、それを使用してLED用の端子を指定することができます。(もちろん従来通り、端子名(この場合はGP25)で指定することもできます。)
import trygear
import digitalio
import board
import time
led = digitalio.DigitalInOut(trygear.LED4) # board.GP25 でも可
led.direction = digitalio.Direction.OUTPUT
led.value = True
time.sleep(1) # 1秒待つ
led.value = Falseこのプログラムは、単純に1秒だけLEDを点灯させています。
LEDの点滅
LEDを一定間隔で点滅するプログラムを示します。
import trygear
import digitalio
import board
import time
led = digitalio.DigitalInOut(trygear.LED4)
led.direction = digitalio.Direction.OUTPUT
while True:
led.value = True
time.sleep(1) # 1秒待つ
led.value = False
time.sleep(1)LEDの明暗制御
LEDはPWMを使用して、単純に点灯、消灯だけでなく、明暗の度合いを制御できます。
PWMを使用してLEDの明暗を制御するプログラムを示します。
import trygear
import pwmio
import board
import time
led = pwmio.PWMOut(trygear.LED4, frequency = 1000)
delta = 100
duty = 0
while True:
duty += delta
if duty == 65500:
delta = -100
elif duty == 0:
delta = 100
led.duty_cycle = duty # 0-65535
time.sleep(0.002)LEDをPWMで制御するように初期化し、Whileループの中で、PWMのデューティー比を増減させて、LEDの明暗を変化させています。
スイッチ
スイッチによるLEDの点灯
スイッチを押したときにLEDが点灯し、スイッチを離したときにLEDが消灯するプログラムを以下に示します。
import trygear
import digitalio
import board
led = digitalio.DigitalInOut(trygear.LED4)
led.direction = digitalio.Direction.OUTPUT
sw1 = digitalio.DigitalInOut(trygear.SW1)
sw1.direction = digitalio.Direction.INPUT
while True:
led.value = not sw1.valueTRYGEARには、ユーザーがプログラムで使用できるスイッチ SW1, SW2, SW3が装備されており、それぞれtrygear.SW1,trygear.SW2, trygear.SW3で使用できます。
TRYGEARのSW1-SW3は負論理となっており、スイッチが押されたときにFalseもしくは0、離されている時にTrueもしくは1となります。このプログラムでは、正論理のLEDを接続している場合のもので、負論理のスイッチの読み取り結果を 'not' を付けて正論理に変換してLEDの引数としています。
なお、TRYGEAR-VIZとTRYGEAR-NETのSW1は、スイッチがプルアップされていない場合に何が起きるかを実験できるように、プルアップ用の抵抗が付けられていません。したがって、ふつうに使用する場合には、SW1だけは、MCUの内部プルアップを有効にする設定を行ってください。
圧電スピーカー
明るく光るLEDは出力装置として魅力的ですが、音を出す圧電スピーカーも電子工作では外せませんね。圧電スピーカーは圧電素子を使ったスピーカーで、TRYGEARに搭載されているものは直径が1センチ程度の小さなものです。
異なる周波数の音の出力
周波数が500Hzから1000Hzまで、10Hzごとに周波数を上げて音を出力するプログラム例を示します。(実際に出力される音(の高さ)は、圧電スピーカーの特性によるのか、ちょっと違和感があります。)
TRYGEARの圧電スピーカーを使用する場合のプログラム例を示します。TRYGEARで圧電スピーカーを使用する場合には、toneの引数として、圧電スピーカー接続した端子の端子名を指定してください。
import trygear
import simpleio
import board
for hz in range(500,1001,10): # 100Hz -1000Hz
simpleio.tone(trygear.SPK, hz, 0.1)RP2040-SLIM-PLUS用の圧電スピーカーはGP23に接続されています。
スイッチによる音の出力
スイッチを押すと音が鳴るプログラム例を示します。
import trygear
import digitalio
import board
import simpleio
sw1 = digitalio.DigitalInOut(trygear.SW1)
sw1.direction = digitalio.Direction.INPUT
while True:
if (sw1.value == 0): # スイッチが押されたとき
simpleio.tone(trygear.SPK, 400, 0.5)メロディーの出力
内臓タイマーを使用した音声出力例です。Arduinoでは、tone()関数の利用に相当します。音のPWM出力と書かれていることも多いのですが、基本的には周波数が重要でデューティーサイクルは問題ではないので、PWMというべきではないですね。
import trygear
import time
import board
from simpleio import tone
# 音符の周波数 (単位: Hz)
NOTES = {
"C4": 261,
"D4": 294,
"E4": 329,
"F4": 349,
"G4": 392,
"A4": 440,
"B4": 493,
"C5": 523,
"REST": 0 # 休符
}
# 「カエルの歌」の楽譜 (音符と長さの組み合わせ)
# 長さは秒単位で指定
SONG = [
("C4", 0.5), ("D4", 0.5), ("E4", 0.5), ("F4", 0.5),
("E4", 0.5), ("D4", 0.5), ("C4", 0.5), ("REST", 0.5),
("E4", 0.5), ("F4", 0.5), ("G4", 0.5), ("A4", 0.5),
("G4", 0.5), ("F4", 0.5), ("E4", 0.5), ("REST", 0.5)
]
print("カエルの歌を演奏します。")
# 楽譜を演奏
while True:
for note, length in SONG:
if NOTES[note] == 0: # 休符の場合
print(f"休符: {length}s")
time.sleep(length) # 秒単位の休符
else:
print(f"再生中: {note}, 長さ: {length}s")
tone(trygear.SPK, NOTES[note], length) # 周波数と長さを指定 (秒単位)
time.sleep(1) # 演奏間に1秒の休止TFTディスプレイ
文字と基本図形の表示
import trygear
import board
import busio
import displayio
from fourwire import FourWire
import terminalio
from adafruit_st7789 import ST7789
from adafruit_display_text import label
from adafruit_display_shapes.circle import Circle
from adafruit_display_shapes.rect import Rect
from adafruit_display_shapes.triangle import Triangle
# 以前のディスプレイリソースを解放
displayio.release_displays()
# SPIバスとピンの設定
spi = busio.SPI(clock=trygear.TFT_SCK, MOSI=trygear.TFT_MOSI)
cs_pin = trygear.TFT_CS # チップセレクトピン
dc_pin = trygear.TFT_DC # データ/コマンドピン
# ディスプレイの初期化(rowstart=80、rotation=270で画面を回転)
display_bus = FourWire(spi, command=dc_pin, chip_select=cs_pin)
display = ST7789(display_bus, width=240, height=240, rotation=0, rowstart=80)
# メインの表示グループを作成
main_group = displayio.Group()
# 背景を黒に設定
background = Rect(0, 0, 240, 240, fill=0x000000) # 全体を黒背景に設定
main_group.append(background)
# 図形の表示
# 円(黄色)
circle = Circle(180, 50, 30, fill=0xFFFF00) # 中心座標(180,50), 半径30
main_group.append(circle)
# 四角形(シアン)
rectangle = Rect(100, 120, 60, 60, fill=0x00FFFF) # 左上座標(100,120), 幅60, 高さ60
main_group.append(rectangle)
# 三角形(マゼンタ)
triangle = Triangle(40, 200, 80, 240, 0, 240, fill=0xFF00FF) # 三角形の3頂点を指定
main_group.append(triangle)
# 文字列の表示(文字サイズを2倍に設定)
text_microfan = label.Label(terminalio.FONT, text="MicroFan", color=0xFF0000, x=20, y=30, scale=2) # 赤文字
text_rp2040 = label.Label(terminalio.FONT, text=trygear.BOARD_NAME, color=0x00FF00, x=0, y=90, scale=2) # 緑文字
text_circuitpython = label.Label(terminalio.FONT, text="CircuitPython", color=0x0000FF, x=20, y=150, scale=2) # 青文字
main_group.append(text_microfan)
main_group.append(text_rp2040)
main_group.append(text_circuitpython)
# ディスプレイに描画
display.root_group = main_group
# 無限ループで画面を維持
while True:
passボールが画面内を跳ね回るプログラム
import trygear
import board
import busio
import displayio
from fourwire import FourWire
from adafruit_st7789 import ST7789
displayio.release_displays()
# SPIバスとピンの設定
spi = busio.SPI(clock=trygear.TFT_SCK, MOSI=trygear.TFT_MOSI)
tft_cs = trygear.TFT_CS # チップセレクトピン
tft_dc = trygear.TFT_DC # データ/コマンドピン
display_bus = FourWire(spi, command=tft_dc, chip_select=tft_cs)
# display = ST7789(display_bus, width=320, height=170, colstart=35, rotation=90) # 1.9 inch 170x320
display = ST7789(display_bus, width=240, height=240, rowstart=80, rotation=0) # 1.54 inch 240x240
group = displayio.Group()
display.root_group = group
# ここまではグラフィックス利用の初期化で今後も共通
import simpleio
from adafruit_display_shapes.circle import Circle
class Ball(Circle):
# 初期座標、縦横速度、色を与える
def __init__(self, x0, y0, r, vx, vy, color):
super().__init__(x0, y0, r, fill=color, outline=0xFFFF00)
self.vx = vx
self.vy = vy
def tick(self):
# 縦横速度分移動して
self.x0 += self.vx
self.y0 += self.vy
# 画面の端に来たら速度を反転させて跳ね返る
if self.x0 <= self.r or self.x0 >= (display.width-1)-self.r:
simpleio.tone(trygear.SPK, 1000, 0.01)
self.vx = -self.vx
if self.y0 <= self.r or self.y0 >= (display.height-1)-self.r:
simpleio.tone(trygear.SPK, 500, 0.01)
self.vy = -self.vy
ball = Ball(100, 100, 10, 2, 5, 0x00FF00)
group.append(ball)
import time
while True:
group[0].tick()
time.sleep(0.02)HDMIコネクタを使用したTV/PCモニタ表示
TRYGEAR-VIZでは、HDMIコネクタが搭載されており、PicoDVIを使用して大画面表示を楽しむことができます。
# 表示システムの初期化を行う
import displayio, picodvi, board, framebufferio
displayio.release_displays()
fb = picodvi.Framebuffer(
width=320, height=240, color_depth=8,
clk_dp=board.GP14, clk_dn=board.GP15,
red_dp=board.GP12, red_dn=board.GP13,
green_dp=board.GP18, green_dn=board.GP19,
blue_dp=board.GP16, blue_dn=board.GP17)
display = framebufferio.FramebufferDisplay(fb)
group = displayio.Group()
display.root_group = group
# 文字列の表示を行う
from adafruit_display_text import label
import terminalio
group.append(label.Label(terminalio.FONT, text="MicroFan", x=0, y=10, scale=2, color=0xFFFFFF))
group.append(label.Label(terminalio.FONT, text="TRYGEAR VIZ:PicoDVI", x=0, y=30, scale=2, color=0xFFFFFF))
# 図形の表示を行う
from adafruit_display_shapes.line import Line
from adafruit_display_shapes.rect import Rect
from adafruit_display_shapes.circle import Circle
from adafruit_display_shapes.triangle import Triangle
group.append(Line(0, 80, 320, 80, 0xFF00FF))
group.append(Rect(0, 120, 100, 100, fill=0xFF0000, outline=0xFFFF00))
group.append(Circle(160, 170, 50, fill=0x00FF00, outline=0xFFFF00))
group.append(Triangle(260, 120, 210, 220, 310, 220, fill=0x0000FF, outline=0xFFFF00))
import displayio, picodvi, board, framebufferio
displayio.release_displays()
fb = picodvi.Framebuffer(
width=320, height=240, color_depth=8,
clk_dp=board.GP14, clk_dn=board.GP15, # 端子の配置はPICO-HDMI-PLUS用
red_dp=board.GP12, red_dn=board.GP13,
green_dp=board.GP18, green_dn=board.GP19,
blue_dp=board.GP16, blue_dn=board.GP17)
display = framebufferio.FramebufferDisplay(fb)
group = displayio.Group()
display.root_group = group
# ここまではグラフィックス利用の初期化で今後も共通
import simpleio
from adafruit_display_shapes.circle import Circle
class Ball(Circle):
# 初期座標、縦横速度、色を与える
def __init__(self, x0, y0, r, vx, vy, color):
super().__init__(x0, y0, r, fill=color, outline=0xFFFF00)
self.vx = vx
self.vy = vy
def tick(self):
# 縦横速度分移動して
self.x0 += self.vx
self.y0 += self.vy
# 画面の端に来たら速度を反転させて跳ね返る
if self.x0 <= self.r or self.x0 >= (display.width-1)-self.r:
simpleio.tone(board.GP26, 1000, 0.01)
self.vx = -self.vx
if self.y0 <= self.r or self.y0 >= (display.height-1)-self.r:
simpleio.tone(board.GP26, 500, 0.01)
self.vy = -self.vy
ball = Ball(100, 100, 10, 2, 5, 0x00FF00)
group.append(ball)
import time
while True:
group[0].tick()
time.sleep(0.02)OLEDディスプレイ
OLEDディスプレイへの文字表示
コントローラにSSD1306を使用した0.96インチのOLEDディスプレイに文字列を表示するプログラム例を示します。
import trygear
import board
import busio
import adafruit_ssd1306
i2c = busio.I2C(trygear.SCL, trygear.SDA)
oled = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c)
oled.text(trygear.BOARD_NAME, 0, 0, True) # 第二引数は文字を出力する横のピクセル座標、第三引数は縦のピクセル座標
oled.text('MicroFan', 32, 8, True)
oled.text('SW x3', 0, 16, True)
oled.text('LED x3 or x4', 0, 24, True)
oled.text('Piezo Speaker', 0, 32, True)
oled.text('RC Servo Conn. x2', 0, 40, True)
oled.text('MicroSD Socket', 0, 48, True)
oled.text('OLED Display', 0, 56, True)
oled.show()ssd1306での文字出力は、文字を出力する座標を毎回指定する必要があります。グラフィックス表示と合わせて文字表示をする場合には役立ちますが、文字だけを出力する場合には、少々面倒です。
また、文字もグラフィックスも、表示の指示をしただけではOLEDディスプレイの画面に表示されず、show()メソッドを呼び出した時点で初めてすべての表示指示が画面に反映されます。
OLEDディスプレイへのグラフィックス表示
OLEDディスプレイにグラフィックス表示するプログラム例です。
import trygear
import board
import busio
import adafruit_ssd1306
import time
i2c = busio.I2C(trygear.SCL, trygear.SDA)
oled = adafruit_ssd1306.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(0.5)
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(0.5)
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(0.5)
oled.fill(0) # 画面のクリア
for n in range(2,32,2):
# oled.ellipse(64,32,n*4,n*2,1) # 楕円
oled.circle(64,32,n*2,1)
oled.show()RCサーボ
カラーLED
WS2812カラーLED
RP2040-SLIMは1個のカラーLEDのみを実装しています。
RGB表示
3個のWS2812タイプのカラーLEDに赤、緑、青色を出力するプログラム例です。
各LEDの明るさは、0-255の範囲で指定できますが、LEDの点灯確認目的であれば、10程度の明るさ指定でも十分な明るさで発光します。
# Ws2812 カラーLEDの点灯
import trygear
import board
import neopixel
rgb = neopixel.NeoPixel(trygear.RGB_LED, 3)
rgb[0] = (10,0,0) # 赤
rgb[1] = (0,10,0) # 緑
rgb[2] = (0,0,10) # 青温度・湿度センサー
気温・湿度センサーAHT20と明るさセンサーは、RP2040-SLIMには装備されていません。
気温・湿度センサーAHT20のドライバーに関しては以下のページをご参照ください。
気温・湿度・明るさ表示
OLEDディスプレイに気温・湿度センサーAHT20で得られた気温と湿度、明るさセンサー(フォトトランジスタ)で得られた明るさを表示するプログラム例です。
AHT20はI2Cで接続されており、OLEDディスプレイと同じGP20,GP21にに接続されています。
明るさは、フォトトランジスタの出力電圧をAD変換で読み取って表示しています。明るさの範囲は0-1で、1に近い方が明るい状態を表します。
import trygear
import board
import busio
import analogio
import microcontroller
import adafruit_ahtx0
import adafruit_ssd1306
import time
i2c = busio.I2C(trygear.SCL, trygear.SDA)
aht20 = adafruit_ahtx0.AHTx0(i2c)
oled = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c)
brt = analogio.AnalogIn(board.A3)
while True:
oled.fill(0)
oled.text('CORE TEMP: {:.1f}\''.format(microcontroller.cpu.temperature),0,0,True)
oled.text('TEMP: {:.1f}\''.format(aht20.temperature),0,16,True)
oled.text('HUM: {:.1f}%'.format(aht20.relative_humidity),0,32,True)
oled.text('BRT: {:.3f}'.format(brt.value/65535),0,48,True)
oled.show()
time.sleep(0.1)気圧センサー
明るさセンサー
加速度センサー
MicroSD
USBデバイス
USBホスト
文字端末(のもと)の作成
TRYGEAR-VIZ-RP2350Bを使用すると、PCキーボードを入力とし、TV/PCモニターを出力とするスタンドアロンの超小型PCを作ることができます。出力はTFTディスプレイでも構いませんが。
まずはその入り口として、JISキーボードの入力内容をモニターに出力するプログラムを示します。
とても基本的な機能のみだけどね。
ここでは、下記の3つプログラムを組み合わせたプログラム例を紹介します。
- USBホスト機能を利用したPCキーボードの読み取りプログラム
- PicoDVIを使用した文字のTV/PCモニター出力プログラム
- 上記の2つを組み合わせた簡易端末
USBホストのPCキーボードの入力機能
読み取るのは、PCキーボード中央部のアルファベット数字キー周りのみで、今回はテンキーやファンクションキーは対象外。
シフトキーは使えます。
import board
import time
import usb.core
import usb_host
class JISKeyboard:
def __init__(self, dp=board.GP34, dm=board.GP35):
# USBホストの初期化
self.host_port = usb_host.Port(dp, dm)
self.keyboard = None
self.buffer = bytearray(8)
self.last_keycode = 0
# JIS配列マップ
self.HID_MAP = {
0x04: "a", 0x05: "b", 0x06: "c", 0x07: "d", 0x08: "e", 0x09: "f", 0x0a: "g",
0x0b: "h", 0x0c: "i", 0x0d: "j", 0x0e: "k", 0x0f: "l", 0x10: "m", 0x11: "n",
0x12: "o", 0x13: "p", 0x14: "q", 0x15: "r", 0x16: "s", 0x17: "t", 0x18: "u",
0x19: "v", 0x1a: "w", 0x1b: "x", 0x1c: "y", 0x1d: "z",
0x1e: "1", 0x1f: "2", 0x20: "3", 0x21: "4", 0x22: "5", 0x23: "6", 0x24: "7",
0x25: "8", 0x26: "9", 0x27: "0",
0x28: "\n", 0x2C: " ",
0x2d: "-", 0x2e: "^", 0x2f: "@", 0x30: "[",
0x32: "]", 0x33: ";", 0x34: ":", 0x35: "`",
0x36: ",", 0x37: ".", 0x38: "/", 0x87: "\\"
}
self.HID_SHIFT_MAP = {
0x04: "A", 0x05: "B", 0x06: "C", 0x07: "D", 0x08: "E", 0x09: "F", 0x0a: "G",
0x0b: "H", 0x0c: "I", 0x0d: "J", 0x0e: "K", 0x0f: "L", 0x10: "M", 0x11: "N",
0x12: "O", 0x13: "P", 0x14: "Q", 0x15: "R", 0x16: "S", 0x17: "T", 0x18: "U",
0x19: "V", 0x1a: "W", 0x1b: "X", 0x1c: "Y", 0x1d: "Z",
0x1e: "!", 0x1f: '"', 0x20: "#", 0x21: "$", 0x22: "%", 0x23: "&", 0x24: "'",
0x25: "(", 0x26: ")", 0x27: "~",
0x28: "\n", 0x2C: " ",
0x2d: "=", 0x2e: "~", 0x2f: "`", 0x30: "{",
0x32: "}", 0x33: "+", 0x34: "*", 0x35: "~",
0x36: "<", 0x37: ">", 0x38: "?", 0x87: "_"
}
def _find_keyboard(self):
devices = list(usb.core.find(find_all=True))
if not devices:
return None
dev = devices[-1]
keyboard = usb.core.find(idVendor=dev.idVendor, idProduct=dev.idProduct)
if keyboard is not None:
try:
keyboard.set_configuration()
except Exception:
pass
return keyboard
def read_char(self):
"""文字が入力されたらその文字を返す。入力がなければNoneを返す。"""
if self.keyboard is None:
self.keyboard = self._find_keyboard()
if self.keyboard is None:
return None
try:
num_bytes = self.keyboard.read(0x81, self.buffer)
if num_bytes > 0:
is_shift = (self.buffer[0] & 0x22) != 0
current_keycode = 0
for code in self.buffer[2:8]:
if code != 0:
current_keycode = code
break
# キーの変更検知(チャタリング防止)
if current_keycode != self.last_keycode:
self.last_keycode = current_keycode
if current_keycode != 0:
if is_shift and current_keycode in self.HID_SHIFT_MAP:
return self.HID_SHIFT_MAP[current_keycode]
elif not is_shift and current_keycode in self.HID_MAP:
return self.HID_MAP[current_keycode]
except Exception:
self.keyboard = None
self.last_keycode = 0
return NonePicoDVIのモニター出力機能
出力された文字をTV/PCモニターに表示します。
エンター(ここでは'\n')が入力されると、改行されます。
改行時に画面がスクロールアップします。
import board
import displayio
import framebufferio
import picodvi
import terminalio
class DVIConsole:
def __init__(self, width=640, height=480):
displayio.release_displays()
# 1. PicoDVIの初期化
self.fb = picodvi.Framebuffer(
width=width, height=height, color_depth=8,
clk_dp=board.GP14, clk_dn=board.GP15,
red_dp=board.GP12, red_dn=board.GP13,
green_dp=board.GP18, green_dn=board.GP19,
blue_dp=board.GP16, blue_dn=board.GP17
)
self.display = framebufferio.FramebufferDisplay(self.fb, rotation=0)
# 2. 画面に収まる文字の行列数を計算
font = terminalio.FONT
font_w, font_h = font.get_bounding_box()
grid_w = width // font_w
grid_h = height // font_h
# 3. ターミナル用のカラーパレットを作成(これが10.xの必須要素)
# [0]を背景色(黒)、[1]を文字色(白)にします
palette = displayio.Palette(2)
palette[0] = 0x000000
palette[1] = 0xFFFFFF
# 4. scroll_area となる TileGrid の生成
# これが Terminal クラスに要求されている最初の引数です
self.tile_grid = displayio.TileGrid(
font.bitmap,
pixel_shader=palette,
width=grid_w,
height=grid_h,
tile_width=font_w,
tile_height=font_h
)
# 5. Terminal を初期化
self.term = terminalio.Terminal(scroll_area=self.tile_grid, font=font)
# 6. グループへ追加して画面表示
self.group = displayio.Group()
self.group.append(self.tile_grid)
self.display.root_group = self.group
def write(self, text):
"""文字列をモニターに出力(改行やスクロールも自動処理)"""
self.term.write(text)統合コード
上記の2つのモジュールをインポートし、PCキーボードから読み込んだ文字をTV/PCモニターに出力するようにしてやると出来上がり。
合計3個のプログラムファイルを開発ボードのファイルシステムにコピーして利用してください。
動いて当たり前だけどちょっと感動。まだ穴だらけですが。。。
画面の解像度を上げると文字が小さくなってインパクトが弱かったので、下記の統合コードでは、画面の解像度を低くしています。
入力と出力をUSBシリアルやUARTに接続すると、簡易端末の出来上がり。目指せVT100(古いですね。)
入力と出力を開発ボード内部のREPLループに接続してやれば、超小型Python PCの出来上がり。
import time
import sys
from jis_keyboard import JISKeyboard
from dvi_console import DVIConsole
print("=== システム起動 ===")
# 各モジュール(部品)をインスタンス化
# これにより、内部の複雑な初期化やピン配置は隠蔽されます
console = DVIConsole(360,200)
keyboard = JISKeyboard()
console.write("JIS Keyboard Test Console\n")
console.write("Ready to Type...\n\n")
while True:
# キーボードモジュールから文字を1文字取得
char = keyboard.read_char()
if char is not None:
# 1. PicoDVIモニターに出力
console.write(char)
# 2. REPL(PC側のシリアルコンソール)にも同時に出力
sys.stdout.write(char)
time.sleep(0.01)