android gps nmea,读取Android GPS NMEA数据

转自:http://cms.35g.tw/coding/%E8%AE%80%E5%8F%96android%E5%85%A7%E5%BB%BAgps%E7%9A%84nmea%E8%B3%87%E8%A8%8A/

如何在Android取得GPS定位資料在很多文章或是教學中都很容易了解及使用,但要如何像其他APP一樣可以取得更詳細的內容呢?這就要利用Android在GpsStatus物件中的Listener:GpsStatus.NmeaListener,當GPS啟動時就會立即的收到GPS統一規格NMEA0831格式資料,解析這些資料就能得到:座標、衛星有效數量、速度…等一些GPS的詳細資訊,所以自已要寫一個了解GPS狀態並不是難事!

取得LocationManager服務

GPS或其他相關的定位服務由LocationManager來管理,我們必需要先取得LocationManager的物件及註冊Listener才能使用最基礎的定位服務,下面先取得定位服務後,再註冊名為locationListener的Listener。

1

2

3

4

5//-----------start-----------

LocationManagerlocationManager=(LocationManager)getSystemService(Context.LOCATION_SERVICE);

locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,5000, 0, locationListener);

//------------end------------

範例中直接指定定位更新的來源提供者為GPS,不加入其他定位來源的判斷,其中上述的locationListener的Listener內容:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44//-----------start-----------

LocationListenerlocationListener=newLocationListener(){

@Override

publicvoidonLocationChanged(Locationloc) {

//TODO Auto-generated method stub

//定位資料更新時會回呼

}

@Override

publicvoidonProviderDisabled(Stringprovider) {

//TODO Auto-generated method stub

//定位提供者如果關閉時會回呼,並將關閉的提供者傳至provider字串中

}

@Override

publicvoidonProviderEnabled(Stringprovider) {

//TODO Auto-generated method stub

//定位提供者如果開啟時會回呼,並將開啟的提供者傳至provider字串中

}

@Override

publicvoidonStatusChanged(Stringprovider, int status, Bundle extras){

//TODO Auto-generated method stub

Log.d('GPS-NMEA',provider + '');

//GPS狀態提供,這只有提供者為gps時才會動作

switch(status) {

caseLocationProvider.OUT_OF_SERVICE:

Log.d('GPS-NMEA','OUT_OF_SERVICE');

break;

caseLocationProvider.TEMPORARILY_UNAVAILABLE:

Log.d('GPS-NMEA','TEMPORARILY_UNAVAILABLE');

break;

caseLocationProvider.AVAILABLE:

Log.d('GPS-NMEA',''+ provider + '');

break;

}

}

};

//------------end------------

以上程式中提供最基本的方法,如果要取得座標更新訊息其方法為onLocationChanged,例如,你可以將座標印在Log上:

1

2

3

4

5

6//-----------start-----------

publicvoidonLocationChanged(Locationloc) {

//TODO Auto-generated method stub

Log.d('GPS-NMEA',loc.getLatitude() + ','+ loc.getLongitude());

}

//------------end------------

不過這些基本操作會在其他文章中再說明,這裡最大的重點是要註冊GpsStatus.NmeaListener的Listener,前面只是做最基本的操作,接下來才能發揮作用。

註冊GpsStatus.NmeaListener

先前的註冊定位相關資訊後,再來就是要註冊GpsStatus.NmeaListener,所以先前的內容會再修改為:

1

2

3

4

5//-----------start-----------

locationManager=(LocationManager)getSystemService(Context.LOCATION_SERVICE);

locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,5000, 0, locationListener);

locationManager.addNmeaListener(nmeaListener);

//------------end------------

其中上述的nmeaListener的Listener內容:

