在2008上半年就曾經深入研究過GPS,當時還以為已經相對全面的了解GPS呢,現在重新拾起去研究GPS技術,發現還是差了一大截。最初以為GPS是單向通信,GPS模塊按照固定的時間間隔發送文本格式的GPS數據。現在才知道GPS不僅可以雙向通信,還可以以二進制格式收發數據,並且可以配置需要發送數據的種類和發送間隔,當然必要的時候,還可以用專門的工具,更新GPS模塊的固件。
最初了解GPS,是基於WINCE平台,為寫一本書而做,詳情請參見《實戰Windows Embedded CE 6.0—GPS篇》和《我的第一個WINCE驅動》。后來為了便於調試,又把程序移植到Windows Mobile手機上(采用.NET精簡框架集的Winform完成,本篇.NET MF界面代碼就是基於原先的這套代碼,稍作改進而來,而底層接收代碼,添加了校驗和更全的GPS命令解析),相關博文請參見《GPS NMEA0183協議解析》。
現在重新研究GPS,是為物聯網網關系統封裝一個GPS庫,最初的時候,購買了幾個低價二手的GPS模塊,但是卻無法定位,在陽台附近無法定位也就算了,但是我直接到空曠的大操場也無法定位,並且沒有一個星的信號。所以后來只好又購買一個價錢較高,帶有源天線的GPS模塊。
這個帶外接天線的模塊果然不錯,信號強度蠻強,但是我在購買的時候犯了一個錯誤,選型的時候,選擇了“4800bps GPRMC數據包輸出,不帶PPS”,所以就只能輸出$GPRMC基本信息了,但是這樣星圖就無法顯示了。
由於技術支持不在線,所以只好先自己想辦法解決這個問題了。我想應該有兩種思路可以解決這個問題,一是更新固件。但是這種方法顯然需要技術支持來提供相應固件,如果自己找相關工具和固件進行燒寫,難免會出問題(后來問了技術支持才知道,還得飛一個線,進入燒寫模式才行);二是配置信息輸出。這種方法最方便,問題是,掉電配置就丟失了,但是這個GPS板子帶紐扣電池,所以問題不大。
有了第二種思路,然后網上就進行搜索,果然功夫不負有心人,搜到了如下信息:
NMEA信息輸出控制
$PSRF103,00,01,00,01*25<CR><LF>
格式說明(Set Serial Port Data Format):
Name |
Example |
Unit |
Description |
Message ID |
$PSRF103 |
|
PSRF103 protocol header |
Msg |
00 |
|
0:GGA 1:GLL 2:GSA 3:GSV 4:RMC 5:VTG 6:MSS (If internal beacon is supported) 7:Not defined 8:ZDA (if 1PPS output is supprttd) 9:Not defined |
Mod |
01 |
|
0 = Set Rate 1 = Query one time 2 = ABP On 3 = ABP Off |
Rate |
00 |
|
Output Rate: 0 = Off 1–255 = seconds between messages |
CksumEnable |
01 |
|
0=Disable Checksum 1=Enable Checksum |
Checksum |
*25 |
|
|
<CR><LF> |
|
|
End of message termination |
示例 |
關閉GGA: $PSRF103,00,00,01,01*25 設置GGA為5秒輸出一次: $PSRF103,00,00,05,01*21
關閉GSA: $PSRF103,02,00,00,01*26 設置GSA為5秒輸出一次: $PSRF103,02,00,05,01*23 |
但是由於NMEA有校驗,所以還需要一個專門的工具來設置才行,所以又找到了SiRFLive軟件,這個軟件很不錯,可以方便的調試GPS模塊。也許是供電的問題,我這次在陽台測試我原先的GPS模塊,居然可以定位成功了。下圖便是該GPS模塊使用SiRFLive軟件進行測試的效果圖。
如果需要配置GPS,直接進入命令發送窗口即可,記得選擇NMEA協議。
修改了相關配置,新購買的GPS果然可以輸出星圖信息了,在物聯網智能網關上的運行效果圖如下:
GPS庫相關內容我這里就不細說了,文檔里面有詳細的說明。我這里說一下,在.NET Micro Framework平台,如何進行Winform界面開發(WinForm for .NET MF 功能一覽)。
本實例程序,GPS相關函數一旦執行,會自動把GPS模塊的相關參數賦值到GPS類的相關屬性中去。界面繪圖我們采用重載Form類的OnPaint方法,為了避免閃爍,我們還采用了在Windows編程中常見的技巧,就是重載OnPaintBackground方法,不去繪制背景。
protected override void OnPaint(PaintEventArgs e) { try { e.Graphics.Clear(Color.Gray); //繪制背景 //-------------------------- //繪制信噪比圖 DrawSNR(e.Graphics, new Rectangle(2, 240 - 80, 320 - 4, 80)); //繪制星圖 DrawSatellite(e.Graphics, new Rectangle(10, 60, 100, 100)); //狀態 e.Graphics.DrawString("狀態:" + (GPS.Online ? "已連接 " : "未連接 ") + (GPS.Manage.AnchorState == "A" ? "已定位" : "未定位"), font, sb, 5, 8); //坐標 e.Graphics.DrawString("坐標:" + GPS.Manage.ToString("D"), font, sb, 5, 25); //pb_Graphics.DrawString("坐標:" + GPS.Manage.Latitude.ToString() + " " + NMEA.GPS.Longitude.ToString(), font, new SolidBrush(Color.White), 5, 25); //時間 e.Graphics.DrawString("時間:" + GPS.Manage.UTCDateTime.ToString(), font, sb, 150, 25); //------------------------------- //衛星數 e.Graphics.DrawString("衛星:" + GPS.Manage.SatelliteNum.ToString() + " 顆", font, sb, 130, 60); //定位狀態 0=未定位,1=GPS單點定位固定解,2=差分定位,3=無效PPS,4=RTK固定解,5=RTK浮點解,6=估計值,7=手工輸入模式,8=模擬模式 e.Graphics.DrawString("狀態:" + strState[GPS.Manage.AnchorSStateEx], font, sb, 130, 75); //獲取定位模式(A=自動,M=手動)。 e.Graphics.DrawString("模式:" + (GPS.Manage.AnchorMode == "A" ? "自動" : "手動"), font, sb, 130, 90); //定位類型(1=未定位,2=2D定位,3=3D定位) e.Graphics.DrawString("類型:" + strType[GPS.Manage.AnchorType], font, sb, 130, 105); //海拔 e.Graphics.DrawString("海拔:" + GPS.Manage.Altitude.ToString("F2") + "(" + GPS.Manage.Height.ToString("F2") + ")", font, sb, 130, 120); //速度 e.Graphics.DrawString("速度:" + GPS.Manage.KSpeed.ToString("F2"), font, sb, 130, 135); //方向 e.Graphics.DrawString("方向:" + GPS.Manage.Track.ToString("F2"), font, sb, 130, 150); //信息 Microsoft.SPOT.Debug.Print(GPS.ErrorMessage); } catch { } }
具體繪制繪制信噪比圖的代碼如下:
private void DrawSNR(Graphics e, Rectangle rect) { Font font = new Font("Arial", 9, FontStyle.Regular); int FontHeight = 20; int SNRHeight = rect.Height - FontHeight; int SNRWidth = (rect.Width - FontHeight / 2) / 12; //繪制信噪比圖 e.DrawLine(new Pen(Color.Gray), rect.Left, rect.Top, rect.Right, rect.Top); e.DrawLine(new Pen(Color.Gray), rect.Left, rect.Top + SNRHeight / 2, rect.Right, rect.Top + SNRHeight / 2); e.DrawLine(new Pen(Color.Gray), rect.Left, rect.Top + SNRHeight, rect.Right, rect.Top + SNRHeight); for (int i = 0; i < 12; i++) { string strPRN = GPS.Manage.Satellite[i].PRN.ToString(); if (strPRN.Length == 1) strPRN = "0" + strPRN; int Height = (int)(GPS.Manage.Satellite[i].SNR * SNRHeight / 100); int font_h, font_w; font.Value.ComputeExtent(strPRN, out font_w, out font_h); //星號 e.DrawString(strPRN, font, new SolidBrush(Color.White), (int)(rect.Left + FontHeight / 4 + SNRWidth * i), (int)(rect.Top + SNRHeight + 4)); //信噪比 e.FillRectangle(new SolidBrush(Color.Blue), new Rectangle(rect.Left + FontHeight / 4 + SNRWidth * i, rect.Top + SNRHeight - Height, font_w, Height)); } }
繪制星圖的代碼如下:
private void DrawSatellite(Graphics e, Rectangle rect) { Font font = new Font("Arial", 9, FontStyle.Regular); int X = rect.Left + rect.Width / 2; int Y = rect.Top + rect.Height / 2; int Size = (rect.Width > rect.Height ? rect.Height : rect.Width); int R = (Size - 12 * 2) / 6; int r = 8; e.DrawLine(new Pen(Color.Red), X - R * 3 - 12, Y, X + R * 3 + 12, Y); e.DrawLine(new Pen(Color.Red), X, Y - R * 3 - 12, X, Y + R * 3 + 12); e.DrawEllipse(new Pen(Color.Blue), new Rectangle(X - R, Y - R, R * 2, R * 2)); e.DrawEllipse(new Pen(Color.Blue), new Rectangle(X - R * 2, Y - R * 2, R * 4, R * 4)); e.DrawEllipse(new Pen(Color.Blue), new Rectangle(X - R * 3, Y - R * 3, R * 6, R * 6)); e.DrawString("N", font, new SolidBrush(Color.White), X + 2, Y - R * 3 - 10); e.DrawString("S", font, new SolidBrush(Color.White), X + 2, Y + R * 3 + 2); e.DrawString("W", font, new SolidBrush(Color.White), X - R * 3 - 10, Y + 2); e.DrawString("E", font, new SolidBrush(Color.White), X + R * 3 + 2, Y + 2); //繪制衛星位置 int X0 = 0, Y0 = 0, L = 0; double A1 = 0, A2 = 0; StringFormat sFormat = new StringFormat(); sFormat.Alignment = StringAlignment.Center; sFormat.LineAlignment = StringAlignment.Center; for (int i = 0; i < 12; i++) { if (GPS.Manage.Satellite[i].PRN > 0) { A1 = GPS.Manage.Satellite[i].Elevation * Math.PI / 180; A2 = GPS.Manage.Satellite[i].Azimuth * Math.PI / 180; L = (int)(Math.Cos(A1) * 3 * R); X0 = X + (int)(Math.Cos(Math.PI * 5 / 2 - A2) * L); Y0 = Y - (int)(Math.Sin(Math.PI * 5 / 2 - A2) * L); e.FillEllipse(new SolidBrush(Color.Blue), new Rectangle(X0 - r, Y0 - r, 2 * r, 2 * r)); e.DrawString(GPS.Manage.Satellite[i].PRN.ToString(), font, new SolidBrush(Color.White), new Rectangle(X0 - r * 2, Y0 - r * 2, 4 * r, 4 * r), sFormat); } } }
從以上代碼可以看出,在.NET Micro Framework系統中開發WinForm程序,和上位機沒有什么區別,上面的代碼也基本上也可以在windows桌面.Net程序中直接可以使用。
下載地址:http://www.sky-walker.com.cn/MFRelease/library/V42/YFSoft.Hardware.GPS.rar
MF簡介:http://blog.csdn.net/yefanqiu/article/details/5711770