趣味の電子工作などの記録。時にLinuxへ行ったり、ガジェットに浮気したりするので、なかなかまとまらない。
RSS icon
  • 久しぶりにRaspberryPi

    投稿日 2014年 8月 24日 コメントはありません

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

     


    コメントをどうぞ(日本語のみ/Only in Japanese)

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