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

Raspberry Pi PicoをSDKで(その3):ADCやり直し

<前の記事 : 次の記事>
ショート動画は埋め込めないのか。。。

サンプリング周期一定のADC

前の記事では8連LEDの点灯制御をメインループで、タッチスイッチの監視を割り込みで処理していた。これに加えADCも一定サンプリング周期で読み込んでLEDが流れる速度を変更してみる。ついでにLEDのタイミング制御もタイマーにしておいたので、二つのインターバルタイマーを使うことになる。

#include "pico/stdlib.h" #include "hardware/timer.h" #include "hardware/adc.h"

インクルードはいつも必須のpico/stdlib.hの他に、ハードウェア固有のhardware/timer.hとhardware/adc.hだ。高機能SDKというかAPIの場合、こういう作法を覚えるのが一苦労だ。PICのような低機能APIだと自分で書く羽目になるわけだからあまり差がないかもしれないけど。

スイッチ割り込み

前の記事と同じように、スイッチの昇りエッジと降りエッジの両方で割り込めるようにしてある。割り込みGPIOの14番は何度も出てくるので#defineで定義すべきかも。

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; } }

インターバルタイマー

用意するインターバルタイマーはrepeating_timerとrepeating_timer_adcだ。このrepeating_timerの方は前の記事と同じになっていて、bool dirの値に従って右シフトか左シフトかを切り替えている。

repeating_timer_t timer,adc_timer; bool repeating_timer_callback(struct repeating_timer *t) { static uint32_t cnt = 1; gpio_put_masked(0xff << 6, cnt<< 6); cnt=(dir)?(cnt<<1)&0xff:(cnt>>1)&0xff; if(cnt==0) cnt=(dir)?1:0x80; return true; }

ADCの方のタイマーは以下のように、LED点灯制御の流れる速度を決めている。処理性能に余裕があるので変数を気兼ねなくfloatに設定できる。ADCの値と速度の関係はリニアになっているが指数的とか対数的じゃないと自然な速度変更にならないようだ。ゆっくりの場合はボリュームをまわしてもいつまでもゆっくりで、急に速度が速くなる。

float result=0; float result_prev=0; float mint=25.0f; float maxt=250.0f; bool repeating_timeradc_callback(struct repeating_timer *t) { result_prev=result; result = (float)(127-(adc_read()>>5)); if(result!=result_prev) { float msval=mint+(maxt-mint)*result/127.0f; cancel_repeating_timer(&timer); add_repeating_timer_ms((int)-msval, repeating_timer_callback, NULL, &timer); } return true; }

初期化

ピン関連の初期化ルーチンは別途settup関数にまとめてみた。Arduino等でよくある形である。ADCを使うためにはadc_init、adc_gpio_initおよびadc_select_inputの3行が必要なところはちょっと長すぎないか。

void setup(void) { 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); adc_init(); adc_gpio_init(26); adc_select_input(0); }

メイン関数

メインはやはり前の記事とほとんど同じだが、ADCのタイマーの呼び出し(割り込み登録)の部分が異なる。ループ部分はwhile(true);の無限ループだが中身が空っぽなので、もしかしたら__wfe();を使う方がいいかもしれない。

int main() { setup(); gpio_set_irq_enabled_with_callback( 14, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback ); add_repeating_timer_ms(125, repeating_timer_callback, NULL, &timer); add_repeating_timer_ms(250, repeating_timeradc_callback, NULL, &adc_timer); while (true) ; }
akira.keiのアイコン画像
機械系エンジニアだが電子工作を趣味としている。週末はひとりバーベキュー。
ログインしてコメントを投稿する