-
简介
最近工作中需要读取gps设备的信息,平板本身有内置的gps设备,但是精度不够,就又添加了一个外置的gps。
对于外置的gps,我们主要通过SerialPort类来获得串口的信息,然后对接收到的内容进行解析处理,
对于内置的gps,我们可以通过GeoCoordinateWatcher类来方便的获取gps数据。 -
使用 SerialPort 设置串口属性
进行串口通讯时,需要设置一些相关参数,可以通过设置SerialPort 类的属性来进行。串口属性主要包括
.PortName 串口名称,COM1, COM2等。
.BaudRate 波特率,也就是串口通讯的速度,进行串口通讯的双方其波特率需要相同,如果用PC连接其他非PC系统,一般地,波特率由非PC系统决定。
.ReadTimeout超时时间。
.Parity 奇偶校验。可以选取枚举Parity中的值
.DataBits 数据位
.StopBits 停止位,可以选取枚举StopBits中的值
.Handshake 握手方式,也就是数据流控制方式,可以选取枚举Handshake中的值 - 事件DataReceived
SerialPort 提供了DataReceived事件。当有数据进入时,该事件被触发。该事件的触发由操作系统决定,当有数据到达时,该事件在辅助线程中被触发。辅助线程的优先级比较低,因此并不能确保每个字节的数据到达时,该事件都被触发。
在使用该事件接收数据时,最好对定义通讯协议格式,添加桢头和桢尾。在DataReceived事件中接收数据时,把数据放在数组中或字符串中缓冲起来,当接收的包含桢头和桢尾的完整数据时,再进行处理。 -
解析Gps信息
外置gps设备数据的获取
public class UsbNmeaGpsHelper : IGpsHelper { private SerialPort serialPort = null; private Object lockOjb2 = new object(); private string currentPortName = ""; private int currentReadTimeout = 2000; private int currentBaudRate = 4800; private double latitude = 0; /// <summary> /// 最新纬度 /// </summary> public double Latitude { get { return latitude; } } private double longitude = 0; /// <summary> /// 最新经度 /// </summary> public double Longitude { get { return longitude; } } private GeoPositionDeviceStatus lastGeoPositionStatus = GeoPositionDeviceStatus.NoData; /// <summary> /// gps最新状态 /// </summary> public GeoPositionDeviceStatus LastGeoPositionStatus { get { return lastGeoPositionStatus; } } private DateTime lastTimestamp = DateTime.Now; /// <summary> /// 数据时间 /// </summary> public DateTime LastTimestamp { get { return lastTimestamp; } } public UsbNmeaGpsHelper(string portName, int baudRate, int readTimeout) { currentPortName = portName; currentBaudRate = baudRate; currentReadTimeout = readTimeout; } public UsbNmeaGpsHelper(string portName) : this(portName, 4800, 2000) { } /// <summary> /// 打开端口,开始监测 /// </summary> public void Start() { if (serialPort == null) { lock (lockOjb2) { serialPort = new SerialPort(); /// 名称不能错 serialPort.PortName = currentPortName; /// 需要设置超时,要不会阻塞 serialPort.ReadTimeout = currentReadTimeout; /// 波特率不能错,要不读不到数据 serialPort.BaudRate = currentBaudRate; /// 获取数据 serialPort.DataReceived += serialPort_DataReceived; /// 打开端口 serialPort.Open(); } } else { if (serialPort.IsOpen) { serialPort.Close(); } serialPort.Open(); } } void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { try { String txt = serialPort.ReadLine(); HandleMsg(txt); } catch (Exception exp) { System.Diagnostics.Trace.WriteLine(exp.Message); } } /// <summary> /// gps数据解析,只获取需要的数据 /// 当前设备的频率为1秒一次 /// </summary> /// <param name="msg"></param> private void HandleMsg(string msg) { /// 根据GPGGA取出全部信息 if (msg.StartsWith("$GPRMC") && msg[msg.Length - 4] == '*') { String[] infos = msg.Split(','); if (infos.Length == 13 || infos.Length == 12) { ///ddmmyy(日月年)hhmmss.sss(时分秒.毫秒) string timeText = infos[9] + infos[1]; DateTime utcDt = DateTime.UtcNow; try { DateTime? parseDt = DateTimeHelper.ParseDateTime(timeText, "ddMMyyHHmmss.fff"); if (parseDt.HasValue) { utcDt = parseDt.Value; } } catch (Exception ex) { System.Diagnostics.Trace.WriteLine(msg + Environment.CommandLine + ex.ToString()); } utcDt = utcDt.ToLocalTime(); lastTimestamp = utcDt; string GPSStateText = infos[2]; if (GPSStateText == "A") { lastGeoPositionStatus = GeoPositionDeviceStatus.Ready; } else { lastGeoPositionStatus = GeoPositionDeviceStatus.NoData; } string latText = infos[3]; latitude = ConvertToJWD(latText, 2); string latNSText = infos[4]; string lonText = infos[5]; longitude = ConvertToJWD(lonText, 3); string lonEWText = infos[6]; string velocityText = infos[7]; string northAngleText = infos[8]; } } } /// <summary> /// 经纬度转化 /// </summary> /// <param name="value"></param> /// <param name="index"></param> /// <returns></returns> private double ConvertToJWD(String value, Int32 index) { try { Int32 du = DbObjectConverter.ToInt(value.Substring(0, index)); Double fen = Math.Round(DbObjectConverter.ToDouble(value.Substring(index)) / 60, 8); return du + fen; } catch { return 0; } } /// <summary> /// 关闭端口 /// </summary> public void Stop() { if (serialPort != null) { serialPort.Close(); } } }
内置gps设备数据的获取
public class GpsBuildinWatcherHelper : IGpsHelper { private GeoCoordinateWatcher geoCoordinateWatcher; private Object lockOjb2 = new object(); private double latitude = 0; public double Latitude { get { return latitude; } } private double longitude = 0; public double Longitude { get { return longitude; } } private GeoPositionDeviceStatus lastGeoPositionStatus = GeoPositionDeviceStatus.NoData; public GeoPositionDeviceStatus LastGeoPositionStatus { get { return lastGeoPositionStatus; } } private DateTime lastTimestamp = DateTime.Now; public DateTime LastTimestamp { get { return lastTimestamp; } } //检测到位置更改时 //当定位服务已准备就绪并接收数据时,它将开始引发 PositionChanged 事件 public void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e) { latitude = e.Position.Location.Latitude; longitude = e.Position.Location.Longitude; lastTimestamp = e.Position.Timestamp.LocalDateTime; } //当位置服务状态发生变化时 //在 GeoPositionStatusChangedEventArgs 对象中传递的 GeoPositionStatus 枚举获取该服务的当前状态。 //可以使用它在应用程序中启用基于位置的功能,以及将服务的当前状态通知给用户。 public void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e) { switch (e.Status) { //如果服务的状态为 Disabled,则可以检查 Permission 属性,看用户是否禁用了应用程序的定位服务功能。 case GeoPositionStatus.Disabled: if (geoCoordinateWatcher.Permission == GeoPositionPermission.Denied) { lastGeoPositionStatus = GeoPositionDeviceStatus.Denied; } else { lastGeoPositionStatus = GeoPositionDeviceStatus.Disabled; } break; case GeoPositionStatus.Initializing: // 位置服务正在尝试获取数据 lastGeoPositionStatus = GeoPositionDeviceStatus.Initializing; break; case GeoPositionStatus.NoData: lastGeoPositionStatus = GeoPositionDeviceStatus.NoData; break; case GeoPositionStatus.Ready: lastGeoPositionStatus = GeoPositionDeviceStatus.Ready; break; } } public GpsBuildinWatcherHelper(GeoPositionAccuracy desiredAccuracy, double movementThreshold) { currentDesiredAccuracy = desiredAccuracy; currentMovementThreshold = movementThreshold; } public GpsBuildinWatcherHelper() : this(GeoPositionAccuracy.High, 5) { } private GeoPositionAccuracy currentDesiredAccuracy = GeoPositionAccuracy.Default; private double currentMovementThreshold = 0; public void Start() { if (geoCoordinateWatcher == null) { lock (lockOjb2) { geoCoordinateWatcher = new GeoCoordinateWatcher(currentDesiredAccuracy); // 采用高精度 geoCoordinateWatcher.MovementThreshold = currentMovementThreshold; // PositionChanged事件之间传送的最小距离 geoCoordinateWatcher.StatusChanged += new EventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged); geoCoordinateWatcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged); geoCoordinateWatcher.Start();//开始使用位置服务 } } else//方便测试,实际使用需要注意 { geoCoordinateWatcher.Start();//开始使用位置服务 } } public void Stop() { if (geoCoordinateWatcher != null) { lock (lockOjb2) { geoCoordinateWatcher.PositionChanged -= new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged); geoCoordinateWatcher.Stop(); geoCoordinateWatcher.StatusChanged -= new EventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged); geoCoordinateWatcher.Dispose(); geoCoordinateWatcher = null; } } } }