編集履歴一覧に戻る
akira.keiのアイコン画像

akira.kei が 2025年03月24日00時46分18秒 に編集

コメント無し

本文の変更

-

[<前の記事](https://elchika.com/article/81fc52a0-43d7-40af-8824-0afd2cf25deb/) : [次の記事>]()

+

[<前の記事](https://elchika.com/article/81fc52a0-43d7-40af-8824-0afd2cf25deb/) : [次の記事>](https://elchika.com/article/bed472d7-e644-4446-9fb5-42e1ba6c2735/)

## Raspberry Pi Pico+Micropython [前の記事で](https://elchika.com/article/81fc52a0-43d7-40af-8824-0afd2cf25deb/)C言語での開発環境を整えた割に、環境が複雑(=面倒くさ)すぎて開発を始めるモチベーションが沸かない。もっと簡単に[Thonny](https://thonny.org/)+[Micropython](https://micropython.org/)を使ってみることにする。ThonnyのインストールやPicoへのMicropythonの書き込みなどは他の記事に任せるとして、この記事は「[RP2 用クイックリファレンス](https://micropython-docs-ja.readthedocs.io/ja/latest/rp2/quickref.html)」とても参考になる。 これまで何度かプログラムを書いてみたが、そのうち飽きてPICとか触り出すわけで、気が向いたら戻って何度も再発見を行うことになる。すぐに書き方を忘れてしまうので、自分用の備忘録としてこの記事を書いておこう。 ## この部品、動くのか? 例えばI2Cのディスプレイを部品箱から久しぶりに取り出したとする。 ![I2Cディスプレイ](https://camo.elchika.com/410c398e88fb6e8726fa4e5b5699c0e5fc8c97b1/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33363031626666382d633530632d343762382d613765362d3531663731393163323336642f37646663376466642d326238652d343037312d616336652d663961376633336130356663/) これをPICで動かそうとした時に表示できなかったりすると、PICに書いたファームウェアが悪いのか部品が壊れているのかわからない場合が多い(大抵は接続ミスだけど)。以前はArdiono UNOに繋いでサンプルを動かすようにしていたが、イマドキならPicoかもと思い直したので、これからのためにお馴染みの(?)開発ボードを作ってみた。 ## 開発ボード ![PICO開発ボード](https://camo.elchika.com/9c7be0e0115b98e1abc0deaa6f4a77747f5bedd7/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33363031626666382d633530632d343762382d613765362d3531663731393163323336642f35643538383964302d613164372d343736632d623231632d613937326462313332306434/) PicoとThonyを組み合わせるならデバッグ用のシリアルモニタは必要ないので、ADC用のボリューム、リセットスイッチ、電源モニタ用LEDおよびトグルスイッチを基板に載せた。Picoの各ピンはソケットで引き出せるようにして、信号モニタはPico側に実装した連結ピンを利用する。 台に使用した百均Seriaのアクリル板がちょっと小さいので基板側がかなり窮屈になってしまった。 ## まずはLチカ よくあるタイプのLチカをやってみる。ArduinoのExamples Blinkとほぼ同じ内容だ。Pythonチュートリアルだとimport machineと書くようだが、例えばGPIOの表記が「machine.Pin」とか長すぎるので、fromを使ってみた。 ```Python: blinker.py from machine import Pin from time import sleep led = Pin("LED", Pin.OUT) while True: led.toggle() sleep(0.5) ``` オシロでモニタしてみると周期は安定しており、精度も意外にちゃんとしている。 ![blinker](https://camo.elchika.com/b8ac04e30f88d544d1767f4002e0c7c355e34e68/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33363031626666382d633530632d343762382d613765362d3531663731393163323336642f34613336346132332d653033642d346336322d613530652d336438383431363161316236/) ## 次はPWMで マイコンなんだから周期処理は無限ループ中ではなく、ハードウェアで実現すべきだ。ここではPWM機能を使ってみよう。たった3行でいい。 ```Python: from machine import PWM,Pin led=Pin("LED",Pin.OUT) pwm=PWM(led,freq=9,duty_u16=32768) ``` 周波数は2にしたかったが最小で9しか設定できなかった。かなり忙しなく点滅するが、これはこれでいい。 ## タイマー割り込み PWMでは1秒点滅ができないので、タイマー割り込みを使ってみた。周期2Hzのトグル動作なので1Hzで点滅する。無限ループがないので実行するとすぐ終了して戻ってくるが、LEDはずっと点滅する。 ```Python: from machine import Pin,Timer led = Pin("LED", Pin.OUT) def toggle(timer): led.toggle() timer=Timer() timer.init(mode=Timer.PERIODIC, freq=2, callback=toggle) ``` ## 柔らかホタル点滅 ここまでのLED点滅はビシッと点灯し同じように消灯するが、ふんわりと点灯と消灯を繰り返す点滅にしてみる。無限ループ内に2つのforループを入れて、PWMのデューティで点滅動作をさせてみた。 ```Python: from machine import PWM,Pin from time import sleep led=Pin("LED",Pin.OUT) pwm=PWM(led, freq=256000) while True: for i in range(0,256): pwm.duty_u16(256*i) sleep(0.5/256) for i in range(0,256): pwm.duty_u16(256*(255-i)) sleep(0.5/256) ``` 何となく点滅が速いのでオシロで見てみると、どうも計算通りになっていない。 ![キャプションを入力できます](https://camo.elchika.com/a9b693cfc205f10a725fe4f7f31c787a15042683/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33363031626666382d633530632d343762382d613765362d3531663731393163323336642f65333063373461632d303263312d346464662d623134612d343634616332623764343533/) ## 正弦波点滅 もう少し柔らかな点滅を目指して正弦波で点滅させてみた。 ```Python: from machine import PWM,Pin from time import sleep from math import sin,pi led=Pin(0,Pin.OUT) pwm=PWM(led, freq=256000) s=[] for i in range(0,256): s.append(int(32767*(sin(2*pi*i/256)+1))) while True: for i in range(0,256): pwm.duty_u16(s[i]) sleep(1/256) ``` それでも無限ループ内でsleep頼りだと計算通りの周期で点滅しない。そして明るさがデューティに比例しないので三角波だろうが正弦波だろうが違いが見た目ではわからない。 ![blinkerSine](https://camo.elchika.com/d8abc1ff00a6ea00309e8fe42fa15c2c6f641184/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33363031626666382d633530632d343762382d613765362d3531663731393163323336642f36326464663732642d333234352d343063382d613537312d666666626537316564333134/) ## ADCで明るさ調整 点滅ではなくボリュームでLED輝度を調整してみた。ADC入力もMicropythonなら簡単に書ける。 ```Python: from machine import Pin,PWM,ADC from time import sleep led=Pin("LED", Pin.OUT) pwm=PWM(led,freq=200000) adc=ADC(Pin(26)) while True: pwm.duty_u16(adc.read_u16()) sleep(0.1) ``` ## 点滅速度切り替え スイッチを押すと点滅速度が切り替わるようにしてみた。ミソは切り替えるのはタイマーの周期ではなく、異なる速さを持つタイマーを2つ用意して、トグル動作を切り替えてみた。スイッチもタイマーも割り込みであり無限ループはない。 なお、チャタリング対策をしていないので、切り替えは安定しない。 ```python: from machine import Pin,Timer def chgstate(p): global fast fast= not fast def tglslow(timer): global fast,led if not fast: led.toggle() def tglfast(timer): global fast,led if fast: led.toggle() led = Pin("LED", Pin.OUT) fast=False; sw = Pin(22,Pin.IN,Pin.PULL_UP) sw.irq(trigger=Pin.IRQ_FALLING, handler=chgstate) timer1=Timer() timer1.init(mode=Timer.PERIODIC, freq=2, callback=tglslow) timer2=Timer() timer2.init(mode=Timer.PERIODIC, freq=10, callback=tglfast) ```