タイマー割り込みの作り方(タイマーとボタンの両方で割り込む)


前回の拡張でタイマー割り込みとボタン入力を同時に受け付けるサンプルを示します。
ソースは以下のとおりです。

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <wiringPi.h>

// Define Button Pin
#define button1 14      // rsp board pin:8
#define button2 15      // rsp board pin:10

#define DEBUG 0

int semid;
int gpioid=0;
int inProc;

//排他処理の開始するためのロック
//自分よりも先にロックされていた場合にはロック解除されるまでスリープします
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);
    }
}
//ボタン1が押されたときの対応
void signal1(void){
     if(inProc == 0) {
     gpioid=1;
     unlock(semid);
     }
}
//ボタン2が押されたときの対応
void signal2(void){
     if(inProc == 0) {
     gpioid=2;
     unlock(semid);
     }
}

int main(int argc, char **argv) {
    int EndFlag=1;
    pid_t result_pid1;
    pid_t result_pid2;
    int kill_status;
    int wait_status;
    time_t now;
    struct tm *pnow;
    int sem_value1=0;
    int sem_value2=0;

    //セマフォを割り付けます
    semid=semget(IPC_PRIVATE,3,0666);
    if(semid==EOF){
        printf("%s\n","semget ERR");
        exit(1);
    }
    //セマフォに初期値を書き込みます
    SemSetValue(semid,0,1);

    result_pid1 = fork();
    if (result_pid1 == 0) {
    // 子プロセス1開始 //
    // 1秒毎にセマフォをunlockする
        while (1) {
            sleep(1);
            SemSetValue(semid,1,1);
            unlock(semid);
        }
    }

    result_pid2 = fork();
    if (result_pid2 == 0) {
    // 子プロセス2開始 //
    // 5秒毎にセマフォをunlockする
        while (1) {
            sleep(5);
            SemSetValue(semid,2,1);
            unlock(semid);
        }
    }

    if (wiringPiSetupGpio() == -1){
        printf("wiringPiSetup init error\n");
        exit(1);
    }

    if(button1) pinMode(button1, INPUT);
    if(button2) pinMode(button2, INPUT);
    if(button1) pullUpDnControl(button1, PUD_DOWN);
    if(button2) pullUpDnControl(button2, PUD_DOWN);
    if(button1) wiringPiISR( button1, INT_EDGE_FALLING, signal1 );
    if(button2) wiringPiISR( button2, INT_EDGE_FALLING, signal2 );

    while(EndFlag){
        inProc=0;
        lock(semid); // Wait Unlock
        inProc=1;
        switch (gpioid) {
            case 0: // 子プロセスのタイムアウト
                sem_value1 = semctl(semid, 1, GETVAL, 0);
                sem_value2 = semctl(semid, 2, GETVAL, 0);
                if(sem_value1 == 1) {
                    now = time(NULL);
                    pnow = localtime(&now);
                    printf("%02d:%02d:%02d\n",pnow->tm_hour,pnow->tm_min,pnow->tm_sec);
                    SemSetValue(semid,1,0);
                }
                if(sem_value2 == 1) {
                    now = time(NULL);
                    pnow = localtime(&now);
                    printf("%s",asctime(pnow));
                    SemSetValue(semid,2,0);
                }
                break;
            case 1: // ボタン1が押された
                printf("Button %d Push!!\n",gpioid);
                break;
            case 2: // ボタン2が押された
                printf("Button %d Push!!\n",gpioid);
                EndFlag=0;
                break;
            default:
                break;
        }
        gpioid=0;
    }

    //子プロセスをKILL
    kill_status = kill( result_pid1, SIGKILL );
    wait(&wait_status);

    kill_status = kill( result_pid2, SIGKILL );
    wait(&wait_status);

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

    exit(0);
}

リンク方法は以下となります。
$ cc -o Sample4 Sample4.c -lwiringPi -lwiringPiDev

実行結果を以下に示します。
1秒毎と5秒毎に2つの割り込みが発生し現在時刻を表示します。
さらにボタン1、ボタン2の入力も受け付けています。
$ sudo ./Sample4
11:17:29
11:17:30
11:17:31
11:17:32
Sun Aug 10 11:17:33 2014
11:17:33
11:17:34
11:17:35
11:17:36
11:17:37
Sun Aug 10 11:17:38 2014
11:17:38
11:17:39
11:17:40
Button 1 Push!! → ボタン1が押された
11:17:41
11:17:42
Sun Aug 10 11:17:43 2014
11:17:43
11:17:44
11:17:45
Button 2 Push!! → ボタン2が押された
$

完成!!