現在C言語を使用して、受信したデータから必要な部分だけを表示するプログラムを作成しております。
以前作成した、GPSからデータを受信するpg1と、必要な部分のみ表示するpg2をあわせることで、受信したデータから必要な部分を抜き出すことができました。
次の段階として、そのプログラムを指定した回数表示が行えるよう変更を試みたのですが、一度表示するとそこで終了してしまう状態から抜け出せません。どの点を改良すれば、回数を指定して表示ができるようになるのでしょうか。よろしくお願いいたします。
このときGPS端末はRS232CでPCに接続GPS端末で受信しています。
受信したNMEAと呼ばれるフォーマットのデータから時刻,緯度,経度に対応する要素を取り出して表示しようとしています。
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include<termios.h>
#include<stdio.h>
#include<math.h>
#define BAUDRATE B4800
#define MODEMDEVICE "/dev/ttyS0"
int main()
{
int fd, c, res;
int utc;
char stat;
char ns;
char ew;
char *p;
double lat;
double lon;
struct termios oldtio, newtio;
char buf[512];
FILE *fp_gps;
while(1){
if((fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY ))==-1){
perror(MODEMDEVICE);
exit(-1);
}
tcgetattr(fd, &oldtio); /*シリアルポートの設定を待避*/
bzero(&newtio, sizeof(newtio)); /*新しいポートの設定の構造体をクリア*/
newtio.c_cflag = (BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD);/*ボー:4800*/
newtio.c_iflag = (IGNPAR | ICRNL);
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
res = read(fd,buf,512);
buf[--res]=0; /* 文字列終端をセット */
if ((p=strtok(buf,","))==NULL) return;
if (strcmp(p,"$GPRMC")!=0) return; /*センテンスの先頭は$GPRMCか?*/
if ((p=strtok(NULL,","))==NULL) return; /*utc:世界標準時*/
sscanf(p,"%d",&utc);
if ((p=strtok(NULL,","))==NULL) return; /*stat:ステータス*/
stat=p[0];
if ((p=strtok(NULL,","))==NULL) return; /*lat:緯度*/
sscanf(p,"%lf",&lat);
if ((p=strtok(NULL,","))==NULL) return; /*ns:南北*/
ns=p[0];
if ((p=strtok(NULL,","))==NULL) return; /*lon:経度*/
sscanf(p,"%lf",&lon);
if ((p=strtok(NULL,","))==NULL) return; /*ew:東西*/
ew=p[0];
if (ew==p[0]){
fp_gps = fopen("gdata/gdata.dat","w");
if (fp_gps == NULL){
printf("open fp_gps err\n");
}
}
/*時刻緯度経度に対応するトークン表示*/
if (stat!='A') return; /*ステータスチェック*/
printf("%02d時%02d分%02d秒(UTC) ",utc/10000+9, (utc%10000)/100, utc%100);/*utc+9時間は日本時間における標準時*/
fprintf(fp_gps,"%02d時%02d分%02d秒(UTC) ",utc/10000+9, (utc%10000)/100, utc%100);
if (ns=='N') printf("北緯"); else if (ns=='S') printf("南緯");
printf("%.0lf度%.4lf分",floor(lat/100.0), fmod(lat,100.0));
fprintf(fp_gps,"%.0lf度%.4lf分",floor(lat/100.0), fmod(lat,100.0));
if (ew=='E') printf("東経"); else if (ns=='W') printf("西経");
printf("%.0lf度%.4lf分",floor(lon/100.0), fmod(lon,100.0));
fprintf(fp_gps,"%.0lf度%.4lf分",floor(lon/100.0), fmod(lon,100.0));
printf("\n");
}
tcsetattr(fd, TCSANOW, &oldtio); /*退避前の設定に戻す*/
fclose(fp_gps);
close(fd); /*ポートを閉じる */
}
/*実行結果
./a.out
./a.out
14時15分48秒(UTC) 北緯34度28.9393分東経136度49.4900分
*/実行結果は上記のように出力され、何も表示されないこともあります。ご指摘よろしくお願いいたします。
A 回答 (2件)
- 最新から表示
- 回答順に表示
No.2
- 回答日時:
>2行目に入ってGPRMC以外の文と判断されてしまうことで
この部分がよくわからないのですが、read関数を抜けると、
bufには$で始まるNMEAの1行が取れているんですね?
以下の部分はwhile文の外で1度だけ行えば良いと思うのですが、
なぜ毎回オープンするようにしているのでしょうか。
if((fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY ))==-1){
…
tcsetattr(fd,TCSANOW,&newtio);
while文は、
while(1) {
read();
解釈
}
でよくて、解釈部分の
if (strcmp(p,"$GPRMC")!=0) return; /*センテンスの先頭は$GPRMCか?*/
がreturnとしてしまっているので、プログラムが終了してしまっているのでしょう。
このreturnをcontinueにしましょう。
while文の先頭に戻って、次の行をreadしにいくはずです。
No.1
- 回答日時:
read直後のbufの内容をfprintfで書き出して、
文字列解析処理に入る前に、どういう文字列が入っているのかを
チェックしたほうがいいと思うよ。
何回目のreadで読めた情報、というのも合わせて書くようにして。
文字列解析処理が想定していない文字列が渡ってきてreturnして
しまっているんだと思うんですが。
この回答への補足
>hidebunさん回答ありがとうございます。
受信しているデータは$GPRMC,093514,A,3428.9468,N,13649.4907,E,0.0,196.2,180708,6.7,W,A*05
$GPRMB,A,,,,,,,,,,,,A,A*0B
$GPGGA,093514,3428.9468,N,13649.4907,E,1,07,2.1,13.2,M,35.9,M,,*7E
$GPGSA,A,3,03,06,07,,16,,21,,25,27,,,2.3,2.1,1.0*35
$GPGSV,3,1,11,03,76,315,47,06,72,017,51,07,21,318,47,13,24,282,00*7D
・・・・・
・・・・・
・・・・・と続くNMEAデータで、
hidebunさんのおっしゃるように
$GPRMC以外の文が先頭に来たり、2行目に入ってGPRMC以外の文と判断されてしまうことで、returnしてしまっているようです。
ここで扱っているNMEAデータは、$GPRMCや$GPRMBなど位置情報など12種類の情報で1セットとなっており、12種類目を受信した後にその時点での情報に更新された先頭の$GPRMCを再び受信してゆきます。
他の11種の文を無視して、この$GPRMCから指定した回数の時刻,緯度,経度を取り出して表示するには、文字列解析処理部分からreturnを除いて何らかの処理を加えればよいでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- 大学・短大 C言語線形リストの問題です 3 2022/12/22 00:45
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# Cのdoubleの浮動小数点表示について 3 2023/04/17 13:14
- C言語・C++・C# C言語で再起関数とポインタを用いて文字列反転をする方法がわかりません。 4 2023/04/29 20:32
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Enterキーを押されたら次の処理...
-
printf による16進表示について
-
空白を含んだ文字列がうまく格...
-
C言語で複数列のデータを1列の...
-
リストの作成と出力(C言語)
-
char型2つを結合し、short型に...
-
C言語のプログラムで、途中で止...
-
タイムカードのシステムを作り...
-
バイナリファイル(画像)のよみ...
-
なぜ無限ループになるかが分か...
-
矢印キーを押下してコンソール...
-
WinInetのInternetOpenUrl関数...
-
プログラミングの授業の課題です
-
10個出力で改行したいのですが...
-
2÷3などの余りについて
-
複数桁10進数の*桁目だけを抽出...
-
マイナスからプラスへ転じた時...
-
*をユーザーが入力した数字の数...
-
2の補数を計算するプログラム
-
fgetsなどのときのstdinのバッ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Enterキーを押されたら次の処理...
-
C言語で複数列のデータを1列の...
-
#defineが使用するメモリ領域に...
-
printf による16進表示について
-
空白を含んだ文字列がうまく格...
-
C言語のプログラムで、途中で止...
-
プログラミングの授業の課題です
-
char型2つを結合し、short型に...
-
C言語でのCSVファイルの読み出...
-
矢印キーを押下してコンソール...
-
【C言語】全角文字の配列を、全...
-
エラーについて質問です。
-
リストの作成と出力(C言語)
-
[C]セグメンテーションエラー:...
-
バイナリファイル(画像)のよみ...
-
WinInetのInternetOpenUrl関数...
-
受信データから必要な部分のみ...
-
c言語で文書を読み込み、単語の...
-
VC++でSQLへSELECT文を送ったの...
-
reallocでエラー
おすすめ情報