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

akira.kei が 2026年09月25日01時27分44秒 に編集

初版

タイトルの変更

+

Raspberry Pi PicoをSDKで(その2):Blinker-8-inlineやり直し

タグの変更

+

PICO

+

RaspberryPi

記事種類の変更

+

セットアップや使用方法

Lチカの変更

Lチカが設定されました

ライセンスの変更

+

(MIT) The MIT License

本文の変更

+

 [<前の記事](https://elchika.com/article/e00cff8c-935c-498b-824a-42d0ea55307a/) : 次の記事> ## GPIO出力 GPIO出力のわかりやすい例は```pico-example```の[blink](https://github.com/raspberrypi/pico-examples/blob/master/blink/blink.c)ではなく[blink-simple](https://github.com/raspberrypi/pico-examples/blob/master/blink_simple/blink_simple.c)だ。LEDをチカっとさせるだけなのにちょっと冗長な書き方ではあるが、初期化して出力を決めて1か0を出力するだけだ。 今回のデモボードにはGP6からGP13まで8つのLEDをつないである。これを流れるように点灯させてみよう。 ```cpp: #include "pico/stdlib.h" int main() { uint32_t cnt=1; for(int i = 6; i < 14; i++) { gpio_init(i); gpio_set_dir(i, GPIO_OUT); } while (true) { gpio_put_masked(0xff << 6, cnt<< 6); cnt=(cnt<<1) & 0xff; if(cnt == 0) cnt = 1; sleep_ms(125); } } ``` 変数```cnt```のビットが立っているところがLEDを点灯させる。1灯だけなら```gpio_put```でいいが、```gpio_put_masked```を使うと同期的に一度にセットできる。 ## インターバルタイマー 上のコードでは```sleep_ms```で点灯タイミングを決めているが、インターバルタイマーで点灯タイミングを制御する場合が以下のようになる。 ```cpp: #include "pico/stdlib.h" #include "hardware/timer.h" #include "hardware/sync.h" repeating_timer_t timer; bool repeating_timer_callback(struct repeating_timer *t) { static uint32_t cnt = 1; gpio_put_masked(0xFF << 6, cnt << 6); cnt=(cnt<<1) & 0xff; if(cnt == 0) cnt = 1; return true; } int main() { for(int i = 6; i < 14; i++) { gpio_init(i); gpio_set_dir(i, GPIO_OUT); } add_repeating_timer_us(-62500, repeating_timer_callback, NULL, &timer); while (true) __wfe(); } ``` 1. タイマーを使うために```hardware/timer.h```をインクルード 1. ```repeating_timer_t```として```timer```を用意 1. ```repeating_timer_callback```関数を書く 1. 初期化の際に```add_repeating_timer_us```を呼ぶ インターバルの値を負にすると指定時間毎の呼び出し、正にすると処理が終わってから次の呼び出しまでの時間になる。なおメインの無限ループ```while(true) __wfe();```は省電力ループであり、```while(true):```とすると普通に全力ループになる。この```__wfe();```を使うためだけに```hardware/sync.h```をインクルードしているわけで、使っても使わなくてもあまり変わらないかもしれない。 ## GPIO入力 アクティブハイのタッチスイッチをGP14に繋いで、押している時と押してない時で8連LEDが流れる方向を変えてみる。物理スイッチの場合はプルアップの必要があるが、タッチスイッチは単純にhighまたはlowを出すのでシンプルだ。 ```cpp: #include "pico/stdlib.h" int main() { uint32_t cnt=1; bool dir=false; for(int i = 6; i < 14; i++) { gpio_init(i); gpio_set_dir(i, GPIO_OUT); } gpio_init(14); gpio_set_dir(14, GPIO_IN); while (true) { dir=gpio_get(14); gpio_put_masked(0xff << 6, cnt<< 6); cnt=(dir)?(cnt<<1)&0xff:(cnt>>1)&0xff; if(cnt==0) cnt=(dir)?1:0x80; sleep_ms(125); } } ``` 物理スイッチを使ってプルアップまたはプルダウンしたい時は```gpio_pull_up```または```gpio_pull_up```を使う。ちなみにどっちでもない場合は```gpio_disable_pulls```なんだが、ちょっとわかりにくくないか? スイッチ状態を調べるには```gpio_get```を使えば良くて、```bool```を返してくるので方向```dir```に直接入れられる。 ## スイッチ割り込み なんでもかんでも割り込みにするのは良くないかもしれないが、スイッチ割り込みはよく使う方だろう。昇りエッジで正方向、降りエッジで反対方向に8連LEDが流れるようにした。ソフトウェアではスイッチの状態を一度も読んでない。物理スイッチの場合はチャタリングで酷いことになりそうだ。 ```cpp: #include "pico/stdlib.h" bool dir=false; void gpio_callback(uint gpio, uint32_t events) { if (gpio == 14) { if (events & GPIO_IRQ_EDGE_RISE) dir=true; if (events & GPIO_IRQ_EDGE_FALL) dir=false; } } int main() { uint32_t cnt=1; for(int i=6;i<14;i++) { gpio_init(i); gpio_set_dir(i, GPIO_OUT); } gpio_init(14); gpio_set_dir(14, GPIO_IN); gpio_set_irq_enabled_with_callback( 14, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback ); while (true) { gpio_put_masked(0xff << 6, cnt<< 6); cnt=(dir)?(cnt<<1)&0xff:(cnt>>1)&0xff; if(cnt==0) cnt=(dir)?1:0x80; sleep_ms(125); } } ``` 要は```gpio_callback```関数を用意して```gpio_set_irq_enabled_callback```(長い)を作法に基づいて設定してやればいいだけだ。タイマー割り込みをこれに加えてもいい。 長くなったので今回はここまで。 ---  [<前の記事](https://elchika.com/article/e00cff8c-935c-498b-824a-42d0ea55307a/) : 次の記事>