akira.keiのアイコン画像
akira.kei 2026年09月25日作成 (2026年09月25日更新) © MIT
セットアップや使用方法 セットアップや使用方法 Lチカ Lチカ 閲覧数 16
akira.kei 2026年09月25日作成 (2026年09月25日更新) © MIT セットアップや使用方法 セットアップや使用方法 Lチカ Lチカ 閲覧数 16

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

<前の記事 : 次の記事>

GPIO出力

GPIO出力のわかりやすい例はpico-exampleのblinkではなくblink-simpleだ。LEDをチカっとさせるだけなのにちょっと冗長な書き方ではあるが、初期化して出力を決めて1か0を出力するだけだ。

今回のデモボードにはGP6からGP13まで8つのLEDをつないである。これを流れるように点灯させてみよう。

#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で点灯タイミングを決めているが、インターバルタイマーで点灯タイミングを制御する場合が以下のようになる。

#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をインクルード
  2. repeating_timer_tとしてtimerを用意
  3. repeating_timer_callback関数を書く
  4. 初期化の際にadd_repeating_timer_usを呼ぶ

インターバルの値を負にすると指定時間毎の呼び出し、正にすると処理が終わってから次の呼び出しまでの時間になる。なおメインの無限ループwhile(true) __wfe();は省電力ループであり、while(true):とすると普通に全力ループになる。この__wfe();を使うためだけにhardware/sync.hをインクルードしているわけで、使っても使わなくてもあまり変わらないかもしれない。

GPIO入力

アクティブハイのタッチスイッチをGP14に繋いで、押している時と押してない時で8連LEDが流れる方向を変えてみる。物理スイッチの場合はプルアップの必要があるが、タッチスイッチは単純にhighまたはlowを出すのでシンプルだ。

#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が流れるようにした。ソフトウェアではスイッチの状態を一度も読んでない。物理スイッチの場合はチャタリングで酷いことになりそうだ。

#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(長い)を作法に基づいて設定してやればいいだけだ。タイマー割り込みをこれに加えてもいい。

長くなったので今回はここまで。


<前の記事 : 次の記事>

akira.keiのアイコン画像
機械系エンジニアだが電子工作を趣味としている。週末はひとりバーベキュー。
ログインしてコメントを投稿する