上两篇博文整理学习了有关串口通信、串口编程以及GPS数据格式的一些基本知识。本篇我们要开始编程实现GPS自动定位数据解析。我们将在FL2440开发板上实现该功能。
由于SF2820模块获取到的GPS定位信息是通过串口发送到终端设备,我们在编程实现获取GPS定位信息中自然涉及到串口编程。
串口编程
前面博文已经介绍的很详细,代码也参考前面串口模块。只需要串口模块的头文件与源码。
串口设置其实就相当于串口通信的协议,我们通过程序设置下面的内容(这些值的设置见main函数)
波特率:是为了两者信号流能同步,
数据位:是指又几位数据封装成一帧
结束位:是指以帧传输数据时,协定好结束位,便于提取有效数据
奇偶校验:检验数据的一种手段
编程获取和解析GPS定位信息
头文件(gps.h)
/********************************************************************************
* Copyright: (C) 2018 NULL
* All rights reserved.
*
* Filename: gps.h
* Description: This head file
*
* Version: 1.0.0(2018年07月31日)
* Author: DingHuanhuan <[email protected]>
* ChangeLog: 1, Release initial version on "2018年07月31日 14时13分55秒"
*
********************************************************************************/
#ifndef _GPS_H
#define _GPS_H
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
typedef struct _GP_RMC
{
unsigned int Time; /*UTC Time :hhmmss */
char Pos_status; //定位状态
float latitude; //纬度
char lati_hemisphere; //纬度半球
float longitude; //经度
char longi_hemisphere; //经度半球
float speed; //移动速度
float direction; //方向
unsigned int data; //日期
float Magnetic_declination; //磁偏角
char M_dd; //磁偏角方向
char mode; //模式
}GPRMC;
int Analyse_GPRMC(char *buff, GPRMC *gprmc_data);
int Print_GPRMC(GPRMC *gprmc_data);
#endif
gps数据分析gps.c
在gps.c文件中有两个函数Analyse_GPRMC 和 Print_GPRMC ,分别实现对gps返回的数据进行分析处理和打印到标准输出。
/*********************************************************************************
* Copyright: (C) 2018 NULL
* All rights reserved.
*
* Filename: gps.c
* Description: This file
*
* Version: 1.0.0(2018年07月31日)
* Author: DingHuanhuan <[email protected]>
* ChangeLog: 1, Release initial version on "2018年07月31日 14时37分56秒"
*
********************************************************************************/
#include "gps.h"
int Analyse_GPRMC(char *buff, GPRMC *gprmc_data)
{
char *ptr = NULL;
if(NULL == gprmc_data)
return -1;
if(strlen(buff) < 10)
return -2;
ptr = strstr(buff,"$GPRMC");
if(NULL == ptr)
return -3;
/* Assign values to structures */
sscanf(ptr, "$GPRMC,%d.000,%c,%f,%c,%f,%c,%f,%f,%d,,,%c*",&(gprmc_data->Time),&(gprmc_data->Pos_status),&(gprmc_data->latitude),&(gprmc_data->lati_hemisphere),&(gprmc_data->longitude),&(gprmc_data->longi_hemisphere),&(gprmc_data->speed),&(gprmc_data->direction),&(gprmc_data->data),&(gprmc_data->mode));
printf("DATA analyse is ok!\n");
printf("ptr:%s\n",ptr);
return 0;
}
int Print_GPRMC(GPRMC *gprmc_data)
{
printf(" \n");
printf(" \n");
printf(" \n");
printf("=======================================================\n");
printf("=======================================================\n");
printf("**** Global GPS positioning module ****\n");
printf("**** Author:dinghuanhuan ****\n");
printf("**** E_mail:[email protected] ****\n");
printf("**** GPS model:FIT-GPS-SF2820 ****\n");
printf("**** MCU model:FL2440 ****\n");
printf("=======================================================\n");
printf("=======================================================\n");
printf("**** 定位状态:%c [A有效定位;V无效定位] ****\n",gprmc_data->Pos_status);
printf("**** 模式指示: %c [A自主定位;D差分定位] ****\n",gprmc_data->mode);
printf("**** UTC日期: 20%02d-%02d-%02d ****\n",gprmc_data->data%100,
(gprmc_data->data%10000)/100,(gprmc_data->data/10000));
printf("**** UTC时间: %02d:%02d:%02d ****\n", (gprmc_data->Time/10000+8)%24,
(gprmc_data->Time%10000)/100,(gprmc_data->Time%100));
printf("**** 维度: %c维 %d度%d分%d秒 ****\n",
gprmc_data->lati_hemisphere, ((int)gprmc_data->latitude)/100,
(int)(gprmc_data->latitude - ((int)gprmc_data->latitude / 100 * 100)),
(int)(((gprmc_data->latitude - ((int)gprmc_data->latitude / 100 * 100))
- ((int)gprmc_data->latitude - ((int)gprmc_data->latitude / 100 * 100)))*60.0));
printf("**** 经度: %c经 %d度%d分%d秒 ****\n",
gprmc_data->longi_hemisphere,((int)gprmc_data->longitude)/100,
(int)(gprmc_data->longitude - ((int)gprmc_data->longitude / 100 * 100)),
(int)(((gprmc_data->longitude - ((int)gprmc_data->longitude / 100 * 100))
- ((int)gprmc_data->longitude - ((int)gprmc_data->longitude / 100 * 100)))*60.0));
printf("**** 地面速度:%.5f m/s ****\n",gprmc_data->speed);
printf(" \n");
printf("=======================================================\n");
printf("=======================================================\n");
return 0;
}
对于字段的分析,在上篇博文已经解读,不过我们要把数据转化一下,方便我们记录和识别。
1. 时间,这个是格林威治时间即世界时间(UTC),把它转换成我们用的北京时间(BTC),在这个时间基础上加8个小时。
2. 经纬度,GPRMC返回的纬度数据位ddmm.mmmm格式即度分格式,我们把它转换成常见的度分秒的格式,计算方法:如接收到的纬度是:3029.60430
3029.60430/100=30.2960430可以直接读出30度, 3029.60430–30*100=29.60430, 可以直接读出29分
(29.60430–29)*60 =0.60430*60=36.258读出36秒, 所以纬度是:30度29分36秒。
3. 南北纬东西经,N:北纬。S:南纬。E:东经。W:西经。
4. 速率,GPRMC返回的速率值是海里/时,单位是节,把它转换成千米/时,换算为:1海里=1.85公里,把得到的速率乘以1.85。
5. 航向,指的是偏离正北的角度
6. 日期,GPRMC的日期格式为:ddmmyy,如:040617表示2017年06月04日,这个日期是准确的,不需要转换。
main函数
/*********************************************************************************
* Copyright: (C) 2018 NULL
* All rights reserved.
*
* Filename: main.c
* Description: This file
*
* Version: 1.0.0(2018年07月31日)
* Author: DingHuanhuan <[email protected]>
* ChangeLog: 1, Release initial version on "2018年07月31日 14时10分09秒"
*
********************************************************************************/
#include "comport.h"
#include "gps.h"
int main(int argc,char **argv)
{
char *devname = "/dev/ttyS1";
unsigned long baudrate = 4800;
COM_PORT *comport;
GPRMC gprmc_data;
char buff[buff_size];
int read_fd = 0;
comport = Comport_Init(devname, baudrate, "8N1");
if(NULL == comport)
{
printf("init serial port failure\n");
return -1;
}
Comport_open(comport);
if(comport->fd <0)
{
printf("open error :%s\n",strerror(errno));
exit(1);
}
printf("OPEN THE DEVICE\n");
while(1)
{
sleep(3);
read_fd = read(comport->fd,buff,sizeof(buff));
if(read_fd < 0)
{
printf("read GPRMC data error\n");
return -2;
}
printf("gps_buff: %s\n",buff);
memset(&gprmc_data,0,sizeof(gprmc_data));
Analyse_GPRMC(buff,&gprmc_data);
Print_GPRMC(&gprmc_data);
}
close(comport->fd);
free(comport);
return 0;
}
接下来用Makefile编译
#This Makefile used to call function to compile all the C source in current folder and links all the objects file into a excutable binary file.
PWD=$(shell pwd)
prom = comport
CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux-
export CC=${CROSS_COMPILE}gcc
export CXX=${CROSS_COMPILE}g++
export AR=${CROSS_COMPILE}ar
export AS=${CROSS_COMPILE}as
export RANLIB=${CROSS_COMPILE}ranlib
export STRIP=${CROSS_COMPILE}strip
VPATH= .
SRCS = $(wildcard ${VPATH}/*.c)
DEPS = $(shell find ${VPATH}/*.h)
OBJS = $(patsubst %.c,%.o,$(SRCS))
$(prom): $(OBJS)
@$(CC) -o $(prom) $(OBJS)
@rm -rf *.o
clean:
@rm -rf *.o
将编译生成的comport下载到开发板,(给其运行权限)运行测试