在2008年上半年就曾經深入研究過GPS,當時還以為已經相對全面的了解GPS呢,現在重新拾起去研究GPS技術,發現還是差了一大截。最初以為GPS是單向通信,GPS子產品按照固定的時間間隔發送文本格式的GPS資料。現在才知道GPS不僅可以雙向通信,還可以以二進制格式收發資料,并且可以配置需要發送資料的種類和發送間隔,當然必要的時候,還可以用專門的工具,更新GPS子產品的固件。
最初了解GPS,是基于WINCE平台,為寫一本書而做,詳情請參見《實戰WindowsEmbedded 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
格式說明(Set Serial Port Data Format):
GPS庫相關内容我這裡就不細說了,文檔裡面有詳細的說明。我這裡說一下,在.NET Micro Framework平台,如何進行Winform界面開發(WinForm for .NET MF 功能一覽)。
本執行個體程式,GPS相關函數一旦執行,會自動把GPS子產品的相關參數指派到GPS類的相關屬性中去。界面繪圖我們采用重載Form類的OnPaint方法,為了避免閃爍,我們還采用了在Windows程式設計中常見的技巧,就是重載OnPaintBackground方法,不去繪制背景。
protected override void OnPaint(PaintEventArgse)
{
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, newSolidBrush(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(Graphicse, Rectangle rect)
{
Fontfont = new Font("Arial", 9, FontStyle.Regular);
intFontHeight = 20;
int SNRHeight= rect.Height - FontHeight;
intSNRWidth = (rect.Width - FontHeight / 2) / 12;
//繪制信噪比圖
e.DrawLine(newPen(Color.Gray),rect.Left, rect.Top, rect.Right, rect.Top);
e.DrawLine(newPen(Color.Gray),rect.Left, rect.Top + SNRHeight / 2, rect.Right, rect.Top + SNRHeight / 2);
e.DrawLine(newPen(Color.Gray),rect.Left, rect.Top + SNRHeight, rect.Right, rect.Top + SNRHeight);
for (int i = 0; i < 12; i++)
{
stringstrPRN = GPS.Manage.Satellite[i].PRN.ToString();
if(strPRN.Length == 1) strPRN = "0"+ strPRN;
intHeight = (int)(GPS.Manage.Satellite[i].SNR *SNRHeight / 100);
intfont_h, font_w;
font.Value.ComputeExtent(strPRN, out font_w, outfont_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 voidDrawSatellite(Graphics e, Rectangle rect)
{
Fontfont = new Font("Arial", 9, FontStyle.Regular);
int X = rect.Left + rect.Width / 2;
int Y =rect.Top + rect.Height / 2;
intSize = (rect.Width > rect.Height ? rect.Height : rect.Width);
int R =(Size - 12 * 2) / 6;
int r =8;
e.DrawLine(newPen(Color.Red),X - R * 3 - 12, Y, X + R * 3 + 12, Y);
e.DrawLine(newPen(Color.Red),X, Y - R * 3 - 12, X, Y + R * 3 + 12);
e.DrawEllipse(newPen(Color.Blue),new Rectangle(X- R, Y - R, R * 2, R * 2));
e.DrawEllipse(newPen(Color.Blue),new Rectangle(X- R * 2, Y - R * 2, R * 4, R * 4));
e.DrawEllipse(newPen(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;
doubleA1 = 0, A2 = 0;
StringFormatsFormat = 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.rarMF簡介:
http://blog.csdn.net/yefanqiu/article/details/5711770MF資料:
http://www.sky-walker.com.cn/News.asp?Id=25