Raspberry Pi PicoでDSPラジオ(1) | お父にゃんの電子工作

お父にゃんの電子工作

暇なおじさんが、電子工作(主にラジオ製作)をして勝手な感想を書く

前回、何となく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ラジオ完成までには、まだまだ道のりは遠い。

 

 

「大きく腰を据えて頑張ってみるニャ!」

あんたは大きいだけ