インタフェース2月号のラズパイで作り学ぶDockerコンテナの再開。 ページ内で、マイコン内蔵RGBLEDテープを使うところがあり、 秋月電子で、探していたところ、それっぽいものがあった。 https://akizukidenshi.com/catalog/g/g116029/ で、物が届いた後に気が付いた。あれ、これって表面実装部品じゃないですか? ヒートガンはあるけど、ペーストはんだもない。 というわけで、2.5ミリ間隔の部分にはんだごてでのはんだ付け。 ワイヤストリッパーもないので、被覆をはさみで切りこみを入れたあとねじって引き抜いて、 作業シートの上にセロハンテープで固定して、 老眼鏡をかけてはんだづけ。 以下のページをみて、ピンアサインと配線例を確認し、 https://www.peace-corp.co.jp/data/WS2812B-V5_V1.0_EN.pdf このページのコードを流用して、 https://howtojp.com/a/sensors/Raspberry-Pi-WS2812B-control import time import board import neopixel # WS2812Bの設定 pixel_pin = board.GP18 # デジタルピン18に接続した場合 num_pixels = 2 # LEDの数 ORDER = neopixel.GRB # カラーオーダー pixels = neopixel.NeoPixel( pixel_pin, num_pixels, brightness=0.2, auto_write=False, pixel_order=ORDER ) # 色の定義 red = (255, 0, 0) green = (0, 255, 0) blue = (0, 0, 255) # 全てのLEDを順番に点灯 for i in range(num_pixels): pixels[i] = red pixels.show() time.sleep(1) pixels[i] = green pixels.show() time.sleep(1) pixels[i] = blue pixels.show() time.sleep(1) で、動かした結果こんな感じ。 このとき2番目のLEDがなぜか暗かったけど、配線をし直したら明るくなった。 そのほか、BME280もピンヘッダとジャンパをはんだ付けしなきゃならない。インタフェースの特集記事への着手への道のりは先は長そう?
2025年3月2日日曜日
マイコン内蔵LEDの接続
2025年3月1日土曜日
picoのHIDデバイス化備忘録
いろいろ至らない部分があるが、ほかにやりたいことがあるので、こちらはいったん終了。
作業メモだけ残す。
配線:
ボタン1~10をGNDと、GP0,GP1,GP2,GP3,GP4,GP28,GP27,GP26,GP5,GP6に接続
ロータリーエンコーダ1を、GP17,GND,GP16に接続。
ロータリーエンコーダ2を、GP19,GND,GP18に接続。
SSD1302の、GND,VCC,SCL,SDAを、GND,3.3V,GP15,GP14に接続。
ライブラリファイル配置。
PIのボタンを押しながらPCに接続する。
PIのドライブにflash_nuke.uf2をコピーしてストレージを初期化。
PIのドライブにadafruit-circuitpython-raspberry_pi_pico2-ja-9.2.3.uf2をコピーしてcircuitpy環境にする。
adafruit-circuitpython-bundle-py-20250201\examples\framebuf\font5x8.bin をcircuitpyドライブ直下にコピー。
adafruit-circuitpython-bundle-py-20250201\libの
adafruit_framebuf.mpy,adafruit_ssd1306.mpy,adafruit_hid/をcircuitpyのlibフォルダにコピー。
pico_MicroPython_misakifont-main.zip\pico_MicroPython_misakifont-main\の
misakifontフォルダをcircuitpyのlibフォルダにコピー。
mode.iniをcircuitpyドライブ直下に作成。内容は0の1バイトのみ。
circuitpyドライブ直下のboot.pyを以下の内容に差し替える。
import os
import storage
import board
import digitalio
switch = digitalio.DigitalInOut(board.GP6)
switch.direction = digitalio.Direction.INPUT
switch.pull = digitalio.Pull.UP
if switch.value:
#NormalMode
storage.disable_usb_drive()
usb_cdc.disable()
else :
#Maintenance
pass
circuitpyドライブ直下のcode.pyを以下の内容に差し替える。
import digitalio
import busio
import adafruit_ssd1306
import time
import usb_hid
import json
from board import *
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard import Keycode
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
from adafruit_hid.consumer_control import ConsumerControl
from adafruit_hid.consumer_control_code import ConsumerControlCode
from adafruit_hid.mouse import Mouse
from misakifont import MisakiFont
i2c = busio.I2C(GP15, GP14)
display = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c, addr=0x3C)
mode=0
try:
with open('mode.ini', 'r') as file:
mode=int(file.read())
with open('mode.ini', 'w') as file:
file.write("{}".format(mode))
except Exception as e:
display.text("MAINTENANCE MODE", 16, 30, True, font_name="font5x8.bin", size=1)
display.show()
# raise e
cc = ConsumerControl(usb_hid.devices)
keyboard = Keyboard(usb_hid.devices)
layout=KeyboardLayoutUS(keyboard)
mouse = Mouse(usb_hid.devices)
s1 = digitalio.DigitalInOut(GP17)
s1.direction = digitalio.Direction.INPUT
s1.pull = digitalio.Pull.UP
s2 = digitalio.DigitalInOut(GP16)
s2.direction = digitalio.Direction.INPUT
s2.pull = digitalio.Pull.UP
n_s1=o_s1=s1.value
n_s2=o_s2=s2.value
s3 = digitalio.DigitalInOut(GP19)
s3.direction = digitalio.Direction.INPUT
s3.pull = digitalio.Pull.UP
s4 = digitalio.DigitalInOut(GP18)
s4.direction = digitalio.Direction.INPUT
s4.pull = digitalio.Pull.UP
n_s3=o_s3=s3.value
n_s4=o_s4=s4.value
mf = MisakiFont()
sw=[]
n_sws=[True,True,True,True,True,True,True,True,True,True]
o_sws=[True,True,True,True,True,True,True,True,True,True]
isDisplay=False
def show_bitmap(x,y,fd):
for row in range(0,7):
for col in range(0,7):
display.pixel(x+col,y+row,1 if (0x80>>col) & fd[row] else 0)
def DisplayMenu(menuNo):
global isDisplay,strs,i2c,display
i2c.deinit()
i2c = busio.I2C(GP15, GP14)
display = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c, addr=0x3C)
display.fill(0) # 表示内容消去
y=1
for str in strs[menuNo]:
i=0
for c in str:
d = mf.font(ord(c))
show_bitmap(i,y,d)
i+=8
y+=10
display.show()
isDisplay=True
strs=(
("――モード1 スタンダード――",
"1.コピー 2.カット", #Ctrl+C,Ctrl+X
"3.はりつけ4.すべてせんたく", #Ctrl+V,Ctrl+A
"5.やり直し6.再実行", #Ctrl+Z,Ctrl+Y
"7.デスク 8.ウィンドウ閉じる", #Win+D,Ctrl+W
"上ボリューム下Ctrl+ホイール",),
("――モード2 YouTube――",
"1.停止再生 2.ミュート", #k,m
"3.10秒進む4.10秒もどる", #l,j
"5.前フレーム 6.次フレーム", #.,,
"7.全画面8.小ウィンドウ", #f,i
"上.ボリューム 下.明るさ",),
("――モード3 Winキー ――",
"1.ゲームバー 2.文字起こし", #G,H
"3.設定画面 4.Winロック", #I,L
"5.画面設定6.クリップりれき", #P,V
"7.拡大表示 8.縮小表示", #+,-
"上マウス左右 下マウス上下",),
("――モード4 メッセージ送信 ――",
"1.Hello 2.Bye",
"3.OK 4.NG",
"5.login 6.logout",
"7.prev 8.next",
"上マウス左右 下マウス上下",),
)
#command 1:kbd.press&release,2:cc.press&release,3:layout.write,4:Mouse.X,5:Mouse.Y,6:MouseWheel,7:Ctrl+MouseWheel,8:MenuChange,9:MenuDisplayOn/OFF
btn_cmds=((
(1,(Keycode.LEFT_CONTROL,Keycode.C,)),(1,(Keycode.LEFT_CONTROL,Keycode.X,)),
(1,(Keycode.LEFT_CONTROL,Keycode.V,)),(1,(Keycode.LEFT_CONTROL,Keycode.A,)),
(1,(Keycode.LEFT_CONTROL,Keycode.Z,)),(1,(Keycode.LEFT_CONTROL,Keycode.Y,)),
(1,(Keycode.WINDOWS,Keycode.D,)),(1,(Keycode.LEFT_CONTROL,Keycode.W,)),
(8,),(9,)),
(
(1,(Keycode.K,)),(1,(Keycode.M,)),(1,(Keycode.L,)),(1,(Keycode.J,)),
(1,(Keycode.PERIOD,)),(1,(Keycode.COMMA,)),(1,(Keycode.F,)),(1,(Keycode.I,)),
(8,),(9,)),
(
(1,(Keycode.WINDOWS,Keycode.G,)),(1,(Keycode.WINDOWS,Keycode.H,)),(1,(Keycode.WINDOWS,Keycode.I,)),(1,(Keycode.WINDOWS,Keycode.L,)),
(1,(Keycode.WINDOWS,Keycode.P,)),(1,(Keycode.WINDOWS,Keycode.V,)),(1,(Keycode.WINDOWS,Keycode.KEYPAD_PLUS,)),(1,(Keycode.WINDOWS,Keycode.KEYPAD_MINUS,)),
(8,),(9,)),
(
(3,"Hello"),(3,"Bye"),(3,"OK"),(3,"NG"),(3,"login"),(3,"logout"),(3,"prev"),(3,"next"),(8,),(9,))
)
#1:NormalWheel,2:Ctrl+Wheel,3:Volume,4:Brightness,5:MouseX,6:MouseY
rotally_cmds=((3,2),(3,4),(5,6),(5,6))
def buttonAction(button):
global mode
global isDisplay
global btn_cmds
global display
global keyboard,cc,layout
if btn_cmds[mode][button][0] == 1:
keyboard.press(*(btn_cmds[mode][button][1]))
keyboard.release(*(btn_cmds[mode][button][1]))
elif btn_cmds[mode][button][0] == 2:
cc.press(*(btn_cmds[mode][button][1]))
cc.release(*(btn_cmds[mode][button][1]))
elif btn_cmds[mode][button][0] == 3:
layout.write(btn_cmds[mode][button][1])
elif btn_cmds[mode][button][0] == 8:
mode= (mode +1 )%4
DisplayMenu(mode)
with open('mode.ini', 'w') as file:
file.write("{}".format(mode))
elif btn_cmds[mode][button][0] == 9:
if isDisplay :
display.fill(0)
display.show()
isDisplay=False
else :
DisplayMenu(mode)
#1:NormalWheel,2:Ctrl+Wheel,3:Volume,4:Brightness,5:MouseX,6:MouseY
def rotallyAction(kind,direction):
global mode
global rotally_cmds
global keyboard,cc,mouse
if rotally_cmds[mode][kind] == 1:
mouse.move(0,0,direction)
elif rotally_cmds[mode][kind] == 2:
keyboard.press(Keycode.LEFT_CONTROL)
mouse.move(0,0,direction)
keyboard.release(Keycode.LEFT_CONTROL)
elif rotally_cmds[mode][kind] == 3:
if direction > 0 :
cc.send(ConsumerControlCode.VOLUME_INCREMENT)
else :
cc.send(ConsumerControlCode.VOLUME_DECREMENT)
elif rotally_cmds[mode][kind] == 4:
if direction > 0 :
cc.send(ConsumerControlCode.BRIGHTNESS_INCREMENT)
else :
cc.send(ConsumerControlCode.BRIGHTNESS_DECREMENT)
elif rotally_cmds[mode][kind] == 5:
mouse.move(direction,0,0)
elif rotally_cmds[mode][kind] == 6:
mouse.move(0,direction,0)
for _gpio in GP0,GP1,GP2,GP3,GP4,GP28,GP27,GP26,GP5,GP6:
s = digitalio.DigitalInOut(_gpio)
s.direction = digitalio.Direction.INPUT
s.pull = digitalio.Pull.UP
sw.append(s)
try:
while True:
nn_s1 , nn_s2= s1.value , s2.value
if (nn_s1 != n_s1 or nn_s2 != n_s2) :
n_s1,n_s2 =nn_s1,nn_s2
elif(n_s1 != o_s1 or n_s2 != o_s2) :
if n_s1 ^ o_s2 == 0 :
rotallyAction(0,1)
else:
rotallyAction(0,-1)
o_s1,o_s2=n_s1,n_s2
nn_s3 , nn_s4= s3.value , s4.value
if (nn_s3 != n_s3 or nn_s4 != n_s4) :
n_s3,n_s4 =nn_s3,nn_s4
elif(n_s3 != o_s3 or n_s4 != o_s4) :
if n_s3 ^ o_s4 == 0 :
rotallyAction(1,1)
else:
rotallyAction(1,-1)
o_s3,o_s4=n_s3,n_s4
for i in range(10):
n_sws[i] = sw[i].value
if ((o_sws[i]==True) and (n_sws[i]==False)):
buttonAction(i)
o_sws[i]=n_sws[i]
time.sleep(0.0002)
except KeyboardInterrupt:
# raise
pass
except Exception as e:
pass
2025年2月24日月曜日
Raspberrypi picoでのHIDキーアサイン画面表示案
キーアサインと画面表示の案。
一番左の黒のボタンはモードや画面の切り替えに使うとして、8個のキーとロータリーエンコーダのキーアサイン案
from misakifont import MisakiFont
import busio
import adafruit_ssd1306
from board import *
i2c = busio.I2C(GP15, GP14)
display = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c, addr=0x3C)
display.fill(0) # 表示内容消去
"""
フォントのビットマップ表示
"""
def show_bitmap(x,y,fd):
for row in range(0,7):
for col in range(0,7):
display.pixel(x+col,y+row,1 if (0x80>>col) & fd[row] else 0)
strs=(
("――モード1 スタンダード――",
"1.コピー 2.カット", #Ctrl+C,Ctrl+X
"3.はりつけ4.すべてせんたく", #Ctrl+V,Ctrl+A
"5.やり直し6.再実行", #Ctrl+Z,Ctrl+Y
"7.デスク 8.ウィンドウ閉じる", #Win+D,Ctrl+W
"上ボリューム下Ctrl+ホイール",),
("――モード2 YouTube――",
"1.停止再生 2.ミュート", #k,m
"3.10秒進む4.10秒もどる", #l,j
"5.前フレーム 6.次フレーム", #.,,
"7.全画面8.小ウィンドウ", #f,i
"上ボリューム下Ctrl+ホイール",),
("――モード3 Winキー ――",
"1.ゲームバー 2.文字起こし", #G,H
"3.設定画面 4.Winロック", #I,L
"5.画面設定6.クリップりれき", #P,V
"7.拡大表示 8.縮小表示", #+,-
"上マウス左右 下マウス上下",),
)
mf = MisakiFont()
y=1
for str in strs[2]:
i=0
for c in str:
d = mf.font(ord(c))
show_bitmap(i,y,d)
i+=8
y+=10
display.show()
表示はこんな感じ。
KeyboardLayout.writeを使って文字列を送出することもできるけど、使う場面がないかな。
ロータリーエンコーダのよみとり(エッジ変化の読み取り)
前回までロータリーエンコーダのON,OFFの状態
を見ていたが、今回はOFF→ON(立ち上がり)ON→OFF(立ち下り)
の変化を見てみることにする。
→状態変化をイベントとして受け取ることにより、circuitpythonが
(バタつきなく)正しく読み取っていることを期待するとともに、
よくわからない待ち時間の考慮をなくす。
その前にロータリーエンコーダの仕組みを復習。
ロータリーエンコーダは、それを回すと、
...OFF→ON→ON→OFF→OFF→ON..と状態を4つで
1周期を繰り返すスイッチが2個あり、
それぞれのスイッチは他方より4分の1周期ずれているもの。
前回はスイッチを回したときのスイッチの状態に着目して、
一方のスイッチの状態ともう片方の直前の状態をを比較したときに、
同じであれば順方向、逆であれば逆方向となる都合の良い動きに着目し、
それらを排他的論理和を取ることにより方向を調べていた。
今回はスイッチを回したときのスイッチの変化に着目して、
同時に両方のスイッチは変化しない(スイッチの変化は1個づつ)、
自身の今回の変化(立ち上がり、立ち下り)の方向と
相手側の前回の変化の方向を比較し、
自身がSW1なら過去のSW2の方向変化が同じであれば順方向、違えば逆方向
自身がSW2なら過去のSW1の方向変化が同じであれば逆方向、違えば順方向
となる都合の良い動きに着目する。
前回は起動直後の状態をとれたので、最初からデータを信用できたが、
今回はプログラム起動直前の状態変化は取れないため、
最初の2カウント分の読み取りは破棄する。
ま、このページのものを参考にして
https://learn.adafruit.com/key-pad-matrix-scanning-in-circuitpython/keys-one-key-per-pin
自分用に書き換えたのが以下のプログラム
# SPDX-FileCopyrightText: 2022 Dan Halbert for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import board
import keypad
KEY_PINS = (
board.GP0,
board.GP1,
board.GP2,
board.GP3,
board.GP4,
board.GP28,
board.GP27,
board.GP26,
board.GP5,
board.GP6,
board.GP16, #RE1S1
board.GP17, #RE1S2
board.GP18, #RE2S1
board.GP19, #RE2S2
)
keys = keypad.Keys(KEY_PINS, value_when_pressed=False, pull=True)
waitcount=2
isRE1Sw1Raise=False
isRE1Sw2Raise=False
while True:
event = keys.events.get()
if event:
# A key transition occurred.
#print(event)
if event.pressed:
# Turn the key blue when pressed
if event.key_number == 10 :
isRE1Sw1Raise=False
if waitcount > 0:
waitcount -=1
continue
if isRE1Sw1Raise == isRE1Sw2Raise : print("UP")
else : print("DOWN")
elif event.key_number == 11 :
isRE1Sw2Raise=False
if waitcount > 0:
waitcount -=1
continue
if isRE1Sw1Raise != isRE1Sw2Raise : print("UP")
else : print("DOWN")
# This could just be `else:`,
# since event.pressed and event.released are opposites.
if event.released:
if event.key_number == 10 :
isRE1Sw1Raise=True
if waitcount > 0:
waitcount -=1
continue
if isRE1Sw1Raise == isRE1Sw2Raise : print("UP")
else : print("DOWN")
elif event.key_number == 11 :
isRE1Sw2Raise=True
if waitcount > 0:
waitcount -=1
continue
if isRE1Sw1Raise != isRE1Sw2Raise : print("UP")
else : print("DOWN")
結果、クリックなしのロータリーエンコーダでゆっくり目に回すといい感じに読み取るが、
速く回すと、逆方向の検知がされてしまう。
クリックありの方で、コメントのprintを有効にして、その他のprintを無効にした結果、以下のようにまったく使い物にならず。
期待していたのは、11と10が交互に出るものなんだけどそうなっていない。
10が多いということは、11を拾えていないのか10がバタついているのか、その両方なのかよくわからない。
IncrementalEncoderでクリックありのものはdivisorを4にクリックなしのものはdivisorを2で使うのがよいのかなぁ。
2025年2月23日日曜日
Raspberry Pi Picoに接続したSSD1302に美咲フォントで表示
https://github.com/Tamakichi/pico_MicroPython_misakifont
からcodeボタン→Download ZIPでダウンロードした後、
misakifontフォルダをCIRCUITPYドライブのlibにコピーした後、
sample_misaki.pyをSSD1302に表示させるため以下のようにちょこっと修正して、
from misakifont import MisakiFont
import busio
import adafruit_ssd1306
from board import *
i2c = busio.I2C(GP15, GP14)
display = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c, addr=0x3C)
display.fill(0) # 表示内容消去
"""
フォントのビットマップ表示
"""
def show_bitmap(x,y,fd):
for row in range(0,7):
for col in range(0,7):
display.pixel(x+col,y+row,1 if (0x80>>col) & fd[row] else 0)
str="こんにちは世界!"
mf = MisakiFont()
i=0
for c in str:
d = mf.font(ord(c))
show_bitmap(10+i,30,d)
i+=8
display.show()
表示させるとこんな感じ。
フォントの大きさの自由度はあまりないけど、これでいいんじゃないかな?
raspberry pi picoでSSD1302に日本語を表示させてみた。
raspberry pi picoでSSD1302に漢字を表示させたい。
というわけで以下の順でやってみた。
1.フォントを探す
2.イメージのバイナリデータをファイル化
3.漢字コードからバイナリファイルの場所を算出するインデックスを作成
4.文字コード変換1(ShiftJIS→JIS変換)
5.文字コード変換2(UTF8→ShiftJIS変換)
6.文字画像確認その1(コンソール出力)
7.文字画像確認その2(SSD1302への出力)
8.文字列を表示する。
1.フォントを探す
https://www.mgo-tec.com/blog-entry-ssd1306-shinonome.html を見てみると東雲フォント
というものがあるみたいなので、今回はこれを(shnmk16.bdf)を使ってみる。
2.イメージのバイナリデータをファイル化
どうせメモリ上にフォントイメージを載せられないので、一字毎イメージファイルを読むことにする。
バイナリデータは1文字32バイトで保存。
そのためのshnmk16.bdfからバイナリファイルを抽出するスクリプトを作って流してみる。
def readandwritefontsfile():
isImageArea=False
code=0
image=b''
with open('shnmk16.bdf') as f:
with open('fontImage.bin','wb') as wf:
for str in f:
if str[:9]=="STARTCHAR" :
code=int(str[10:14],16)
elif str[:6]=="BITMAP" :
image=b''
isImageArea=True
elif str[:7]=="ENDCHAR" :
wf.write(image)
isImageArea=False
elif isImageArea:
image+=bytes.fromhex(str[:4])
readandwritefontsfile()
で作成されたfontImage.binのファイルサイズが、220,128バイト。
CircuitPyドライブには載せられるが、メモリ上にこのイメージを載せるのは容量的に少し不安がある。
なので、表示の都度このファイルから1文字ずつ読み出すことにする。
3.漢字コードからバイナリファイルの場所を算出するインデックスを作成
shnmk16.bdf内で定義しているコードはJISのよう。
最初の文字コード(10進数)8481からで、使われていない文字はそのコードを飛ばしていて、
フォントコードが飛び番になっている。
確認方法として、以下を実施
・「shnmk16.bdf」をキーワードENCODINGでgrepし、
・出てきた行をExcelに貼り付け、
・区切り位置ウィザードで半角スペースを区切り
・E2セルに=D2-D1-1の計算式を入れ、E列末までコピーし、値貼り付けにより計算式を数値にして
・オートフィルタでE列として、マイナス値が1件を確認したのち、値0のもののみ表示し、表示された行を行削除し、
・オートフィルタを解除して、F1セルに=E1、F2セルに=F1+E2の計算式を入れ、F2セルをF列末までコピーして
・D列(コード)、E列(飛び番)、F列(累積)を抽出して確認
確認したところ、以下のコード値で直前のコードから+1より大きい数字に飛んでいる。コード値と飛び番数は以下。
コード 飛び番 累積
8737 162 162
8762 11 173
8778 8 181
8796 11 192
8818 7 199
8830 4 203
9008 177 380
9025 7 387
9057 6 393
9249 166 559
9505 173 732
9761 170 902
9793 8 910
10017 200 1110
10065 15 1125
10273 175 1300
12321 2016 3316
12577 162 3478
12833 162 3640
13089 162 3802
13345 162 3964
13601 162 4126
13857 162 4288
14113 162 4450
14369 162 4612
14625 162 4774
14881 162 4936
15137 162 5098
15393 162 5260
15649 162 5422
15905 162 5584
16161 162 5746
16417 162 5908
16673 162 6070
16929 162 6232
17185 162 6394
17441 162 6556
17697 162 6718
17953 162 6880
18209 162 7042
18465 162 7204
18721 162 7366
18977 162 7528
19233 162 7690
19489 162 7852
19745 162 8014
20001 162 8176
20257 162 8338
20513 205 8543
20769 162 8705
21025 162 8867
21281 162 9029
21537 162 9191
21793 162 9353
22049 162 9515
22305 162 9677
22561 162 9839
22817 162 10001
23073 162 10163
23329 162 10325
23585 162 10487
23841 162 10649
24097 162 10811
24353 162 10973
24609 162 11135
24865 162 11297
25121 162 11459
25377 162 11621
25633 162 11783
25889 162 11945
26145 162 12107
26401 162 12269
26657 162 12431
26913 162 12593
27169 162 12755
27425 162 12917
27681 162 13079
27937 162 13241
28193 162 13403
28449 162 13565
28705 162 13727
28961 162 13889
29217 162 14051
29473 162 14213
29729 162 14375
これをもとに以下の関数で入力code(SJISコード)を、その値により補正値を変え、
最終的にイメージファイルの読み込みアドレスを算出する
具体的には、
・G2セルに="elif code <"&D2&" :(Alt+Enter) code-="&E1 計算式を入れG列末までコピーして、
・G列をコピーし、テキストエディタに貼り付け、正規表現置換で\r?\nを\r\nに置換。
あとは前後を整備して、以下の関数を作る。
def binfileindex(code):
if code < 8737 :
pass
elif code <8762 :
code-=162
elif code <8778 :
code-=173
elif code <8796 :
code-=181
elif code <8818 :
code-=192
elif code <8830 :
code-=199
elif code <9008 :
code-=203
elif code <9025 :
code-=380
elif code <9057 :
code-=387
elif code <9249 :
code-=393
elif code <9505 :
code-=559
elif code <9761 :
code-=732
elif code <9793 :
code-=902
elif code <10017 :
code-=910
elif code <10065 :
code-=1110
elif code <10273 :
code-=1125
elif code <12321 :
code-=1300
elif code <12577 :
code-=3316
elif code <12833 :
code-=3478
elif code <13089 :
code-=3640
elif code <13345 :
code-=3802
elif code <13601 :
code-=3964
elif code <13857 :
code-=4126
elif code <14113 :
code-=4288
elif code <14369 :
code-=4450
elif code <14625 :
code-=4612
elif code <14881 :
code-=4774
elif code <15137 :
code-=4936
elif code <15393 :
code-=5098
elif code <15649 :
code-=5260
elif code <15905 :
code-=5422
elif code <16161 :
code-=5584
elif code <16417 :
code-=5746
elif code <16673 :
code-=5908
elif code <16929 :
code-=6070
elif code <17185 :
code-=6232
elif code <17441 :
code-=6394
elif code <17697 :
code-=6556
elif code <17953 :
code-=6718
elif code <18209 :
code-=6880
elif code <18465 :
code-=7042
elif code <18721 :
code-=7204
elif code <18977 :
code-=7366
elif code <19233 :
code-=7528
elif code <19489 :
code-=7690
elif code <19745 :
code-=7852
elif code <20001 :
code-=8014
elif code <20257 :
code-=8176
elif code <20513 :
code-=8338
elif code <20769 :
code-=8543
elif code <21025 :
code-=8705
elif code <21281 :
code-=8867
elif code <21537 :
code-=9029
elif code <21793 :
code-=9191
elif code <22049 :
code-=9353
elif code <22305 :
code-=9515
elif code <22561 :
code-=9677
elif code <22817 :
code-=9839
elif code <23073 :
code-=10001
elif code <23329 :
code-=10163
elif code <23585 :
code-=10325
elif code <23841 :
code-=10487
elif code <24097 :
code-=10649
elif code <24353 :
code-=10811
elif code <24609 :
code-=10973
elif code <24865 :
code-=11135
elif code <25121 :
code-=11297
elif code <25377 :
code-=11459
elif code <25633 :
code-=11621
elif code <25889 :
code-=11783
elif code <26145 :
code-=11945
elif code <26401 :
code-=12107
elif code <26657 :
code-=12269
elif code <26913 :
code-=12431
elif code <27169 :
code-=12593
elif code <27425 :
code-=12755
elif code <27681 :
code-=12917
elif code <27937 :
code-=13079
elif code <28193 :
code-=13241
elif code <28449 :
code-=13403
elif code <28705 :
code-=13565
elif code <28961 :
code-=13727
elif code <29217 :
code-=13889
elif code <29473 :
code-=14051
elif code <29729 :
code-=14213
else :
code-=14375
return (code-8481)*32
d=binfileindex(29400)
4.文字コード変換1(ShiftJIS→JIS変換)
pythonの標準でのJISコード変換は見つからなかったので、SJIS→JISの変換関数を作る。
def sjis2jis(indata):
h_data=int.from_bytes(indata)>>8
l_data=int.from_bytes(indata) & 0xff
if h_data<=0x9f :
if l_data < 0x9f :
h_data=(h_data<<1) - 0xe1
else :
h_data=(h_data<<1) - 0xe0
else :
if l_data < 0x9f :
h_data =(h_data << 1 ) -0x161
else:
h_data =(h_data << 1 ) -0x160
if l_data < 0x7f :
l_data -= 0x1f
elif l_data < 0x9f:
l_data -=0x20
else:
l_data -=0x7e
return h_data << 8 | l_data
5.文字コード変換2(UTF8→ShiftJIS変換)
circuitpythonでは、「'あ'.encode('shift_jis')」が使えずUTF-8で表示されてしまう。
なので自前で変換テーブルを作成する。元ネタとして、以下に簡易的なUTF-8→ShiftJISの変換の情報があるので
https://ameblo.jp/fc2miha/entry-12876272336.html
上の情報から、以下の情報を辿って、
https://drive.google.com/file/d/1dMNG8bcM58w7uHRdBbqsP2R1HGAU9K2z/view?usp=sharing
UTF-8→SJISの変換テーブル(list.dat)をダウンロードする。
このlist.datを入力にした、3バイトのUTF-8コードと2バイトのShiftJISのペアの5バイト*変換文字分のデータを作る。
次のプログラムでutf8tosjis.binを作り、
import json
def readandwriteconvfile():
flg_firstline=True
dic=dict()
with open('utf8tosjis.bin','wb') as wf:
with open('list.dat','r',encoding='utf-8') as f:
for str in f:
if flg_firstline :
flg_firstline=False
continue
str_utf8code,str_sjiscode,_=str.split(',')
wf.write(int(str_utf8code,16).to_bytes(3,byteorder='big'))
wf.write(int(str_sjiscode,16).to_bytes(2,byteorder='big'))
readandwriteconvfile()
出来上がった変換テーブル(utf8tosjis.bin)ファイルをcircuitpyドライブ直下におく。
サイズは、46,795バイト。どうせイメージを読み込むのにファイルアクセスがあるので
こちらを高速化してもあまり意味がないが、今回は変換テーブルを起動時にファイルから読み込み
メモリ上に載せておくことにする。
(ただ辞書にしてjson.dumpやjson.loadをすると、すごく時間がかかるのでメモリ一括読み込みし、
キーをハッシュアクセスではなく、ループで検索することにする。)
dic=dict()
allbyte=b''
with open('utf8tosjis.bin','rb') as f:
allbyte=f.read()
で、変換表を使ったutf8文字列→sjis文字列への変換関数を作る。
def utf8str2sjisstr(utf8str):
retval=b''
for utf8char in utf8str:
utf8=utf8char.encode()
i=0
while i>8
l_data=indata & 0xff
if h_data<=0x9f :
if l_data < 0x9f :
h_data=(h_data<<1) - 0xe1
else :
h_data=(h_data<<1) - 0xe0
else :
if l_data < 0x9f :
h_data =(h_data << 1 ) -0x161
else:
h_data =(h_data << 1 ) -0x160
if l_data < 0x7f :
l_data -= 0x1f
elif l_data < 0x9f:
l_data -=0x20
else:
l_data -=0x7e
return h_data << 8 | l_data
str_mainte='メンテナンス中'
putString(utf8str2sjisstr(str_mainte),28,8)
表示はこんな感じ。
utf8→sjis変換部分やユーザから見えなくてもよいので、putStringの中から呼べばよかったかも。
ま、泥臭いし半角対応はできていないので、今回作ってみたものの使わないかな?
8x8の美咲フォントを使う方は、いろいろ整備されているみたいだし。
2025年2月16日日曜日
CircuitPythonにロータリーエンコーダー用のモジュールがあった。
https://docs.circuitpython.org/en/latest/shared-bindings/rotaryio/index.html circuit pythonにロータリーエンコーダー専用のモジュールがあるのなら自作しないで使うべきでした。 で、このページをみたらクリックタイプの動きがわかりました。 秋月で買った100円のクリックタイプのロータリーエンコーダーは1クリック進むとOFF,OFF,ON,ONの1サイクル分進んでいた、と。 rotaryio.IncrementalEncoderを呼び出すときに指定する。divisorがデフォルトで4で、 これはdedents(引っ掛かり)が、(ON,ON,OFF,OFFの)1サイクルあたりに1回しかこない場合に指定するようです。 ということは、1クリック分動かすと1サイクル分うごくものがある、と、 ロータリーエンコーダをGPIO1,GND,GPIO2に接続し、 上記のcircuitpythonのページのサンプルをraspberrypipico用にピンを少し書き換えて、以下のプログラムを動かしてみました。 import rotaryio import time from board import * enc = rotaryio.IncrementalEncoder(GP1, GP2) last_position = None while True: position = enc.position if last_position == None or position != last_position: print(position) last_position = position 結果、ロータリーエンコーダを回すと+1もしくは-1をした値を返してくれた。 もう簡単に試せるクリックなしのロータリーエンコーダを持っていないので試していないのだけど、 クリックなしのロータリーエンコーダーの場合は、IncrementalEncoderの第三引数に1を入れればよいのだと思う。 2025/2/20 追記: クリックなしロータリーエンコーダーでIncrementalEncoderモジュールを使ったところ、第三引数なし(divisor=4)だと誤りなく拾えるが、 回す量に対する読み取り頻度が体感1/4になってしまい、第三引数に1を設定すると読み取り頻度が向上するが、逆方向読み取りも多々発生する。 1周期1カウントや2カウントを拾うのなら使えそうだが、1周期4カウント拾うのは汎用的なものだと無理があるのかな?
登録:
投稿 (Atom)