GpsStatus.NmeaListener nmeaListener = new GpsStatus.NmeaListener() { public void onNmeaReceived(long timestamp, String nmea) { //check nmea's checksum Log.d('GPS-NMEA', nmea); } };

在方法onNmeaReceived中,只要系統每次取得GPS資料時就會呼叫此方法,並將資料傳前字串nmea,此時再處理這個字串內容就行,在這我們將每次收到的訊息印出來,印出來的資訊類似下面例子:$PGLOR,0,NEW,PERFIX,1,PER,1,QOP,50*36$PGLOR,0,RID,BCD,2,18,2,96441*77$GPGGA,072515.33,,,,,0,00,1000.0,,M,,M,,*53$PGLOR,0,STA,072515.33,0.000,0.707,175,98,10000,0,P,D,L,1,C,0,S,0004,0*54$PGLOR,1,SAT,G03,035,13,G16,036,13,G20,023,11,G27,034,13,G32,031,13*6F$PGLOR,0,SIO,TxERR,0,RxERR,0,TxCNT,3444,RxCNT,3360,DTMS,2059,DTIN,6,DTOUT,201,HATMD,0*0A$PGLOR,0,HLA,072515.33,L,3,Al,,A,,H,,,M,0,Ac,0,Gr,0,S,,,Sx,,,T,0,Tr,,Mn,0*01$GPGSV,2,1,05,03,01,000,35,16,01,000,36,20,01,000,23,27,01,000,34*79$GPGSV,2,2,05,32,01,000,31*4E$GPGSA,A,1,,,,,,,,,,,,,140.0,99.0,99.0*35$GNGSA,A,1,,,,,,,,,,,,,140.0,99.0,99.0*2B$QZGSA,A,1,,,,,,,,,,,,,140.0,99.0,99.0*29$GPRMC,072515.33,V,,,,,,,090414,,,N*71$GPGGA,072516.33,,,,,0,00,1000.0,,M,,M,,*50$PGLOR,0,STA,072516.33,0.000,0.707,175,98,10000,0,P,D,L,1,C,1,S,0000,0*52$PGLOR,1,SAT,G16,037,13,G32,032,13,G27,034,13,G03,036,13*36$PGLOR,0,SIO,TxERR,0,RxERR,0,TxCNT,1792,RxCNT,2996,DTMS,970,DTIN,7,DTOUT,152,HATMD,-27*2E$PGLOR,0,HLA,072516.33,L,,Al,,A,,H,,,M,0,Ac,0,Gr,0,S,,,Sx,,,T,0,Tr,,Mn,0*31$GPGSV,3,1,10,16,46,251,37,32,34,249,32,27,19,189,34,03,07,203,36*7F$GPGSV,3,2,10,31,51,019,,14,39,138,,29,25,053,,20,17,286,*70$GPGSV,3,3,10,23,10,320,,25,03,046,*7F$GPGSA,A,1,,,,,,,,,,,,,140.0,99.0,99.0*35$GNGSA,A,1,,,,,,,,,,,,,140.0,99.0,99.0*2B$QZGSA,A,1,,,,,,,,,,,,,140.0,99.0,99.0*29

此時,你就完成讀取GPSNMEA資料的工作,但你取得此資料後還是必需要解析NMEA資料才能正確的取得資訊,後面會利用一個範例來取得GPS定位狀態、衛星有效數量、座標…等資訊。

執行範例:

執行範例之前必需要提醒一點,你要自行先將GPS開啟,範例不會對GPS是否開啟做偵測的動作,當然你也可以試著自行加入該程式內容讓範例程式更加符合實際需要。

檢查NMEA誤碼資料(checksum)

NMEA規格中規定必需要對NMEA檢查checksum是否正確,這樣才能確保資料內容正確後再去解析資料,這裡我將檢查方式寫程一個方法,需要的可以從範例擷取使用。

NMEA規格中將每串資料最後一筆從的*號後到結尾內容為checksum的值,例如:

$GPGSA,A,1,,,,,,,,,,,,,140.0,99.0,99.0*35

其取得的checksum為35,而35的值為十六進制的35,再利用checksum特性將格式中的$與*之間內容加總計算,與取得的比對,正確時,此資料為有效資料。$......加總........*

所以我所寫的checksum程式如下,資料為有效值會返回true。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27//-----------start-----------

privatebooleanisValidForNmea(StringrawNmea){

booleanvalid = true;

byte[]bytes = rawNmea.getBytes();

intchecksumIndex = rawNmea.indexOf('*');

//NMEA星號後為checksumnumber

bytechecksumCalcValue = 0;

intchecksumValue;

//檢查開頭是否為$

if((rawNmea.charAt(0) != '$') ||(checksumIndex==-1)){

valid= false;

}

//

if(valid){

Stringval = rawNmea.substring(checksumIndex + 1,rawNmea.length()).trim();

checksumValue= Integer.parseInt(val, 16);

for(inti = 1; i< checksumIndex; i++){

checksumCalcValue= (byte) (checksumCalcValue ^ bytes[i]);

}

if(checksumValue != checksumCalcValue){

valid= false;

}

}

returnvalid;

}

//------------end------------

移除Listener

不使用時記得將Listener給移除:

1

2

3

4//-----------start-----------

locationManager.removeUpdates(locationListener);

locationManager.removeNmeaListener(nmeaListener);

//------------end------------

正確來說是必需要自行移除,如果你忘記移除時,系統雖然還防止問題產生,在過程中還是會正常運作,但不增加系統上的負擔,Listener不使用時還是移除比較好。

處理NMEA資料

在每次取得NMEA資料會進行檢查,再將NMEA資料傳遞至副程式nmeaProgress:

1

2

3

4

5

6

7

8

9

10

11

12//-----------start-----------

nmeaListener= newGpsStatus.NmeaListener() {

publicvoidonNmeaReceived(longtimestamp, String nmea) {

//checknmea's checksum

if(isValidForNmea(nmea)){

nmeaProgress(nmea);

Log.d('GPS-NMEA',nmea);

}

}

};

//------------end------------

因為讀取NMEA的Listener並非在UI執行緒之中,利用nmeaProgress將NMEA資料傳至自建的Handler,確保在UI執行緒中能將資料傳至UI控制元件:

private void nmeaProgress(String rawNmea){ String[] rawNmeaSplit = rawNmea.split(','); if (rawNmeaSplit[0].equalsIgnoreCase('$GPGGA')){ //send GGA nmea data to handler Message msg = new Message(); msg.obj = rawNmea; mHandler.sendMessage(msg); } }

程式中必需要注意一段:if (rawNmeaSplit[0].equalsIgnoreCase('$GPGGA')){::: }

$GPGGA為NMEA0831所定義的,下圖為NMEA0831描述的規格,我也有將格式貼於範例中,

c4395c90ca8199e9061a1ef1c2516516.png

中文說明:

<1> UTC時間,格式為hhmmss.sss。<2> 緯度,格式為ddmm.mmmm(前導位數不足則補0)。<3> 緯度半球,N或S(北緯或南緯)。<4> 經度,格式為dddmm.mmmm(前導位數不足則補0)。<5> 經度半球,E或W(東經或西經)。<6> 定位品質指示,0=定位無效,1=定位有效,2=差分定位(有效)。<7> 使用衛星數量,從00到12(前導位數不足則補0)。<8> 水平精確度,0.5到99.9。<9> 天線離海平面的高度,-9999.9到9999.9米<10> 高度單位,M表示單位米。<11> 大地橢球面相對海平面的高度(-999.9到9999.9)。<12> 高度單位,M表示單位米。<13> 差分GPS數據期限(RTCM SC-104),最後設立RTCM傳送的秒數量。<14> 差分參考基站標號,從0000到1023(前導位數不足則補0)。<15> checksum校驗和。

每項資料都使用,分隔,每項資料都有其意義,範例中取用GGA中的2、3、4、5、6、7的資料,並將處理過程寫在Handler內容中。

Handler內容如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15//-----------start-----------

mHandler= new Handler() {

publicvoidhandleMessage(Messagemsg) {

Stringstr = (String) msg.obj;

String[]rawNmeaSplit = str.split(',');

txtGPS_Quality.setText(rawNmeaSplit[6]);

txtGPS_Location.setText(rawNmeaSplit[2]+ ' '+ rawNmeaSplit[3] +',' + rawNmeaSplit[4] + ''+ rawNmeaSplit[5]);

txtGPS_Satellites.setText(rawNmeaSplit[7]);

}

};

}

//------------end------------

依照格式中的第6筆為GPS定位品質,第2~5為定位座標,如果未定位成功在這裡得到的資料會是空白,最後第7筆為已經接收到的衛星有效數量,再將取得的資料傳至UI控制元件的TextView,所以看到的結果如下:

179295972_1_20191231101255207.png

以上為最基本的讀取內建GPS的NMEA資料方式,如果將NMEA的資料加強利用時,提供的GPS狀態將更詳細,利用NMEA讀取的技巧與解析方式也能用在藍牙的外部GPS接收器,將從藍牙取得的NMEA資料加以利用。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值