ラズベリーパイ zero GPSロガー作成 その3 プログラム作成
それでは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のデータを読み込む前準備を行う関数です。シリアルポートをオープンして、GPIOやGPSのセットアップを行っています。また、get_gps_data関数を登録して、割り込みで呼び出すようにしています。
3.main関数
int main(void) { if (init() == -1) { return 1 ; } while(digitalRead(STOP_PIN) != 0) { } serialClose(fd) ; return 1 ; }
init関数を呼び出して、初期化を行います。
そして、GPIOの26番から終了信号が送られるまで、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形式で現在位置の情報が出力されます。今回は画面に結果を出力しましたが、次回はファイルへ保存します。
実際の動作を見ると、感度も良いし実用性が高いものができそうです。