プロローグ
組み込みCを勉強しようとするとよく目にするvolatile。
使っていないと勝手に判断して消してしまうとはなかなか強気だな。
そういうエッジの効いた設計思想は個人的には嫌いじゃない。
回路
引き続き内部プルアップ抵抗を使ってタクトスイッチでLEDを光らせるやつを使う。
GPIO18 ── (ボタン) ── GND
3.3V ── [330Ω] ── (LED) ── GPIO17
volatileあり版
ソースコード
前回実装したトグル動作をポーリングから割込みにする。
wiringPiISR2を使うとデバウンスもやってくれるので便利。
volatileの効果を見たいがために意味なくメインループでtoggle変数を参照する。
#include <stdio.h>
#include <wiringPi.h>
#define LED_PIN_BCM 17
#define BUTTON_PIN_BCM 18
#define BOUNCETIME 20000 // microseconds
volatile int toggle;
int prev;
static void buttonIRS(struct WPIWfiStatus wfiStatus, void* userdata) {
if (toggle == 0) {
// Led on
digitalWrite(LED_PIN_BCM, LOW);
toggle = 1;
} else {
// Led off
digitalWrite(LED_PIN_BCM, HIGH);
toggle = 0;
}
}
int main(void) {
if (wiringPiSetupPinType(WPI_PIN_BCM) == -1) {
printf("setup wiringPi failed.");
return 1;
}
// pull up
pullUpDnControl(BUTTON_PIN_BCM, PUD_UP);
pinMode(LED_PIN_BCM, OUTPUT);
pinMode(BUTTON_PIN_BCM, INPUT);
digitalWrite(LED_PIN_BCM, HIGH); // Led off
wiringPiISR2(BUTTON_PIN_BCM, INT_EDGE_FALLING, &buttonIRS, BOUNCETIME, NULL);
toggle = 0;
prev = toggle;
while (1) {
if (toggle != prev) {
printf("toggle changed to %d\n", toggle);
prev = toggle;
}
}
wiringPiISRStop(BUTTON_PIN_BCM);
return 0;
}
実行
$ gcc ./button_interrupts.c -o button_interrupts -lwiringPi
$ ./button_interrupts
ボタンのON/OFFで toggle changed ... が出力される。
volatileなし版
ソースコード
toggle変数のvolatileを削除しただけ。
...
// volatile int toggle;
int toggle;
...
実行
-O2 で最適化を有効にしてビルドする。
CPUが張り付かないように念のため25秒でタイムアウトさせる。
$ gcc ./button_interrupts.c -O2 -o button_interrupts -lwiringPi
$ timeout 25 ./button_interrupts
ボタンをON/OFFしても toggle changed ... が出力されなくなった。
エピローグ
一応目的は果たせたのだが、もうちょっと実用的な使い方で確認したかったな。
まだやりたいことはあるんだけど、一回別の部品でリフレッシュしたい。
YouTuberは目指していないので動画が勝手にショートになったりならなかったりするのは一旦放っておく。
参考文献