ラズベリーパイ 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形式で現在位置の情報が出力されます。今回は画面に結果を出力しましたが、次回はファイルへ保存します。
実際の動作を見ると、感度も良いし実用性が高いものができそうです。
日本周遊マップ