小言_互联网的博客

STM32+移远MC20模块采用MQTT协议登录OneNet上传GPS数据

705人阅读  评论(0)

一、环境介绍

MCU:  STM32F103C8T6

GSM模块: 移远MC20 (MT2503D)(GSM+GPS共存)功能很强大

开发软件: Keil5

MQTT协议采用OneNet的旧版协议,登录OneNet控制台创建应用时要选择旧版本。

如果想使用新版本的标准MQTT协议连接OnetNet请参考这里:  https://blog.csdn.net/xiaolong1126626497/article/details/107385118

完整源代码下载:  https://download.csdn.net/download/xiaolong1126626497/18245206

二、MC20模块

 

MC20模块采用联发科技最新推出的多功能通信定位芯片研制而成。它是一款集成LCC封装、四频段GSM/GPRS和先进算法GNSS引擎于一体的全功能通信模块,具有超小体积、低功耗、双卡单待等优势。MC20不仅内嵌丰富的网络协议(如 TCP、UDP、PPP、FTP、HTTP以及SSL),还集成了多星座卫星系统(如北斗、GPS、QZSS),因此能提供无线移动通信以及精准的导航定位功能。

除具备GSM/GPRS无线通信功能外,MC20模块还支持先进的GNSS技术。它集成了EPOTM(用户无需自设服务器,直接从MTK服务器获取EPO数据)、秒定等技术,能够实现快速首次定位。由于支持北斗、GPS、QZSS等多星座卫星系统解调算法,其定位更加精准,抗多路径干扰能力更强,比传统GPS模块具有更多优势。另外,MC20模块中内置LNA和低功耗算法:前者使其接收灵敏度提升至-149dBm;后者使其在低功耗模式(GLP Mode)下的耗流仅为正常工作模式的40%。

MC20模块较传统GSM+GNSS方案体积减少40%,使其在各种应用中占具更大优势。其主要应用领域为:可穿戴设备(智能手表)、宠物追踪、财产追踪及行车记录仪等等。
主要优势
● 超小体积: 18.7mm × 16.0mm × 2.1mm
● 多卫星导航系统: GPS/BeiDou/QZSS
● GNSS 接收机通道: 99 路捕获通道/33 路跟踪通道
● 支持多种 AGPS 技术,如 EASYTM 、EPOTM 、秒定等
● 内置 LNA 大大提升 GNSS 接收机灵敏度(-167dBm@跟踪模式):可使用无源 GNSS 天线而无需任何外部低噪声放大器
● 支持增强型 GNSS 功能,如 SDK 命令、LOCUSTM 、AIC 和 GLP
● 多功能四频段 GSM模块: 850/900/1800/1900MHz
● 内嵌丰富网络协议: TCP/UDP/PPP/HTTP/FTP/SSL
● 支持语音、短信、QuecFOTATM 、双卡单待以及 OpenCPU 功能
● 支持蓝牙 V3.0 以及 SPP & HFP-AG 配置文件


三、代码功能

使用STM32F103C8T6 通过串口+AT指令控制MC20模块+MQTT协议,登录OneNet服务器上传GPS数据,LED控制(网页按钮控制开发板上的LED灯)。

四、核心代码

