ラズベリーパイ zero GPSロガー作成 その3 プログラム作成

2018年12月9日

それではGPSロガーのプログラミングを開始します。今回は、GPSのデータを受信して標準出力へ結果を出力するところまで作成します。プログラミング言語はC言語を使います。

以下に作成した関数を説明します。ソースファイルは次回の投稿で用意しますので、今回は全てのソースが載っていないことをご了承ください。

1.外部定義

#include <stdio.h>
#include <stdlib.h>

#include <wiringPi.h>
#include <wiringSerial.h>
#include <string.h>

#define ON 1
#define OFF 0

#define STOP_PIN	26
#define INTERRUPT_PIN	18
#define SERIAL_PORT "/dev/serial0"
#define ONE_LINE 1024

int fd ; /* ファイルポインタ */
char oneline[ONE_LINE] ;

必要なライブラリなどの定義を行います。ファイルポインタと1行のバッファ用にoneline変数を定義しています。

2.init関数

int init() {
	int i = 0 ;

	if (wiringPiSetupGpio() == -1) {
		return -1 ;
	}

	fd = serialOpen(SERIAL_PORT, 9600); 

	if (fd < 0) {
		printf("open error\n") ;
		return -1 ;
	}

	pinMode(INTERRUPT_PIN, INPUT) ;
	pullUpDnControl(INTERRUPT_PIN, PUD_UP) ;
	wiringPiISR(INTERRUPT_PIN, INT_EDGE_FALLING, get_gps_data) ;
	waitForInterrupt(INTERRUPT_PIN, 2000) ;

	pinMode(STOP_PIN, INPUT) ;
	pullUpDnControl(STOP_PIN, PUD_UP) ;

	memset(oneline, 0x00, ONE_LINE);

	return 1 ;
}

GPSのデータを読み込む前準備を行う関数です。シリアルポートをオープンして、GPIOGPSのセットアップを行っています。また、get_gps_data関数を登録して、割り込みで呼び出すようにしています。

3.main関数

int main(void) {

	if (init() == -1) {
		return 1 ;
	}


	while(digitalRead(STOP_PIN) != 0) {
 
	}

	serialClose(fd) ;

	return 1 ;
}

init関数を呼び出して、初期化を行います。

そして、GPIO26番から終了信号が送られるまで、GPSデータの受信を続けます。前のハードウェア作成の投稿では26番にスイッチを付けていないので、終了メッセージは現状では送れません。次回投稿で26番終了スイッチを付けたいと思います。

4.get_gps_data関数

void get_gps_data() {
        char buff[1024] ;
        int read_length ;
        int onelinepointer ;

        onelinepointer = strlen(oneline) ;

        read_length = serialDataAvail(fd) ;

        /*  受信データをバッファに入れる */
        for (int i=0;i<read_length;i++) {
		if (onelinepointer >= ONE_LINE) {
		    memset(oneline, 0x00, ONE_LINE) ;
	            onelinepointer = 0 ;
                    continue ;
		}
	        oneline[onelinepointer] = serialGetchar(fd) ;
	        if (oneline[onelinepointer] == 0x0a) { 
		    // printf("%s", oneline) ;
	            potwrite() ;
		    memset(oneline, 0x00, ONE_LINE) ;
	            onelinepointer = 0 ;
	        } else {
		    onelinepointer++ ;
		}
        }
}

GPSのデータを受信する関数です。今回のプログラムは1PPSを利用して1秒ごとに割り込みを発生させてget_gps_data関数を呼び出すようにしています。

get_gps_data関数で読み込まれるデータは、NMEA-0183というテキスト形式です。NMEA-0183のデータは1行毎に取れるわけではなく、1行の途中で切れた状態で取得するので、前回の余りをバッファに残しておいて、次回の受信バッファの先頭に加えるなどの処理をしています。

1行が完成するごとに、potwrite関数を呼び出します。

5.potwrite関数

void potwrite() {
	char ido[128] ;
	char keido[128] ;
	char potbuff[1024] ;

	// GPGGA ONLY
	if (strncmp(oneline, "$GPGGA", 6) == 0) {
		// printf("GPGGA receive !!\n") ;
		MySplit(ido, keido) ;

		sprintf(potbuff, "ORD=POI/tex=test/ido=%s/kei=%s/alt=-0/pda=/pti=", ido, keido) ;
		printf("%s\n", potbuff) ;

	}

}

読み込んだデータの中の$GPGGAの行を使って緯度経度を取得します。緯度経度の取得は、MySplit関数で行います。

緯度経度が取得できたら、POT形式のフォーマットで標準出力します。今回は緯度経度のみの情報ですが、高度時間などの情報を追加するのが本来の形です。これは、みなさんで自由に追加してみてください。

6.MySplit関数

void MySplit(char *ido, char *keido)

ソースが長いので割愛させていただきました。緯度経度のポインタを受けて、緯度経度の文字列を設定しています。NMEA-0183緯度・経度数値ルールは特殊なので、編集がやや面倒です。

7.実行してみる

画面にPOT形式で現在位置の情報が出力されます。今回は画面に結果を出力しましたが、次回はファイルへ保存します。

実際の動作を見ると、感度も良いし実用性が高いものができそうです。