訳あって久しぶりにRaspberryPiを触っています。しっかし、日々いろんな事が起きるせいか、忘れていることだらけです。
今回はGPIOを使ってちょっとしたシーケンスを組んでいます。はっきりいって、Arduinoの方が簡単にできるんですが、PCなしでプログラムを変更しないといけない環境なので、セルフコンパイルが可能なRaspberryPiに白羽の矢が立ちました。
で、以前の自分の記事を元に、いろいろやってみたのですが、スマートになりません。そこで、再びググってみると、いろいろ便利になっているようです。
簡単そうなのは、「C library for Broadcom BCM 2835 as used in Raspberry Pi」を使うことです。リンク先の記述に沿って、ダウンロード&インストールしました。
インストールが完了すると、こちらの記事で紹介されているような簡単な記述でGPIOが扱えます。(ちなみにリンク先では他の言語でのI/O制御も紹介されています)
#include <stdio.h> #include <stdlib.h> #include <bcm2835.h> #include <signal.h> // Rpi P1ヘッダの26ピン(GPIO 7)をPINと定義する #define PIN RPI_V2_GPIO_P1_26 // 割り込みコールバック関数 void signal_callback_handler(int signum) { printf("\ndetect key interrupt\n",signum); bcm2835_close(); printf("Program exit\n"); exit(0); } int main(int argc, char **argv) { if (!bcm2835_init()) return 1; bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP); signal(SIGINT, signal_callback_handler); printf("press ^C to exit program ...\n"); while (1) { bcm2835_gpio_write(PIN, HIGH); delay(500); // 0.5秒待つ bcm2835_gpio_write(PIN, LOW); delay(500); // 0.5秒待つ } }
こんな感じで26ピンに接続したLEDが点滅します。(リンク先との差はGPIOの端子だけです)
コンパイル&実行の方法は下記。
$ gcc blink_led.c -o blink_led -l rt -l bcm2835 $ sudo ./blink_led
次にポート入力の方法は以下のような感じ。
#include <stdio.h> #include <stdlib.h> #include <bcm2835.h> #include <signal.h> // Rpi P1ヘッダの24ピン(GPIO 8)をPINと定義する #define PIN RPI_V2_GPIO_P1_24 // 割り込みコールバック関数 void signal_callback_handler(int signum) { printf("\ndetect key interrupt\n",signum); bcm2835_close(); printf("Program exit\n"); exit(0); } int main(int argc, char **argv) { if (!bcm2835_init()) return 1; bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_INPT); // VCCまでプルアップする bcm2835_gpio_set_pud(PIN, BCM2835_GPIO_PUD_UP); signal(SIGINT, signal_callback_handler); printf("press ^C to exit program ...\n"); while (1) { uint8_t value = bcm2835_gpio_lev(PIN); printf("read from pin 24: %d\n", value); delay(500); // 0.5秒待つ } }
これだけじゃ芸がないので、HRTとSCHEDULERをいじってみます。
まず、LED点滅はこんな感じ。0.5秒周期の点滅にHRTを使ってます。
#include <stdio.h> #include <stdlib.h> #include <bcm2835.h> #include <signal.h> // Rpi P1ヘッダの26ピン(GPIO 7)をPINと定義する #define PIN RPI_V2_GPIO_P1_26 // 割り込みコールバック関数 void signal_callback_handler(int signum) { printf("\ndetect key interrupt\n",signum); bcm2835_close(); printf("Program exit\n"); exit(0); } /////////////////////////// // HRTを使ったポート入力 // #include <sched.h> #include <time.h> static struct timespec hrt_now; static struct timespec hrt_next; void test(long tick) { int v=1; // HRT処理 clock_gettime(CLOCK_MONOTONIC, &hrt_now); while(1){ hrt_next.tv_nsec = hrt_now.tv_nsec + tick; if(hrt_next.tv_nsec >= 1000000000){ hrt_next.tv_nsec -= 1000000000; hrt_next.tv_sec = hrt_now.tv_sec + 1; } else { hrt_next.tv_sec = hrt_now.tv_sec; } clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &hrt_next, NULL); hrt_now = hrt_next; // 周期処理 { if(v){ bcm2835_gpio_write(PIN, HIGH); } else { bcm2835_gpio_write(PIN, LOW); } v=1-v; } } } int main(int argc, char **argv) { if (!bcm2835_init()) return 1; bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP); signal(SIGINT, signal_callback_handler); printf("press ^C to exit program ...\n"); test(500000000); return EXIT_SUCCESS; }
次に、ポート入力はこんな感じ。
#include <stdio.h> #include <stdlib.h> #include <bcm2835.h> #include <signal.h> // Rpi P1ヘッダの24ピン(GPIO 8)をPINと定義する #define PIN RPI_V2_GPIO_P1_24 // 割り込みコールバック関数 void signal_callback_handler(int signum) { printf("\ndetect key interrupt\n",signum); bcm2835_close(); printf("Program exit\n"); exit(0); } /////////////////////////// // HRTを使ったポート入力 // #include <sched.h> #include <time.h> static struct timespec hrt_now; static struct timespec hrt_next; void test(long tick) { // HRT処理 clock_gettime(CLOCK_MONOTONIC, &hrt_now); while(1){ hrt_next.tv_nsec = hrt_now.tv_nsec + tick; if(hrt_next.tv_nsec >= 1000000000){ hrt_next.tv_nsec -= 1000000000; hrt_next.tv_sec = hrt_now.tv_sec + 1; } else { hrt_next.tv_sec = hrt_now.tv_sec; } clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &hrt_next, NULL); hrt_now = hrt_next; // 周期処理 { uint8_t value = bcm2835_gpio_lev(PIN); printf("read from pin 24: %d\n", value); } } } int main(int argc, char *argv[]) { int MinPriority; int MaxPriority; struct sched_param prio; // SCHED_FIFOポリシーの優先度の最大値/最小値を得る MinPriority=sched_get_priority_min(SCHED_FIFO); printf("Min priority for FIFO policy is %d\n",MinPriority); MaxPriority=sched_get_priority_max(SCHED_FIFO); printf("Max priority for FIFO policy is %d\n",MaxPriority); // スケジューリングポリシーと優先度最大を設定する prio.sched_priority = MaxPriority; if(sched_setscheduler(0,SCHED_FIFO,&prio)<0){ perror("Schedule set error\n"); exit(0); } if (!bcm2835_init()) return 1; bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_INPT); // VCCまでプルアップする bcm2835_gpio_set_pud(PIN, BCM2835_GPIO_PUD_UP); // CTRL-C 押下時の処理 signal(SIGINT, signal_callback_handler); printf("press ^C to exit program ...\n"); test(500000000); return EXIT_SUCCESS; }