4.1 main.c


  
  1. #include "stm32f10x.h"
  2. #include "beep.h"
  3. #include "delay.h"
  4. #include "led.h"
  5. #include "sys.h"
  6. #include "usart.h"
  7. #include <string.h>
  8. #include <stdio.h>
  9. #include "timer.h"
  10. #include "mc20.h"
  11. //网络协议层
  12. #include "onenet.h"
  13. //协议封装文件
  14. #include "dStream.h"
  15. //产品ID
  16. char PROID[]= "231174";
  17. //鉴权信息
  18. char AUTH_INFO[]= "1234567890";
  19. //设备ID
  20. char DEVID[]= "523369555";
  21. //API KEY
  22. char API_KEY[]= "k6vtrrEd1H7UMddiF3DzripS47w=";
  23. //缓冲区
  24. char onenet_http_cmd[ 1024];
  25. //服务器IP地址
  26. #define TCP_SERVER_IP_ADDR "183.230.40.39"
  27. //服务器端口号
  28. #define TCP_SERVER_PORT 6002
  29. //数据流结构
  30. DATA_STREAM data_stream[ 1]=
  31. {
  32. { "gps", "88.88",TYPE_JSON, 1},
  33. };
  34. /*
  35. STM32开发板接线说明:
  36. STM32 MC20
  37. 3.3V ------> V_IO
  38. GND <-----> GND
  39. PA3 <------ GSM_TX
  40. PA2 ------> GSM_RX
  41. */
  42. int main()
  43. {
  44. u32 time_cnt= 0;
  45. u32 cnt= 0;
  46. double Longitude; //经度
  47. double latitude; //纬度
  48. LED_Init();
  49. BEEP_Init();
  50. USART_X_Init(USART1, 72, 115200);
  51. TIM2_Init( 72, 20000); //辅助串口2接收,超时时间为20ms
  52. USART_X_Init(USART2, 36, 9600); //连接着MC20(GPS+GPRS)
  53. printf( "串口准备就绪.....\r\n");
  54. DelayMs( 500);
  55. printf( "程序修改时间: %s\r\n",__TIME__);
  56. while( 1)
  57. {
  58. u8 stat;
  59. /*初始化MC20,并连接到指定服务器*/
  60. MC20_InitConnect(TCP_SERVER_IP_ADDR,TCP_SERVER_PORT);
  61. /*登录OneNET服务器,上线设备*/
  62. stat=OneNet_DevLink();
  63. if(stat) printf( "ERROR:%d,接入OneNET失败:%d\r\n",stat,cnt++);
  64. else break; //登录成功
  65. LED1=!LED1;
  66. delay_ms( 200);
  67. break; //失败也退出继续运行下面代码
  68. }
  69. printf( "6. OneNET服务器登录成功!\r\n");
  70. delay_ms( 100);
  71. while( 1)
  72. {
  73. /*6. 向OneNet服务器5秒发送一次数据*/
  74. time_cnt++;
  75. DelayMs( 1);
  76. if(time_cnt>= 5000)
  77. {
  78. time_cnt= 0;
  79. /*获取一次GPS输出的经纬度信息*/
  80. switch(MC20_GetGPS_Data(&Longitude,&latitude))
  81. {
  82. case 0: printf( "经度:%f,纬度:%f\r\n",Longitude,latitude); break;
  83. case 1: printf( "ERROR:GPS数据接收失败!\r\n"); break;
  84. case 2: printf( "ERROR:GPS定位数据解码失败!<请将GPS拿到空旷位置定位>\r\n"); break;
  85. }
  86. //组装数据格式
  87. sprintf(onenet_http_cmd, "{\"lon\":%f,\"lat\":%f}",Longitude,latitude);
  88. data_stream[ 0].dataPoint=onenet_http_cmd; //赋值GPS数据
  89. //向云端发送数据流
  90. OneNet_SendData(FORMAT_TYPE1,DEVID,API_KEY,data_stream, 1);
  91. }
  92. /*实时接收MC20收到的数据,进行解析*/
  93. if(USART2_RX_FLAG)
  94. {
  95. USART2_RX_BUFF[USART2_RX_CNT]= '\0';
  96. printf( "USART2_RX_BUFF=%s\r\n",USART2_RX_BUFF); //向串口打印信息
  97. //解析平台返回的数据
  98. OneNet_RevPro(USART2_RX_BUFF);
  99. USART2_RX_CNT= 0;
  100. USART2_RX_FLAG= 0;
  101. memset(USART2_RX_BUFF, 0, sizeof(USART2_RX_BUFF));
  102. }
  103. }
  104. }

 

