久しぶりにRaspberryPi

訳あって久しぶりに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;
}

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)