NMEA 0183是一种航海、海运方面有关于数字信号传递的标准,此标准定义了电子信号所需要的传输协议,传输数据时间、并且指明了信息格式需要一个4800bps的串行数据接口。
NMEA 0183的设备使用了一个如下图的串行接口的参数选择:
Baud Rate |
4800 |
Data Bits |
8(d7=0) |
Parity |
None |
Stop Bits |
One(or more) |
设备需要有信息源和接收端,传送端发送数据到另一个NMEA 0183的设备,信息源和接收端分别用来传送和接受8位ASCII码的数据。
信息格式:
NMEA 0183的信息格式一般如下所示,
$aaaaa,df1,df2,....[CR][LF]
所有的信息由$开始,以换行结束,紧跟着$后的五个字符解释了信息的基本类型,多重的信息之间用逗号隔开。
下面是三种基本的类型:
Ø 信息源
Ø 查询
Ø 属性
信息源:
它的标准格式为
$ttsss,df1,df2,....[CR][LF]
在紧随$后的两个字符用来识别做为信息内容识别码的后3个字符,信息识别码定义了保留的数据区,在NMEA 0183标准下,每个类型的数据区的信息内容是符合标准的。
例:
$HCHDM,238,M[CR][LF]
标明“HC”说明信息源作为一个磁性的罗盘,“HDM” 指明以下是磁性的船首向航向,238是船首向航向的值,M指明船首向航向的值是磁性的。
查询内容
查询意味着接受端需要从信息源那里得到一个有规律的内容,例如,我们可以发一个信息给GPS接受器请求传送一个“DISTANCE-TO-WAYPOINT”的信息,得到响应后,GPS接受器会发送请求的内容,直到接到别的请求。
一般格式为:
$ttllQ,sss,[CR][LF]
头两个字符做为请求者的信息源的识别码,后两个字符作为被查询的设备的信息识别,最后一个字符说明这是一个查询信息。紧跟着的字段(sss)包含了三个字的被查询内容的记忆信息,如下
$CCGPQ,GGA[CR][LF]
说明“CC”这个设备(计算机)正从 “GP”这个设备(GPS)查询GGA的内容。GPS将每隔一秒传送这个内容,直到有别的查询请求。
属性
这对厂商来说是一种使用没有在标准下预定义的特殊内容的方法。
它通常的格式为
$PmmmA,df1,df2,...,[CR][LF]
P说明是属性内容,mmm定义为厂商信息代码,A(A-Z)标明信息类型。
以下是一个具体的例子:
和卫星的通讯,接收到的数据格式将是下面这样的:
$GPRMC,204700,A,3403.868,N,11709.432,W,001.9,336.9,170698,013.6,E*6E
通过这个例子来仔细分析一下其中的各部分的含义。不过请注意,我们只讨论前7个数据。表格指出了这些数据的细节说明。
表格9.1:GPS手持机的NMEA数据结构
数据 |
NMEA 0183协议 |
说明 |
$GPRMC |
|
GPS推荐的最短数据 |
204700 |
UTC_TIME |
24小时制的标准时间,按照小时/分钟/秒的格式 |
A |
A 或者 V |
A表示数据“OK”,V表示一个警告 |
3403.868 |
LAT |
纬度值,精确到小数点前4位,后3位 |
N |
LAT_DIR |
N表示北纬,S表示南纬 |
11709.432 |
LON |
经度值,精确到小数点前5位,后3位 |
W |
LON_DIR |
W表示西经,E表示东经 |
如果当前没有和卫星取得联系,那么字符串的格式为:
$GPRMC,UTC_TIME,V,...
GPS THING
有关NMEA数据的类为
struct CNmeaData
{
CNmeaData ();
void ResetData ();
// Data retrieved from the NMEA sentences.
double lat; // Latitude, in degrees (positive=N, negative=S)
double lon; // Longitude, in degrees (positive=E, negative=W)
double altitude; // Altitude, in feet
double speed; // Speed, in knots
double track; // Current track, in degrees.
double magVariation; // Magnetic variation, in degrees.
double hdop; // Horizontal dilution of precision.
int numSats; // Number of satellites in the sky.
int UTCYear; // GPS Date (UTC), year part
int UTCMonth; // GPS Date (UTC), month part
int UTCDay; // GPS Date (UTC), day part
int UTCHour; // GPS Time (UTC), hour part.
int UTCMinute; // GPS Time (UTC), minute part
int UTCSecond; // GPS Time (UTC), second part
CSatData satData[MAX_SATS];
// Quality of last fix:
// 0 = invalid, 1 = GPS fix, 2 = DGPS fix.
GPS_FIX_QUALITY lastFixQuality;
// Validity of data parsed.
bool isValidLat; // Latitude
bool isValidLon; // Longitude
bool isValidAltitude; // Altitude
bool isValidSpeed; // Speed
bool isValidDate; // Date
bool isValidTime; // Time
bool isValidTrack; // Track
bool isValidMagVariation; // Magnetic variation
bool isValidHdop; // Horizontal dilution of precision
bool isValidSatData; // Satellite data
// Has a valid coordinate ever been sent over the serial port?
bool hasCoordEverBeenValid;
};
class CNmeaParser
{
public:
CNmeaParser ();
SENTENCE_STATUS ParseSentence (const char* sentence);
void GetData (CNmeaData& data) const;
void ResetData () {m_data.ResetData ();}
private:
bool ParseDegrees (double& degrees, const char* degString) const;
bool ParseDate (int& year, int& month, int& day,
const char* dateString) const;
bool ParseTime (int& hour, int& minute, int& second,
const char* timeString) const;
void ParseAndValidateAltitude (const char* field, const char unit);
void ParseAndValidateDate (const char* field);
void ParseAndValidateFixQuality (const char* field);
void ParseAndValidateLat (const char* field, const char hem);
void ParseAndValidateLon (const char* field, const char hem);
void ParseAndValidateHdop (const char* field);
void ParseAndValidateSpeed (const char* field);
void ParseAndValidateMagVariation(const char* field,
const char direction);
void ParseAndValidateTime (const char* field);
void ParseAndValidateTrack (const char* field);
void ParseGGA (const char* sentence);
void ParseGLL (const char* sentence);
void ParseRMC (const char* sentence);
void ParseGSV (const char* sentence);
bool GetNextField (char* data, const char* sentence,
uint& currentPosition) const;
bool IsValidSentenceType (const char* sentence) const;
bool IsCorrectChecksum (const char* sentence) const;
CNmeaData m_data;
// Needed for parsing the GSV sentence.
int m_lastSentenceNumber;// Which sentence number was the last one?
int m_numSentences; // Number of sentences to process.
int m_numSatsExpected; // Number of satellites expected to parse.
int m_numSatsLeft; // Number of satellites left to parse.
int m_satArrayPos; // Array position of the next sat entry.
CSatData m_tempSatData[MAX_SATS];
};
class CNmeaSerial
{
public:
CNmeaSerial ();
CNmeaSerial (HWND hMsgWnd, DWORD timeout);
~CNmeaSerial ();
SERIAL_RESULT_TYPE CloseConnection ();
SERIAL_RESULT_TYPE OpenConnection ();
SERIAL_RESULT_TYPE OpenConnection (uint8 comPort, uint32 baudRate,
uint8 dataBits, SETPARITY parity, STOPBITS stopBits);
SERIAL_RESULT_TYPE GetData (CNmeaData& data) const;
SERIAL_RESULT_TYPE GetSettings (uint8& comPort, uint32& baudRate,
uint8& dataBits, SETPARITY& parity, STOPBITS& stopBits) const;
unsigned long GetThreadHandle () const {return m_hThread;}
BOOL IsConnected () const {return m_isConnected;}
private:
SERIAL_RESULT_TYPE InitThread ();
BOOL KillThread ();
BOOL LockData () const;
void SetDefaults ();
BOOL UnlockData () const;
// The member function that parses the sentences; this function runs
// in another thread.
static void ProcessSentences (void* currentObject);
uint8 m_comPort;
uint32 m_baudRate;
uint8 m_dataBits;
SETPARITY m_parity;
STOPBITS m_stopBits;
BOOL m_isConnected;
DWORD m_timeout;
unsigned long m_hThread;
HANDLE m_hPort;
HANDLE m_hMutex;
DWORD m_threadId;
CNmeaParser m_parser;
// Window that will receive the parsing messages.
HWND m_hMsgWnd;
// If this value is set to TRUE, the thread that parses the sentences
// will terminate itself.
BOOL m_terminateThread;
};