MOOC翁凯C语言课的题目,题目如下:
GPS数据处理(6分)
题日内容:
NMEA-0183协议是为了在不同的GPS(全球定位系统)导航设备中建立统一的BTCM(海事无线电技术委员会)标准,由美国国家海洋电子协会(NMEA-The National Marine Electronics Associa-tion)制定的一套通讯协议。GPS接收机根据NMEA-0183协议的标准规范,将位置,速度等低息通过串口传送到PC机、PDA等设备。
NMEA-0183协议是GPS接收机应当遵守的标准协议,也是目前GPS接收机上使用最广泛的协议,大多数常见的GPS接收机,GPS数据处理软件,导航软件都遵守或者至少兼容这个协议。
NMEA-0183协议定义的语句非常多,但是常用的或者说兼容性最广的语句只有$GPGGA、$GPGSA、$GPGSV、$GPRMC、$GPVTG、$GPGLL等。
其中$GPRMC语句的格式如下:
$GPRMC.024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706A50
这里整条语句是一个文本行,行中以逗号,隔开各个字段,每个字段的大小(长度)不一,这里的示例只是一种可能,并不能认为字段的大小就如上述例句一样。
字段0:$GPRMC, 语句ID, 表明该请句为Recommended Minimum Specific GPS/TRANSIT Data (RMC)推荐最小定位信息
字段1 :UTC时间,hhmmss.sss格式
字段2:状态,A=定位,V=未定位
字段3:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
字段4:纬度N(北纬)或S(南纬)
字段5:经度dddmm.mmmm,度分格式(前导位数不足则补0)
字段6:经度E(东经)或W(西经)
字段7:速度,节,Knots
字段8:方位角,度
字段9:UTC日期,DDMMYY格式
字段10:磁偏角,(000-180)度(前导位数不足则补0)
字段11:磁偏角方向,E=东W=西
字段16:校验值
这里,“*”为校验和识别符,其后面的两位数为校验和,代表了“$“和“*”之间所有字符(不包括这两个字符)的异或值的十六进制值。上面这条例句的校验和是十六进制的50,也就是十进制的80。
提示:“运算符的作用是异或。将S和*之间所有的字符做^运算(第一个字符和第二个字符异或,结果再和第三个字符异或,依此类推)之后的值对65536取余后的结果,应该和*后面的两个十六进制数字的值相等,否则的话说明这条语句在传输中发生了锚误,注意这个十六进制值中是会出现 A-F的大写字母的
现在,你的程序要读入一系列GPS输出,其中包含$GPRMC,也包含其他语句。在数据的最后,有一行单独的 :
END
表示数据的结束。
你的程序要从中找出$GPRMC语句,计算校验和,找出其中校验正确,并且字段2表示已定位的语句,从中计算出时间,换算成北京时间。一次数据中会包含多条$GPRMC语句,以最后一条语句得到的北京时间作为结果输出。你的程序一定会读到一条有效的$GPRMC语句。
输入格式:
多条GPS语句,每条均以回车换行结束。最后一行是END三个大写字母
输出格式:
6位数时间,表达为:
hh:mm:ss
其中,hh是两位数的小时,不足两位时前面补0;mm是两位数的分钟,不足两位时前面补0;ss是两位数的秒,不足两位时前面补0。
输入样例:
$GPRMC,024813.640A,3158.4608,N,11848.3737,E,10.05,324.27.150706,,,A*50
END
输出样例:
10:48:13
时间限制:500ms 内存限制:32000kb
唔,看完题目可以知道其实就是要求读入多行字符串,然后找出符合条件的字符串,从中抽取六位数的UTC时间,把它转化成北京时间输出。
我想的大致思路就是:外层循环读入字符串,一直到END,然后里面把读入的单行字符串进行条件判断(先是需要$GPRMC,然后校验值要正确),遇到符合条件的字符串提取UTC时间并且转化,直到最后读到END之后再输出(因为要求只输出最后符合条件的)。
代码如下,由于我是初学者,可能很多便捷的函数我都不知道,所以如果有不妥欢迎批评指正。大部分解释都在代码注释里啦。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void copy(char *a,char *b,int start,int end);/*函数作用:把数组b中的start至end号元素copy到数组a中。(因为我对字符串函数不太了解,所以用自己写的)*/
void transform(int *h,int *m,int *s,int );/*把的6位数int的UTC时间转化成hms的北京时间*/
int main(void)
{
char ch[100]; /*放置读入的单行字符串*/
int ret,h,m,s; /*ret用来存储最后得到的六位UTC时间,hms就是结果的时分秒*/
scanf("%s",ch);
while (strcmp(ch,"END")) /*ch不等于END时进入循环体*/
{
char type[10]; /*用来储存GPS语句格式*/
copy(type,ch,0,5); /*从读取到的字符串中提取GPS语句格式*/
if (!strcmp(type,"$GPRMC") )/*type是$GPRMC时进入*/
{
int i,test; /*test用来存储读取到的字符串的异或运算值*/
test=ch[1]; /*先让它等于$后的第一个字符*/
for (i=2;ch[i]!='*';i++) /*循环计算$和*之间的字符串的异或运算值*/
{
test=test^ch[i];
}
test%=65530; /*得到读取字符串的理论校验值的十进制*/
char xtest[10]={0}; /*用来存放test的十六进制形式*/
sprintf(xtest,"%X",test); /*把test的十六进制形式放入xtest*/
char check[10]={0}; /*用于存储实际校验值*/
copy(check,ch,i+1,i+2); /*从字符串提取校验值*/
if (!strcmp(xtest,check)) /*比较理论校验值和实际校验值*/
{
char utc[10]; /*用于存储UTC时间*/
copy(utc,ch,7,12); /*从字符串提取UTC时间*/
ret=atoi(utc); /*把字符串转化为int*/
}
}
scanf("%s", ch);
}
transform(&h,&m,&s,ret); /*把六位数UTC时间转化为北京时间hms*/
printf("%02d:%02d:%02d", h, m, s); /*输出所得北京时间*/
return 0;
}
void copy(char *a,char *b,int start,int end)
{
int i;
for (i=start;i<=end;i++) /*把字符串b中的start到end号元素复制到a*/
{
*(a++)=*(b+i);
}
*a='\0'; /*数组a加上结尾的\0才是字符串*/
}
void transform(int *h,int *m,int *s,int ret)
{
ret/=1;
*s=ret%100;
ret/=100;
*m=ret%100;
*h=ret/100;
*h+=8; /*北京时间是UTC+8*/
if (*h>=24) *h-=24;
}