GPS定位发展很快,随着物联网的推广,衍生出很多GPS相关的应用万变不离其宗,主要应用的技术是GPS信号的采集、解析、将GPS信号通过4G或GPRS等传至服务器,客户端与服务器通信,获取设备位置信息,实现定位轨迹跟踪等。大概都包含这三大部分,设备、服务器后台、客户端。

设备如下

C#编写服务器后台

C#客户端

下面逐个介绍

设备采用STM32串口接收GPS模块输出的位置信息,解析出经纬度,通过AT指令控制GPRS模块与服务器通信。硬件电路如下

单片机解析GPS模块的位置信息,一般解析GPRMC这一条就可以,解析的方法很多,可以用找字头,数逗号的方式例如下面的信息。

$GPRMC,092927.000,A,2235.9058,N,11400.0518,E,0.000,74.11,151216,,D*49 
$GPVTG,74.11,T,,M,0.000,N,0.000,K,D*0B 
$GPGGA,092927.000,2235.9058,N,11400.0518,E,2,9,1.03,53.1,M,-2.4,M,0.0,0*6B 
$GPGSA,A,3,29,18,12,25,10,193,32,14,31,,,,1.34,1.03,0.85*31 
$GPGSV,3,1,12,10,77,192,17,25,59,077,42,32,51,359,39,193,49,157,36*48 
$GPGSV,3,2,12,31,47,274,25,50,46,122,37,18,45,158,37,14,36,326,18*70 
$GPGSV,3,3,12,12,24,045,45,26,17,200,18,29,07,128,38,21,02,174,*79

