赤外線モーションセンサモジュールを使う

HC-SR501(その2)


前回は赤外線モーションセンサモジュール(HC-SR501)の簡単なテ ストを紹介 しましたが、今回はもう少し実用的(??)なプログラムとして
人の動きを検出すると一定時間LEDを点灯するプログラムを紹介します。
回路図は以下のとおりです。
基本的なボタンとLEDの回路を応用して、ボタン部分をセンサからの入力に変えただけです。
プログラムは永久ループするので、一応プログラム終了のためのボタンを付けています。
LEDの抵抗は220オーム、ボタンの抵抗は10Kオームです。
右上にあるのが赤外線モーションセンサモジュールです。
赤外線モーションセンサモジュール(HC-SR501)の出力(黄色のワイヤー)はGPIO25につないでいます。




ソースコードは以下のとおりです。

センサが人の動きを検出すると割り込みが発生し、子プロセスを起動します。
子プロセス起動前に、実行中の子プロセスの数を判定し、実行中の子プロセスが無ければ(つまり最初の子プロセスなら)LEDを点灯します。
子プロセス起動前に、実行中の子プロセスの数を判定し、実行中の子プロセスが有れば(つまりLEDが点灯中であれば)何もしません。

子プロセスが終了すると割り込みが発生します。
割り込み発生時に、実行中の子プロセスの数を判定し、実行中の子プロセスが無ければ(つまり最後の子プロセスなら)LEDを消灯します。
割り込み発生時に、実行中の子プロセスの数を判定し、実行中の子プロセスが有れば(つまりLEDが点灯中であれば)何もしません。
/*
cc -o test1 test1.c -lwiringPi
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <wiringPi.h>

// Define Senser Pin
#define SENSER  25        // rsp board pin:22

// Define LED Pin
#define LED        24      // rsp board pin:18

// Define Button Pin
#define BUTTON    23      // rsp board pin:16

// Define Timeout
#define WAITSEC    15      // タイムアウト時間

int semid;
int gpioid=0;

//排他処理開始(ロック開始)
//自分よりも先にロックされていた場合にはロック解除されるまでスリープします
void lock(int semid){
    struct sembuf sb[1];
    sb[0].sem_num=0;
    sb[0].sem_op=-1;
    sb[0].sem_flg=0;
    if(EOF==semop(semid,sb,1)){
        printf("%s\n","lock ERR");
        exit(1);
    }
}

//排他処理終了(ロック解除)
void unlock(int semid){
    struct sembuf sb[1];
    sb[0].sem_num=0;
    sb[0].sem_op=1;
    sb[0].sem_flg=0;
    if(EOF==semop(semid,sb,1)){
        printf("%s\n","unlock ERR");
        exit(1);
    }
}

//セマフォ値のセット
void SemSetValue(int semid, int semnum, int semval) {
    union semun {
        int              val;     /* SETVAL の値 */
        struct semid_ds  *buf;    /* IPC_STAT, IPC_SET 用のバッファ */
        unsigned short   *array;  /* GETALL, SETALL 用の配列 */
    } ctl_arg;

    ctl_arg.val = semval;
    if((semctl(semid,semnum,SETVAL,ctl_arg))==EOF){
        printf("%s\n","semctl ERR");
        exit(1);
    }
}

//センサーが反応したときの対応
void signal1(void){
     gpioid=1;
     unlock(semid);
}

//ボタンが押されたときの対応
void signal9(void){
     gpioid=9;
     unlock(semid);
}

int main(int argc, char **argv) {
    int endFlag=1;
    pid_t result_pid;
    int status;
    int process_count=0;

    //セマフォを割り付けます
    semid=semget(IPC_PRIVATE,1,0666);
    if(semid==EOF){
        printf("%s\n","semget ERR");
        exit(1);
    }

    //セマフォに初期値を書き込みます
    SemSetValue(semid,0,0);

    if (wiringPiSetupGpio() == -1){
        printf("wiringPiSetup init error\n");
        exit(1);
    }
    pinMode(SENSER, INPUT);
    pinMode(BUTTON, INPUT);
    pinMode(LED, OUTPUT);
    digitalWrite(LED,0);

    //割り込みを設定します
    wiringPiISR( SENSER, INT_EDGE_FALLING, signal1 );
    wiringPiISR( BUTTON, INT_EDGE_FALLING, signal9 );

    while(endFlag){
        lock(semid); // Wait Unlock
        switch (gpioid) {
            case 0: // 子プロセス終了
                process_count--;
                if (process_count == 0) digitalWrite(LED,0);
                break;
            case 1: // センサからの入力あり
                if (process_count == 0) digitalWrite(LED,1);
                process_count++;
                result_pid = fork();
                if (result_pid == 0) { // 子プロセス開始
                    sleep(WAITSEC);
                    unlock(semid);
                    exit(0);
                }
                break;
            case 9: // ボタンが押された
                endFlag=0;
                break;
            default: //
                break;
        }
        gpioid=0;
    }

    if (process_count != 0) { // 子プロセス終了待ち
        waitpid( result_pid,&status,0);
    }
    digitalWrite(LED,0);

    //セマフォの削除
    if((semctl(semid,0,IPC_RMID,0))==EOF){
        printf("%s\n","semctl ERR");
        exit(1);
    }

    exit(0);
}

次回は赤外線モーションセンサモジュールを使った家電の制御を紹介したい と思います。