4.2  mc20.c


  
  1. #include "mc20.h"
  2. /*
  3. 函数功能:向MC20模块发送指令
  4. 函数参数:
  5. char *cmd 发送的命令
  6. char *check_data 检测返回的数据
  7. 返回值: 0表示成功 1表示失败
  8. */
  9. u8 MC20_SendCmd(char *cmd,char *check_data)
  10. {
  11. u16 i,j;
  12. for(i= 0;i< 5;i++) //测试的总次数
  13. {
  14. USART2_RX_FLAG= 0;
  15. USART2_RX_CNT= 0;
  16. memset(USART2_RX_BUFF, 0, sizeof(USART2_RX_BUFF));
  17. USART_X_SendString(USART2,cmd); //发送指令
  18. for(j= 0;j< 500;j++) //等待的时间(ms单位)
  19. {
  20. if(USART2_RX_FLAG)
  21. {
  22. USART2_RX_BUFF[USART2_RX_CNT]= '\0';
  23. if( strstr(( char*)USART2_RX_BUFF,check_data))
  24. {
  25. return 0;
  26. }
  27. else break;
  28. }
  29. delay_ms( 10); //一次的时间
  30. }
  31. }
  32. return 1;
  33. }
  34. /*
  35. 函数功能: MC20初始化检查
  36. */
  37. u8 MC20_InitCheck(void)
  38. {
  39. return MC20_SendCmd( "AT\r\n", "OK\r\n");
  40. }
  41. /*
  42. 函数功能: 开启GPS功能
  43. 返 回 值:0表示成功 1表示失败
  44. */
  45. u8 MC20_StartGPS(void)
  46. {
  47. //先判断GPS功能是否启动
  48. if(MC20_SendCmd( "AT+QGNSSC?\r\n", "+QGNSSC: 1"))
  49. {
  50. //没有启动就启动GPS功能
  51. if(MC20_SendCmd( "AT+QGNSSC=1\r\n", "OK\r\n"))
  52. {
  53. return 1; //GPS功能启动失败
  54. }
  55. }
  56. return 0;
  57. }
  58. /*
  59. 函数功能:从buf里面得到第cnt个逗号所在的位置
  60. 返 回 值:0~254,代表逗号所在位置的偏移.
  61. 255,代表不存在第cnt个逗号
  62. */
  63. u8 GPS_GetCommaOffset(char *buf,u8 cnt)
  64. {
  65. char *p=buf;
  66. while(cnt)
  67. {
  68. if(*buf== '*'||*buf< ' '||*buf> 'z') return 255; //遇到'*'或者非法字符,则不存在第cx个逗号
  69. if(*buf== ',')cnt--;
  70. buf++;
  71. }
  72. return buf-p; //计算偏移量
  73. }
  74. /*
  75. 函数功能: 获取GPS经纬度数据值
  76. 函数参数:
  77. double *Longitude :经度
  78. double *latitude :纬度
  79. 返回值: 0表示定位成功,1表示定位失败
  80. 说明: 解析$GNRMC命令,得到经纬度
  81. $GNRMC,023705.000,A,2842.4164,N,11549.5713,E,1.73,91.65,150319,,,A*41
  82. 转换公式示例:
  83. 经度: dddmm.mmmm 东经 11408.4790 114+(08.4790/60)=114.141317
  84. 纬度: ddmm.mmmm 北纬 2236.9453 22+(36.9453/60)= 22.615755
  85. */
  86. u8 GPS_GNRMC_Decoding(char *gps_buffer,double *Longitude,double *latitude)
  87. {
  88. u8 Offset;
  89. u32 int_data;
  90. double s_Longitude,s_latitude;
  91. char *p;
  92. /*1. 确定下定位是否成功*/
  93. p= strstr(gps_buffer, "$GNRMC");
  94. if(!p) return 1;
  95. Offset=GPS_GetCommaOffset(p, 2);
  96. if(Offset== 255) return 2;
  97. if(*(p+Offset)!= 'A') return 3; //定位不准确
  98. /*2. 得到纬度*/
  99. Offset=GPS_GetCommaOffset(p, 3);
  100. if(Offset== 255) return 4;
  101. sscanf(p+Offset, "%lf",&s_latitude);
  102. s_latitude=s_latitude/ 100;
  103. int_data=s_latitude; //得到纬度整数部分
  104. s_latitude=s_latitude-int_data; //得到纬度小数部分
  105. s_latitude=(s_latitude)* 100;
  106. *latitude=int_data+(s_latitude/ 60.0); //得到转换后的值
  107. /*3. 得到经度*/
  108. Offset=GPS_GetCommaOffset(p, 5);
  109. if(Offset== 255) return 5;
  110. sscanf(p+Offset, "%lf",&s_Longitude);
  111. s_Longitude=s_Longitude/ 100;
  112. int_data=s_Longitude; //得到经度整数部分
  113. s_Longitude=s_Longitude-int_data; //得到经度小数部分
  114. s_Longitude=s_Longitude* 100;
  115. *Longitude=int_data+(s_Longitude/ 60.0);
  116. return 0;
  117. }
  118. /*
  119. 函数功能: 获取一次GPS经纬度数据
  120. 函数参数:
  121. double *Longitude :经度
  122. double *latitude :纬度
  123. 返回值: 0表示定位成功,1表示数据接收失败,2表示定位失败
  124. */
  125. u8 MC20_GetGPS_Data(double *Longitude,double *latitude)
  126. {
  127. /*1. 发送获取GPS数据的指令*/
  128. if(MC20_SendCmd( "AT+QGNSSRD=\"NMEA/RMC\"\r\n", "OK\r\n")) return 1;
  129. /*2. 对GPS数据进行解码*/
  130. if(GPS_GNRMC_Decoding(( char *)USART2_RX_BUFF,Longitude,latitude)) return 2;
  131. //解码成功
  132. return 0;
  133. }
  134. /*
  135. 函数功能: 连接服务器
  136. 函数参数:
  137. char *server_ip 服务器IP地址
  138. u16 port 服务器端口号
  139. 返回值: 0表示连接成功,1表示连接失败
  140. */
  141. u8 MC20_Connect_TCP_Server(char *server_ip,u16 port)
  142. {
  143. char send_buf[ 100]={ 0};
  144. sprintf(send_buf, "AT+QIOPEN=\"TCP\",\"%s\",\"%d\"\r\n",server_ip,port);
  145. //连接至服务器
  146. if(MC20_SendCmd(send_buf, "CONNECT"))
  147. {
  148. return 1; //连接失败
  149. }
  150. return 0; //连接成功
  151. }
  152. /*
  153. 函数功能: 向服务器发送数据
  154. 函数参数:
  155. u8 *buffer 发送的数据
  156. u32 len 发送的长度
  157. 返 回 值: 0表示发送成功,1表示准备发送失败,2表示数据发送失败
  158. */
  159. u8 MC20_ClientSendData(u8 *buffer,u32 len)
  160. {
  161. char send_buf[ 2];
  162. /*1. 准备发送数据*/
  163. if(MC20_SendCmd( "AT+QISEND\r\n", ">"))
  164. {
  165. printf( "AT+QISEND->ERROR Info:%s\r\n",USART2_RX_BUFF);
  166. return 1;
  167. }
  168. /*2. 开始发送数据*/
  169. USART_X_SendData(USART2,buffer,len);
  170. delay_ms( 20);
  171. /*3. 发送结束符*/
  172. send_buf[ 0] = 0x1a;
  173. send_buf[ 1] = '\0';
  174. if(MC20_SendCmd(send_buf, "OK\r\n"))
  175. {
  176. printf( "发送结束符->ERROR Info:%s\r\n",USART2_RX_BUFF);
  177. return 2;
  178. }
  179. return 0;
  180. }
  181. /*
  182. 函数功能: MC20初始化检查并连接至服务器
  183. */
  184. #include "led.h"
  185. void MC20_InitConnect(char *server_ip,u16 port)
  186. {
  187. /*1. MC20模块初始化检查*/
  188. while(MC20_InitCheck())
  189. {
  190. LED1=!LED1;
  191. printf( "ERROR:MC20模块初始化检查失败!\r\n");
  192. delay_ms( 100);
  193. }
  194. printf( "1. MC20模块初始化成功!\r\n");
  195. delay_ms( 100);
  196. /*2. 查询是否有PIN码锁定*/
  197. while(MC20_SendCmd( "AT+CPIN?\r\n", "READY"))
  198. {
  199. LED1=!LED1;
  200. printf( "ERROR:PIN码锁定检查失败!\r\n");
  201. delay_ms( 100);
  202. }
  203. printf( "2. PIN码锁定检查成功!\r\n");
  204. delay_ms( 100);
  205. /*3. 查询SIM卡网络注册信息*/
  206. if(MC20_SendCmd( "AT+CREG?\r\n", ",1")) //本地SIM卡
  207. {
  208. if(MC20_SendCmd( "AT+CREG?\r\n", ",5")) //漫游SIM卡
  209. {
  210. printf( "ERROR:查询SIM卡网络注册信息失败!\n");
  211. }
  212. else printf( "3. 漫游SIM卡网络注册成功!\n");
  213. }
  214. else printf( "3. 本地SIM卡网络注册成功!\n");
  215. delay_ms( 100);
  216. /*4. 启动GPS功能*/
  217. if(MC20_StartGPS())
  218. {
  219. printf( "ERROR:GPS功能启动失败!\n");
  220. }
  221. else printf( "4. GPS功能启动成功!\n");
  222. delay_ms( 100);
  223. /*5. 连接指定服务器*/
  224. while(MC20_Connect_TCP_Server(server_ip,port))
  225. {
  226. printf( "ERROR: 连接TCP服务器失败!\r\n现在正在断开服务器,进行重连!\r\n需要保证服务器地址正确,并且SIM卡可以上网\r\n");
  227. /*先断开服务器连接 (如果之前没有连接过服务器,这里就会出现错误)*/
  228. MC20_SendCmd( "AT+QICLOSE\r\n", "OK\r\n");
  229. delay_ms( 100);
  230. MC20_SendCmd( "AT+QIDEACT\r\n", "OK\r\n");
  231. delay_ms( 100);
  232. }
  233. printf( "5. 连接TCP服务器成功!\n");
  234. delay_ms( 100);
  235. }

4.2 mc20.h


  
  1. #ifndef _MC20_H
  2. #define _MC20_H
  3. #include "stm32f10x.h"
  4. #include "usart.h"
  5. #include "delay.h"
  6. #include <string.h>
  7. u8 MC20_SendCmd(char *cmd,char *check_data);
  8. u8 MC20_InitCheck(void);
  9. u8 MC20_StartGPS(void);
  10. u8 MC20_GetGPS_Data(double *Longitude,double *latitude);
  11. u8 MC20_Connect_TCP_Server(char *server_ip,u16 port);
  12. u8 MC20_ClientSendData(u8 *buffer,u32 len);
  13. void MC20_InitConnect(char *server_ip,u16 port);
  14. #endif

五、OneNet创建产品

链接地址:  https://open.iot.10086.cn/develop/global/product/#/console

 

 

 


转载:https://blog.csdn.net/xiaolong1126626497/article/details/116298805
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场