char *gpsdata;int i,count;if(USART_GetITStatus(USART2,USART_IT_IDLE) == SET)     {                                                 USART2->SR;        USART2->DR;USART_ClearITPendingBit(USART2,USART_IT_IDLE); DMA_Cmd(DMA1_Channel6,DISABLE);                      //??DMA        U2_Rx_Counter = 1024 - DMA_GetCurrDataCounter(DMA1_Channel6);  //??????????                 gpsdata = strstr(U2_RX_data,"$GNRMC");if(gpsdata)    { for(i=0;i<strlen(gpsdata);i++){if(gpsdata[i]==','){count++;if(count==2){if(gpsdata[i+1]=='A'){gps_flag=1;}else{gps_n=0;gps_e=0;break;} }    if(gps_flag==1){if((count==3)&&(gpsdata[i+1]!=',')){gps_n=((gpsdata[i+1]-0x30)*100000+(gpsdata[i+2]-0x30)*10000+((gpsdata[i+3]-0x30)*100000+(gpsdata[i+4]-0x30)*10000+(gpsdata[i+6]-0x30)*1000+(gpsdata[i+7]-0x30)*100+(gpsdata[i+8]-0x30)*10+(gpsdata[i+9]-0x30))/60);}if((count==5)&&(gpsdata[i+1]!=',')){gps_e=((gpsdata[i+1]-0x30)*1000000+(gpsdata[i+2]-0x30)*100000+(gpsdata[i+3]-0x30)*10000+((gpsdata[i+4]-0x30)*100000+(gpsdata[i+5]-0x30)*10000+(gpsdata[i+7]-0x30)*1000+(gpsdata[i+8]-0x30)*100+(gpsdata[i+9]-0x30)*10+(gpsdata[i+10]-0x30))/60);            }       if(count>=13){count=0;gps_flag=0;break;}} }   }}memset(U2_RX_data,0, 1024);       DMA1_Channel6->CNDTR = 1024;                            //??????????           DMA_Cmd(DMA1_Channel6,ENABLE);                       //??DMA             }

单片机与服务器通过AT指令控制GPRS模块与服务器通信,AT指令是比较难的,开发过的会有感受,AT指令返回的状态比较多,并不是返回一种或两种结果。不但要按照正常流程一步一步发送AT指令,还要有错误返回处理。AT指令挺复杂的,特别适合用状态机处理这些流程。

switch (M26_info.state)             {case GPRS_state_Poweroff :if(AT_Delay_Timer>5){GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_SET);GPIO_SetBits(GPIOA,GPIO_Pin_1);GPIO_ResetBits(GPIOA, GPIO_Pin_7);GPIO_ResetBits(GPIOA, GPIO_Pin_4);             // Sleep}if(AT_Delay_Timer>25){GPIO_ResetBits(GPIOA,GPIO_Pin_1);GPIO_SetBits(GPIOA, GPIO_Pin_7);}               if(AT_Delay_Timer>45){GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_RESET);M26_info.state=GPRS_state_AT;AT_Timeslimite=0;AT_Delay_Timer=0;AT_overtime=0;ZC_DATA_flog=1;}        break; case GPRS_state_AT :M26_ATTR(5,30,50,"AT+IPR=115200&W\r\n","OK","","","","",GPRS_state_CREG,GPRS_state_AT);break; case GPRS_state_CREG :M26_ATTR(5,30,100,"AT+CREG?\r\n","+CREG: 0,1","+CREG: 0,5","+CREG: 0,2","+CREG: 0,3","+CREG: 0,4",GPRS_state_CSQ,GPRS_state_CREG);break;case GPRS_state_CSQ :M26_ATTR(2,30,20,"AT+CSQ\r\n","+CSQ:","","","","",GPRS_state_QIDNSIP,GPRS_state_CSQ);case GPRS_state_QIDNSIP:M26_ATTR(2,30,5,"AT+QIFGCNT=0\r\n","OK","","","","",GPRS_state_QIDEACT,GPRS_state_Poweroff);break;case GPRS_state_QIDEACT:M26_ATTR(2,2,50,"AT+QICSGP=1,\"CMMTM\"\r\n","OK","","ERROR","","",GPRS_state_QIREGAPP,GPRS_state_Poweroff);break;case GPRS_state_QIREGAPP:M26_ATTR(2,2,50,"AT+QIREGAPP\r\n","OK","","ERROR","","",GPRS_state_QIACT,GPRS_state_Poweroff);break;case GPRS_state_QIACT:M26_ATTR(10,2,300,"AT+QIACT\r\n","OK","","ERROR","","",GPRS_state_QIOPEN,GPRS_state_Poweroff);break;case GPRS_state_QIOPEN:M26_ATTR(20,10,50,"AT+QIOPEN=\"TCP\",\"122.51.33.246\",\"8888\"\r\n","CONNECT OK","ALREADY CONNECT","ERROR","CONNECT FAIL","",GPRS_state_QISEND,GPRS_state_QIACT);break;case GPRS_state_QISTAT:M26_ATTR(10,10,500,"AT+QISTAT\r\n","STATE: CONNECT OK","","STATE: IP INITIAL","","",GPRS_state_QISEND,GPRS_state_QIOPEN);break;case GPRS_state_QISEND:GPRS_DATA_flog=1;M26_ATTR(50,20,100,"AT+QISEND=27\r\n",">",">","ERROR","ERROR","ERROR",GPRS_state_QISENDDATA,GPRS_state_QISENDDATA);break;case GPRS_state_QISENDDATA:M26_senddata(10,10,100,"12345678","SEND OK","","ERROR","ERROR","ERROR",GPRS_state_QISEND,GPRS_state_Poweroff);break;default:  ; }

服务器后台

用C#编写服务器后台程序,他负责接收所有设备发来数据,把与客户端有关的设备数据转发给客户端。这样局域网里的客户端可以通过网关获取服务器的数据。服务器程序用到多线程技术,可以同时处理多个设备发来的数据。用到了Dictionary数据类型,实现设备ID与socket对应,关键代码如下

private void ReceiveClient(object obj){Socket _ClientSocket = (Socket)obj;while (true){try{byte[] result = new byte[1024];int receiveLength = _ClientSocket.Receive(result);             string clientMessage = Encoding.UTF8.GetString(result, 0, receiveLength);string Destination_Address;string Data_Rcve;if (receiveLength == 0){ClientSocketDictionary.Remove(_ClientSocket);_ClientSocket.Shutdown(SocketShutdown.Both);_ClientSocket.Close();SetText2box();break;}else{if ((result[0] == '$') && (result[1] == '2'))//发送数据 目的地址{Destination_Address = clientMessage.Substring(2, 10);Data_Rcve = clientMessage.Substring(12, clientMessage.Length-12);temp = DateTime.Now.ToString()+ " Dest is : " + Destination_Address + "  Data is : " + Data_Rcve;SetTextbox();SendMessage(clientMessage);}if ((result[0] == '$') && (result[1] == '1'))//注册ID  源地址{if (!ClientSocketDictionary.ContainsKey(_ClientSocket)){ClientSocketDictionary.Add(_ClientSocket, clientMessage.Substring(2, 10));SetText2box();}else{ClientSocketDictionary.Remove(_ClientSocket);ClientSocketDictionary.Add(_ClientSocket, clientMessage.Substring(2, 10));SetText2box();}                                        }}}catch (Exception e){ClientSocketDictionary.Remove(_ClientSocket);_ClientSocket.Shutdown(SocketShutdown.Both);_ClientSocket.Close();SetText2box();SetText3box(e);break;}}}
public void SendMessage(string msg){if (msg == string.Empty || this.ClientSocketDictionary.Count <= 0) return;string Destination_Address = msg.Substring(2, 10);string Data_Rcve = msg.Substring(12, msg.Length-12);msg = "$3" + Destination_Address + Data_Rcve;try{foreach (KeyValuePair<Socket, string> kvp in ClientSocketDictionary){if(kvp.Value.Substring(0,10)== Destination_Address){kvp.Key.Send(Encoding.UTF8.GetBytes(msg));}              }}catch (Exception e){SetText3box(e);}}      

客户端

C#编写客户端程序,调用百度地图API,实现地图打标,绘制轨迹。客户端工作流程是这样的,首先向服务器发送注册自身ID,然后向服务器获取相关设备ID的数据,解析数据,调用百度地图API实现打标定位等。关键代码如下

 private void button1_Click(object sender, EventArgs e){try{clientScoket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);clientScoket.Connect(new IPEndPoint(IPAddress.Parse(textBox1.Text.ToString()), 8888));t = new Thread(ReceiveMessage);//开启线程执行循环接收消息t.IsBackground=true;t.Start();button1.Text = "已连接服务器";button1.Enabled = false;}catch (Exception ex){SetText3box(ex);button1.Text = "无法连接服务器";button1.Enabled = true;}}public delegate void CallSetTextbox(string ms);void ReceiveMessage()//接收消息{string Destination_Address;string Data_Rcve;send_flog = 1;while (true){if (clientScoket.Connected == true){if (send_flog == 1){send_flog = 0;message = "$1" + textBox4.Text;SendMessage(message);}int length = 0;try{length = clientScoket.Receive(data);}catch (Exception e){SetText3box(e);break;}if (length != 0){message = Encoding.UTF8.GetString(data, 0, length);if ((data[0] == '$') && (data[1] == '3'))//配置ID{Destination_Address = message.Substring(2, 10);Data_Rcve = message.Substring(12, message.Length - 12);Longitude = Data_Rcve.Substring(0, 8);Latitude = Data_Rcve.Substring(8, 7);if ((Longitude != "000.0000") && (Latitude != "00.0000")){SetTextbox(DateTime.Now.ToString() + " Dest is : " + Destination_Address + "  Data is : " + Data_Rcve);}SetText2box(DateTime.Now.ToString() + " Dest is : " + Destination_Address + "  Data is : " + Data_Rcve);}}}else{break;}}

STM32开发GPRS传输的GPS定位器 C#编写服务器转发程序,客户端显示轨迹相关推荐

  1. NBIOT 移远BC28模块+stm32开发板例程、教程(打通TCP、COAP协议)

    为了开发者能够快速入门BC28的开发,加快开发者的项目进度,开发出此款针对BC28的stm32开发板和完善的发送网络数据的示例程序(TCP协议.COAP协议),程序流程逻辑清楚,注释完善,上手就可以玩 ...

  2. 大白NBIOT 移远BC28模块+stm32开发板例程、教程(打通TCP、COAP协议)

    大白为了开发者能够快速入门BC28的开发,加快开发者的项目进度,大白开发出此款针对BC28的stm32开发板和完善的发送网络数据的示例程序(TCP协议.COAP协议),程序流程逻辑清楚,注释完善,上手 ...

  3. STM32开发 -- Ublox GPS之设置PUBX

    如需转载请注明出处:https://juyou.blog.csdn.net/article/details/99678012 STM32开发 – GPS模块开发详解 之前获取GPS所需内容需要解析多个 ...

  4. 服务器如何接收GPS定位器发送过来的数据

    GPS定位器内部分两部分,一部分是定位系统,是通过接收天空卫星信号而运算出定位器所在的地理坐标,这个信号只要能看到天空的地方,就可以搜到. 第二部分是通讯系统,是将定位系统运算出来的坐标信息.车子状态 ...

  5. 野火洋桃STM32开发版学习指导完整版

    该文章是我历时一个月整理总结而成,专门针对想要通过野火&洋桃STM32开发板入门stm32的读者.由于csdn编辑限制,该学习指导只包含文字信息.如需查看含图片的完整版可进入我的博客下载页.完 ...

  6. STM32开发 -- 地球坐标系(WGS84),火星坐标系(GCJ02), 百度坐标系(BD09)坐标转换

    如需转载请注明出处:https://juyou.blog.csdn.net/article/details/99599071 STM32开发 – GPS模块开发详解 最后有提到一下: WGS84坐标系 ...

  7. STM32开发 -- 惯导模块开发详解

    如需转载请注明出处:https://juyou.blog.csdn.net/article/details/93476976 STM32开发 – GPS模块开发详解 这篇文章已经对于GPS模块开发讲得 ...

  8. STM32开发 -- UTC、UNIX时间戳、北京时间之间的转换

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/87637350 我碰到的问题,GPS上UTC时间转北京时间和STM32上UNI ...

  9. STM32开发 -- 4G模块开发详解(3)

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/81782682 上面两篇文章,基本上把软硬件部分讲完了.接下来我们就看一下收发 ...

最新文章

  1. 什么可以搜python答案_什么软件可以搜python答案
  2. 华尔街宫斗戏升温:银行巨头和纽交所争夺交易数据所有权
  3. 在WCF中启用事务的6个步骤
  4. 关于ENSP1.2.00.510安装过程中的一点心得
  5. Java 编程之美:并发编程基础晋级篇
  6. Android ROS开发环境搭建
  7. c++使用POP协议接收以及解析邮件
  8. 手动配置网络设置静态IP地址
  9. “本地资源检测” 上手指南,玩转最前沿的优化黑科技!
  10. PHP面向对象开发:类成员的相关知识
  11. 为什么有些人拼了命也要考上985?
  12. MAME模拟器debug帮助文档汉化一(介绍)
  13. Python美股量化交易填坑记录——13c.Vegas隧道交易机器人(实盘记录)
  14. 深度探索:使用FFmpeg实现视频Logo的添加与移除
  15. CUDA学习(十一):原子操作实现向量内积
  16. scsi和iscsi区别
  17. 面试官没想到,一个SQL,我可以扯一小时
  18. ubuntu软件下载
  19. linux7怎么卸载vnc,Centos 7 安装VNC步骤
  20. 【优化模型】单服务台负指数分布排队系统分析 — M/M/1模型

热门文章

  1. 获取顺序栈的栈顶元素
  2. 模拟cmos集成电路(6)
  3. linux怎样保存文件,linux不能保存文件如何解决
  4. Vmware虚拟机无法联网?
  5. IDEA远程debug调试设置
  6. Dubbo-02 20190315
  7. 笔记本电脑C盘满了清理方法大全
  8. oa html5管理系统模板,OA系统html5整站模板 后台模板
  9. CNN与句子分类之动态池化方法DCNN--模型介绍篇
  10. 小目标---时钟的实现