前回、何となくRaspberry Pi Picoを動かせるようになったので、MicroPythonの勉強を兼ねてDSPラジオを作っていきたい。
もともとプログラミングが苦手でかつ、MicroPythonについて知識がほとんど無いので、基本的な使い方を調べながら徐々に作ってみる。
まず最初に、端子割り込みを使ってロータリーエンコーダーの読み取りをやってみる。
DSPラジオの操作には欠かせない機能なのである。
何も知らないのでChatGPTに聞いてみる。それっぽいコードを書いてくれたのだが、意図したのと違ったので、少し変更して以下とした。
-------------------------------------------------------------
from machine import Pin
import time
# グローバル変数
encoder_position = 0
last_encoder_state = 0
# コールバック関数
def rotary_encoder_handler(pin):
global encoder_position, last_encoder_state
# 現在の状態を読み取る
state_b = b_pin.value()
# 位置を更新
if state_b == 1:
encoder_position += 1
else:
encoder_position -= 1
# GPIOピンの設定
a_pin = Pin(14, Pin.IN, Pin.PULL_UP)
b_pin = Pin(15, Pin.IN, Pin.PULL_UP)
# 割り込みの設定
a_pin.irq(trigger=Pin.IRQ_FALLING, handler=rotary_encoder_handler)
# メインループ
try:
while True:
if encoder_position != last_encoder_state:
print("Encoder position:", encoder_position)
last_encoder_state = encoder_position
time.sleep(0.5)
except KeyboardInterrupt:
print("プログラムを終了します")
------------------------------------------------------
このようにロータリーエンコーダーを接続
動かしてみると、それっぽく動くようになった。
これで、ロータリーエンコーダーは使えそうな気がしてきた。
次は、表示機能
前回、OLEDの表示を試したが、文字が小さくて使いにくいのでLCDにする。
使うのはこれ↓
AQM1602のライブラリは無いものか?と探したけども無いようだ。
ゼロからコードを書くのはきついと思っていたが、こちら↓に良い感じにまとめてくれているのを発見。
一旦そのまま動かしてみる。
このように接続。I2Cの波形を見た結果、内部プルアップだけでは不足気味なので10Kでプルアップを追加してある。
お、ちゃんと動く
先人の知恵と努力はありがたい
しかし、これからDSPラジオを作るのにあたっては、3つほど気になったので修正した。
①文字表示の方法が、ライン指定であって、カーソル位置指定でない
setCursor(x,y)を追加してprint()を修正
②I2Cの設定をライブラリの中で行っている
I2CはDSPラジオICと共有する予定なので、変な競合は避けたい。
メインプログラム側で設定して、ライブラリに渡すように修正
③print()には文字列を渡さないと表示してくれない。
数値で渡された場合に、文字列に変換して表示するように修正
MicroPythonの超初心者なので、いろいろ調べたり、他のライブラリがどのように記述しているか確認したりして、おじさん的には、たったこれだけでも苦労した。
ああ、道のりは遠い。
以下を、「nyan_aqm1602y.py」として保存
"""
AQM1602
Resolution: 16 x 2
I2C Interface
Original : https://plaza.rakuten.co.jp/washiinuru/diary/202310090000/
オリジナルから仕様変更
"""
from micropython import const
import utime
class AQM1602(object):
# I2C
ADDRESS = const(0x3e)
def __init__(self ,i2c):
self.i2c = i2c
self.cmd = bytearray(2)
def init(self):
utime.sleep_ms(40)
self.send_cmd(0x38)
self.send_cmd(0x39)
self.send_cmd(0x14)
self.send_cmd(0x76)
self.send_cmd(0x56)
self.send_cmd(0x6C)
utime.sleep_ms(200)
self.send_cmd(0x38)
self.send_cmd(0x0C)
self.send_cmd(0x01)
utime.sleep_ms(1)
# コマンドを送信する
def send_cmd(self, command):
self.cmd[0] = 0x00
self.cmd[1] = command
self.i2c.writeto(self.ADDRESS,self.cmd)
# データを送信する
def send_data(self, buf):
self.i2c.writeto(self.ADDRESS,b'\x40'+buf)
#カーソル位置を指定
def setCursor(self, xc, yc):
setdata= xc + yc* 0x40 | 0x80
self.send_cmd(setdata)
utime.sleep_ms(2)
def clear(self):
self.send_cmd(0x01)
utime.sleep_ms(2)
# コード取得
def get_cgram_addr(self,code):
""" 文字コードからアドレスを取得 """
l_num = 0
h_num = len(self.kana)-1
while(l_num <= h_num): # 二分探索を使って、
m_num = int((h_num+l_num)/2)
if(int(code) == self.kana[m_num][0]):
return self.kana[m_num][1]
elif(int(code) < self.kana[m_num][0]):
h_num = m_num-1
else:
l_num = m_num+1
return 0x20 # 見つからなかった場合
# 表示
def print(self,buf):
ty = type(buf)
if ty == int or ty == float:
buf = str(buf)
for i in buf:
if(ord(i) <= 0x7f): #ASCII
self.send_data(i.encode())
else: # 0x80以降
kn = self.get_cgram_addr("0x"+i.encode('utf-8').hex())
self.send_data( kn.to_bytes(1,'little'))
kana=(
[0xEFBDA1,0xa1], # 。
[0xEFBDA2,0xa2], # 「
[0xEFBDA3,0xa3], # 」
[0xEFBDA4,0xa4], # 、
[0xEFBDA5,0xa5], # ・
[0xEFBDA6,0xa6], # ヲ
[0xEFBDA7,0xa7], # ァ
[0xEFBDA8,0xa8], # ィ
[0xEFBDA9,0xa9], # ゥ
[0xEFBDAA,0xaa], # ェ
[0xEFBDAB,0xab], # ォ
[0xEFBDAC,0xac], # ャ
[0xEFBDAD,0xad], # ュ
[0xEFBDAE,0xae], # ョ
[0xEFBDAF,0xaf], # ッ
[0xEFBDB0,0xb0], # ー
[0xEFBDB1,0xb1], # ア
[0xEFBDB2,0xb2], # イ
[0xEFBDB3,0xb3], # ウ
[0xEFBDB4,0xb4], # エ
[0xEFBDB5,0xb5], # オ
[0xEFBDB6,0xb6], # カ
[0xEFBDB7,0xb7], # キ
[0xEFBDB8,0xb8], # ク
[0xEFBDB9,0xb9], # ケ
[0xEFBDBA,0xba], # コ
[0xEFBDBB,0xbb], # サ
[0xEFBDBC,0xbc], # シ
[0xEFBDBD,0xbd], # ス
[0xEFBDBE,0xbe], # セ
[0xEFBDBF,0xbf], # ソ
[0xEFBE80,0xc0], # タ
[0xEFBE81,0xc1], # チ
[0xEFBE82,0xc2], # ツ
[0xEFBE83,0xc3], # テ
[0xEFBE84,0xc4], # ト
[0xEFBE85,0xc5], # ナ
[0xEFBE86,0xc6], # ニ
[0xEFBE87,0xc7], # ヌ
[0xEFBE88,0xc8], # ネ
[0xEFBE89,0xc9], # ノ
[0xEFBE8A,0xca], # ハ
[0xEFBE8B,0xcb], # ヒ
[0xEFBE8C,0xcc], # フ
[0xEFBE8D,0xcd], # ヘ
[0xEFBE8E,0xce], # ホ
[0xEFBE8F,0xcf], # マ
[0xEFBE90,0xd0], # ミ
[0xEFBE91,0xd1], # ム
[0xEFBE92,0xd2], # メ
[0xEFBE93,0xd3], # モ
[0xEFBE94,0xd4], # ヤ
[0xEFBE95,0xd5], # ユ
[0xEFBE96,0xd6], # ヨ
[0xEFBE97,0xd7], # ラ
[0xEFBE98,0xd8], # リ
[0xEFBE99,0xd9], # ル
[0xEFBE9A,0xda], # レ
[0xEFBE9B,0xdb], # ロ
[0xEFBE9C,0xdc], # ワ
[0xEFBE9D,0xdd], # ン
[0xEFBE9E,0xde], # ゙
[0xEFBE9F,0xdf] # ゚
)
次に、以下を「main.py」として実行
import nyan_aqm1602y
import utime
from machine import Pin,I2C
sda = Pin(0)
scl = Pin(1)
i2c = I2C(0,sda=sda, scl=scl, freq=100000)
pai = 3.1415926535
LCD=nyan_aqm1602y.AQM1602(i2c)
LCD.init()
while True:
LCD.clear()
LCD.setCursor(0,0)
LCD.print("ラズベリパイ ピコ")
LCD.setCursor(5,1)
LCD.print("デアソブ")
utime.sleep(3)
LCD.clear()
LCD.setCursor(0,0)
LCD.print(pai)
pai2 = "{:.3f}".format(pai)
LCD.setCursor(0,1)
LCD.print(pai2)
utime.sleep(3)
何とか、ちゃんと動作するようになった
小数点以下の指定しない場合小数点以下は6桁までで、勝手に四捨五入されている
次にLCDのバックライトの光量調整をしたいので、PWM出力を試す。
こちら↓に初心者向けに解説が有ったのでそのまま試してみる。
このようにTrでバックライトを駆動するようにした。
先ほどのmain.pyに以下を追加してみる
led = machine.PWM(machine.Pin(10))
led.freq(1000)
led.duty_u16(30000)
GP10の波形を見ると、それっぽく動作して、光量も調節されていた
これで、とりあえずロータリーエンコーダーとLCD周りは何とかなりそう。
DSPラジオ完成までには、まだまだ道のりは遠い。
「大きく腰を据えて頑張ってみるニャ!」
あんたは大きいだけ