获得GPS数据的两种方法 1读串口 - [技术]

版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://memset.blogbus.com/logs/17801310.html

获得GPS数据一般可通过两种方法,读串口及调用gpsapi函数。串口作为硬件设备,不能同时被两个程序占用,gpsapi函数几个应用程序可同时共享端口。

1.读串口

先找出gps使用的串口号,然后直接打开串口,读取串口数据了 串口通信api函数:1. 用途:打开串口

   原型:HANDLE CreateFile(LPCTSTR lpFileName,

  DWORD dwDesiredAccess,

  DWORD dwShareMode,

  LPSECURITY_ATTRIBUTES lpSecurityAttributes

DWORD dwCreationDistribution,

  DWORD dwFlagsAndAttributes,

  HANDLE hTemplateFile);
  参数说明:

  -lpFileName:要打开的文件名称。对串口通信来说就是COM1或COM2。

  -dwDesiredAccess:读写模式设置。此处应该用GENERIC_READ及GENERIC_WRITE。

  -dwShareMode:串口共享模式。此处不允许其他应用程序共享,应为0。

  -lpSecurityAttributes:串口的安全属性,应为0,表示该串口不可被子程序继承。

  -dwCreationDistribution:创建文件的性质,此处为OPEN_EXISTING.

  -dwFlagsAndAttributes:属性及相关标志,这里使用异步方式应该用FILE_FLAG_OVERLAPPED。

  -hTemplateFile:此处为0。

  操作说明:若文件打开成功,串口即可使用了,该函数返回串口的句柄,以后对串口操作时即可使用该句柄。

   举例:HANDLE hComm;

  hComm=CreateFile("COM1", //串口号

  GENERIC_READ|GENERIC_WRITE, //允许读写0, //通讯设备必须以独占方式打开

  NULL, //无安全属性

  OPEN_EXISTING, //通讯设备已存在FILE_FLAG_OVERLAPPED, //异步I/O 0); //通讯设备不能用模板打开hComm即为函数返回的串口1的句柄。
2 . CloseHandle()

  用途:关闭串口

   原型:BOOL CloseHandle(HANDLE hObjedt)
  参数说明:

  -hObjedt:串口句柄

  操作说明:成功关闭串口时返回true,否则返回false

   举例:CloseHandle(hComm);
3. GetCommState()

  用途:取得串口当前状态

   原型:BOOL GetCommState(HANDLE hFile,LPDCB lpDCB);
  参数说明:

  -hFile:串口句柄

  -lpDCB:设备控制块(Device Control Block)结构地址。此结构中含有和设备相关的参数。此处是与串口相关的参数。由于参数非常多,当需要设置串口参数 时,通常是先取得串口的参数结构,修改部分参数后再将参数结构写入。

  在此仅介绍少数的几个常用的参数:

  DWORD BaudRate:串口波特率

  DWORD fParity:为1的话激活奇偶校验检查

  DWORD Parity:校验方式,值0~4分别对应无校验、奇校验、偶校验、校验置位、校验清零

  DWORD ByteSize:一个字节的数据位个数,范围是5~8

  DWORD StopBits:停止位个数,0~2分别对应1位、1.5位、2位停止位操作举例:DCB ComDCB; //串口设备控制块

   GetCommState(hComm,&ComDCB);
4. SetCommState()

  用途:设置串口状态,包括常用的更改串口号、波特率、奇偶校验方式、数据位数等原型:BOOL SetCommState(HANDLE hFile,LPDCB lpDCB);
  参数说明:

  -hFile:串口句柄

  -lpDCB:设备控制块(Device Control Block)结构地址。要更改的串口参数包含在此结构中。  
 操作举例:DCB ComDCB;

  GetCommState(hComm,&ComDCB);//取得当前串口状态ComDCB.BaudRate=9600;//更改为9600bps,该值即为你要修改后的波特率

  SetCommState(hComm,&ComDCB;//将更改后的参数写入串口
5. WriteFile()

  用途:向串口写数据

   原型:BOOL WriteFile(HANDLE hFile,

  LPCVOID lpBuffer,

  DWORD nNumberOfBytesToWrite,

  LPDWORD lpNumberOfBytesWritten,

  LPOVERLAPPED lpOverlapped);
  参数说明:

  -hFile:串口句柄

  -lpBuffer:待写入数据的首地址

  -nNumberOfBytesToWrite:待写入数据的字节数长度

  -lpNumberOfBytesWritten:函数返回的实际写入串口的数据个数的地址,利用此变量可判断实际写入的字节数和准备写入的字节数是否相同。

  -lpOverlapped:重叠I/O结构的指针  操作举例:DWORD BytesSent=0;

  unsigned char SendBytes[5]={1,2,3,4,5};

  OVERLAPPED ov_Write;

  ov_Write.Offset=0;

  ov_Write.OffsetHigh=0;

  WriteFile(hComm, //调用成功返回非零,失败返回零

  SendBytes, //输出缓冲区

  5, //准备发送的字符长度

  &BytesSent, //实际发出的字符数

  &ov_Write); //重叠结构
  如果函数执行成功的话检查BytesSent的值应该为5,此函数是WriteFile函数执行完毕后自行填充的,利用此变量的填充值可以用来检查该函数是否将所有的数据成功写入串口

6. ReadFile()

  用途:读串口数据  原型:BOOL ReadFile(HANDLE hFile,

  LPVOID lpBuffer,

  DWORD nNumberOfBytesToRead,

  lpNumberOfBytesRead,

  lpOverlapped);  参数说明:

  -hFile:串口句柄

  -lpBuffer:存储被读出数据的首地址

  -nNumberOfBytesToRead:准备读出的字节个数

  -NumberOfBytesRead:实际读出的字节个数

  -lpOverlapped:异步I/O结构,  操作举例:unsigned char ucRxBuff[20];

  COMSTAT ComStat;

  DWORD dwError=0;

DWORD BytesRead=0;

  OVERLAPPED ov_Read;

  ov_Read.hEvent=CreateEvent(NULL, true, false, NULL);//必须创建有效事件

  ClearCommError(hComm,&dwError,&ComStat);//检查串口接收缓冲区中的数据个数

  bResult=ReadFile(hComm, //串口句柄

  ucRxBuff, //输入缓冲区地址

  ComStat.cbInQue, //想读入的字符数

  &BytesRead, //实际读出的字节数的变量指针

  &ov_Read); //重叠结构指针
  假如当前串口中有5个字节数据的话,那么执行完ClearCommError()函数后,ComStat

  结构中的ComStat.cbInQue将被填充为5,此值在ReadFile函数中可被直接利用。

7. ClearCommError()

  用途:清除串口错误或者读取串口现在的状态  原型:BOOL ClearCommError(HANDLE hFile,

  LPDWORD lpErrors,

  LPCOMATAT lpStat

  );  参数说明:

  -hFile:串口句柄

  -lpErrors:返回错误数值,错误常数如下:

  1-CE_BREAK:检测到中断信号。意思是说检测到某个字节数据缺少合法的停止位。

  2-CE_FRAME:硬件检测到帧错误。

  3-CE_IOE:通信设备发生输入/输出错误。

  4-CE_MODE:设置模式错误,或是hFile值错误。

  5-CE_OVERRUN:溢出错误,缓冲区容量不足,数据将丢失。

  6-CE_RXOVER:溢出错误。

  7-CE_RXPARITY:硬件检查到校验位错误。

  8-CE_TXFULL:发送缓冲区已满。

  -lpStat:指向通信端口状态的结构变量,原型如下:

  typedef struct _COMSTAT{

  ...

  ...

  DWORD cbInQue; //输入缓冲区中的字节数

  DWORD cbOutQue;//输出缓冲区中的字节数

  }COMSTAT,*LPCOMSTAT;

  该结构中对我们很重要的只有上面两个参数,其他的我们可以不用管。  操作举例:COMSTAT ComStat;

  DWORD dwError=0;

  ClearCommError(hComm,&dwError,&ComStat);

  上式执行完后,ComStat.cbInQue就是串口中当前含有的数据字节个数,我们利用此

  数值就可以用ReadFile()函数去读串口中的数据了。
8. PurgeComm()

  用途:清除串口缓冲区  原型:BOOL PurgeComm(HANDLE hFile,DWORD dwFlags);
  参数说明:

  -hFile:串口句柄

  -dwFlags:指定串口执行的动作,由以下参数组成:

  -PURGE_TXABORT:停止目前所有的传输工作立即返回不管是否完成传输动作。

-PURGE_RXABORT:停止目前所有的读取工作立即返回不管是否完成读取动作。

  -PURGE_TXCLEAR:清除发送缓冲区的所有数据。

  -PURGE_RXCLEAR:清除接收缓冲区的所有数据。  操作举例:PurgeComm(hComm, PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
  清除串口的所有操作。
10-SetCommMask()

  用途:设置串口通信事件。  原型:BOOL SetCommMask(HANDLE hFile,DWORD dwEvtMask);
  参数说明:

  -hFile:串口句柄

  -dwEvtMask:准备监视的串口事件掩码

  注:在用api函数撰写串口通信函数时大体上有两种方法,一种是查寻法,另外一种是事件通知法。

  这两种方法的区别在于收串口数据时,前一种方法是主动的周期性的查询串口中当前有没有数据;后一种方法是事先设置好需要监视的串口通信事件,然后依靠单独开设的辅助线程进行监视该事件是否已发生,如果没有发生的话该线程就一直不停的等待直到该事件发生后,将该串口事件以消息的方式通知主窗体,然后主窗体收到该消息后依据不同的事件性质进行处理。

  比如说当主窗体收到监视线程发来的RX_CHAR(串口中有数据)的消息后,就可以用ReadFile()

  函数去读串口。该参数有如下信息掩码位值:

  EV_BREAK:收到BREAK信号

  EV_CTS:CTS(clear to send)线路发生变化

  EV_DSR:DST(Data Set Ready)线路发生变化

  EV_ERR:线路状态错误,包括了CE_FRAME/CE_OVERRUN/CE_RXPARITY 3钟错误。

  EV_RING:检测到振铃信号。

  EV_RLSD:CD(Carrier Detect)线路信号发生变化。

  EV_RXCHAR:输入缓冲区中已收到数据。

  EV_RXFLAG:使用SetCommState()函数设置的DCB结构中的等待字符已被传入输入缓冲区中。

  EV_TXEMPTY:输出缓冲区中的数据已被完全送出。  操作举例:SetCommMask(hComm,EV_RXCHAR|EV_TXEMPTY);

  上面函数执行完毕后将监视串口中有无数据和发送缓冲区中的数据是否全部发送完毕。
11-WaitCommEvent()

  用途:用来判断用SetCommMask()函数设置的串口通信事件是否已发生。  原型:BOOL WaitCommEvent(HANDLE hFile,

  LPDWORD lpEvtMask,

  LPOVERLAPPED lpOverlapped

  );参数说明:

  -hFile:串口句柄

  -lpEvtMask:函数执行完后如果检测到串口通信事件的话就将其写入该参数中。

  -lpOverlapped:异步结构,用来保存异步操作结果。

由于GPS定位信息内容较少,因此多用RS-232串口将定位信息(NEMA0183语句)从GPS接收机传送到计算机中进行信息提取处理。

在Windows下不允许直接对硬件端口进行控制操作,所有的端口均被视为"文件",因此在对串口进行侦听之前需要通过打开文件来打开串口,并对其进行相关参数配置:
m_hCom=CreateFile("COM1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING, FILE_FLAG_OVERLAPPED,NULL); file://以异步方式打开COM1口
SetCommMask (m_hCom, EV_RXCHAR ) ; file://添加或修改Windows所报告的事件列表
SetupComm (m_hCom,READBUFLEN/*读缓冲*/,WRITEBUFLEN/*写缓冲*/); // 初始化通讯设备参数
// 清除缓冲信息
PurgeComm (m_hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR) ;
// 对异步I/O进行设置
CommTimeOuts.ReadIntervalTimeout = MAXDWORD ; file://接收两连续字节的最大时间间隔
CommTimeOuts.ReadTotalTimeoutMultiplier =0; file://接收每字节的平均允许时间
CommTimeOuts.ReadTotalTimeoutConstant = 0 ; file://接收时间常数
SetCommTimeouts (m_hCom , &CommTimeOuts) ;
file://获取并设置串口
GetCommState ( m_hCom, &dcb) ;
dcb.BaudRate = CBR_4800;
dcb.ByteSize = 8;
dcb.Parity = ODDPARITY;
dcb.StopBits = ONESTOPBIT ;
SetCommState( m_hCom, &dcb);    在成功打开并设置通讯口后,可采取轮询串口和事件触发两种方式对数据进行接收处理,本文在此采取效率比较高的事件触发方式进行接收处理,通过等待EV_RXCHAR事件的发生来启动ReadFile函数完成对GPS定位信息的接收:
while(true){
 WaitCommEvent (m_hCom,&dwEvtMask,NULL);
 if (dwEvtMask&EV_RXCHAR == EV_RXCHAR)
  if(ComStat.cbInQue>0)
   ReadFile(m_hCom,m_readbuf,ComStat.cbInQue,&nLength,&olRead);
}提取定位数据

  GPS接收机只要处于工作状态就会源源不断地把接收并计算出的GPS导航定位信息通过串口传送到计算机中。前面的代码只负责从串口接收数据并将其放置于缓存,在没有进一步处理之前缓存中是一长串字节流,这些信息在没有经过分类提取之前是无法加以利用的。因此,必须通过程序将各个字段的信息从缓存字节流中提取出来,将其转化成有实际意义的,可供高层决策使用的定位信息数据。同其他通讯协议类似,对GPS进行信息提取必须首先明确其帧结构,然后才能根据其结构完成对各定位信息的提取。对于本文所使用的GARMIN GPS天线板,其发送到计算机的数据主要由帧头、帧尾和帧内数据组成,根据数据帧的不同,帧头也不相同,主要有"$GPGGA"、"$GPGSA"、"$GPGSV"以及"$GPRMC"等。这些帧头标识了后续帧内数据的组成结构,各帧均以回车符和换行符作为帧尾标识一帧的结束。对于通常的情况,我们所关心的定位数据如经纬度、速度、时间等均可以从"$GPRMC"帧中获取得到,该帧的结构及各字段释义如下:

  $GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>*hh

  <1> 当前位置的格林尼治时间,格式为hhmmss

  <2> 状态, A 为有效位置, V为非有效接收警告,即当前天线视野上方的卫星个数少于3颗。

  <3> 纬度, 格式为ddmm.mmmm

  <4> 标明南北半球, N 为北半球、S为南半球

  <5> 径度,格式为dddmm.mmmm

  <6> 标明东西半球,E为东半球、W为西半球

  <7> 地面上的速度,范围为0.0到999.9

  <8> 方位角,范围为000.0到 359.9 度

  <9> 日期, 格式为ddmmyy

  <10> 地磁变化,从000.0到 180.0 度

  <11> 地磁变化方向,为E 或 W

  至于其他几种帧格式,除了特殊用途外,平时并不常用,虽然接收机也在源源不断地向主机发送各种数据帧,但在处理时一般先通过对帧头的判断而只对"$GPRMC"帧进行数据的提取处理。如果情况特殊,需要从其他帧获取数据,处理方法与之也是完全类似的。由于帧内各数据段由逗号分割,因此在处理缓存数据时一般是通过搜寻ASCII码"$"来判断是否是帧头,在对帧头的类别进行识别后再通过对所经历逗号个数的计数来判断出当前正在处理的是哪一种定位导航参数,并作出相应的处理。下面就是对缓存Data中的数据进行解帧处理的主要代码,本文在此只关心时间(日期和时间)和地理坐标(经、纬度):
for(int i=0;i<DATALENGTH;I++){
 if(Data[i]==''$'') file://帧头,SectionID为逗号计数器
  SectionID=0;
  if(Data[i]==10){ file://帧尾
}
 if(Data[i]=='','') file://逗号计数
  SectionID++;
 else {
  switch(SectionID){
   case 1: file://

获得GPS数据的两种方法 1读串口相关推荐

  1. java构造和解析json_Java构造和解析Json数据的两种方法详解一

    在www.json.org上公布了很多JAVA下的json构造和解析工具,其中org.json和json-lib比较简单,两者使用上差不多但还是有些区别.下面首先介绍用json-lib构造和解析Jso ...

  2. java json解析 代码_Java构造和解析Json数据的两种方法详解一

    在www.json.org上公布了很多JAVA下的json构造和解析工具,其中org.json和json-lib比较简单,两者使用上差不多但还是有些区别.下面首先介绍用json-lib构造和解析Jso ...

  3. Java构造和解析Json数据的两种方法详解一

    在www.json.org上公布了很多JAVA下的json构造和解析工具,其中org.json和json-lib比较简单,两者使用上差不多但还是有些区别.下面首先介绍用json-lib构造和解析Jso ...

  4. java在文件的后面添加_java 在file的尾部添加数据的两种方法总结

    java 在file的尾部添加数据的两种方法总结 问题描述: 在文件的末尾追加内容 方法1:利用RandomAccessFile类 1.将randomAccessFile模式设置为rw 2将rando ...

  5. java构建json_Java构造和解析Json数据的两种方法详解一

    在www.json.org上公布了很多JAVA下的json构造和解析工具,其中org.json和json-lib比较简单,两者使用上差不多但还是有些区别.下面首先介绍用json-lib构造和解析Jso ...

  6. SQLServer 批量插入数据的两种方法

    SQLServer 批量插入数据的两种方法- 发布:dxy 字体:[增加 减小] 类型:转载 在SQL Server 中插入一条数据使用Insert语句,但是如果想要批量插入一堆数据的话,循环使用In ...

  7. java 文件尾部_java 在file的尾部添加数据的两种方法总结

    java 在file的尾部添加数据的两种方法总结 问题描述: 在文件的末尾追加内容 方法1:利用RandomAccessFile类 1.将randomAccessFile模式设置为rw 2将rando ...

  8. mvc控制器接收数据的两种方法

    一.mvc控制器接收数据的两种方法 A方法: public ActionResult ProcessAdd() { string username=Request["UserName&quo ...

  9. 通达信交易接口api_股票量化交易-获取数据的两种方法

    量化交易第一步就是获取数据,介绍两种免费的方法 1.通过pytdx获取本地通达信数据 2.通过requests爬虫爬取腾讯财经数据 通过python第三方库pytdx获取 这是个很强大的第三方库,原理 ...

最新文章

  1. CMRNet++:在激光雷达地图中与地图和相机无关的单目视觉定位
  2. 不止最佳长论文,腾讯AI在ACL上还有这些NLP成果(附论文链接)
  3. php protected 属性,PHP实现在对象之外访问其私有属性private及保护属性protected的方法...
  4. 使用运行时动态创建属性
  5. BZOJ2002 [HNOI2010] 弹飞绵羊
  6. springboot集成redis配置多数据源
  7. java操作mongodb_Java操作MongoDB
  8. Lua的扩展库LuaSocket
  9. oracle拼接字符串报错,Oracle 中wmsys.wm_concat拼接字符串,结果过长报错解决
  10. JVM调优总结(四)-垃圾回收面临的问题
  11. 前端学习(1986)vue之电商管理系统电商系统之建立新分支
  12. Picturefill.WP – 根据屏幕尺寸加载合适的图片
  13. centos7.3 kvm虚拟化全自动化部署(0915金测OK)
  14. PIC单片机应用开发实践教程(四): MPLAB X IDE Debug
  15. Windows下载安装cuda10.1详细步骤
  16. 笔记本实现有线路由器功能
  17. 坚果云和微云哪个好?谈谈我的使用感受
  18. 它拖慢你的网速,还泄露你的个人隐私,学一招治治它
  19. 2021年度总结 -- 万粉博主的写作荣誉分享,写博客是一种心灵的修行
  20. 制作自己的matlab图注颜色

热门文章

  1. 使用powershell将Ppt转化为PDF
  2. Docker面试相关内容--2022年总结
  3. 对不起,学习Python的捷径教程有99%的人都已经知道了
  4. 基于深度学习的影像深度重建综述
  5. 改计算机高级设置吃鸡,玩端游吃鸡卡怎么办
  6. 【转】深入理解Batch Normalization批标准化
  7. Deckset for Mac(MD文档转幻灯片软件)
  8. 技术分享| 基于RTM 实现的呼叫邀请如何添加推送功能?
  9. idea创建第一个SpringMVC项目
  10. nginx 手机版页面判断_nginx通过user-agent判断是否手机浏览器的方法