天天看點

STM32+移遠MC20子產品采用MQTT協定登入OneNet上傳GPS資料

一、環境介紹

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子產品
STM32+移遠MC20子產品采用MQTT協定登入OneNet上傳GPS資料
STM32+移遠MC20子產品采用MQTT協定登入OneNet上傳GPS資料
STM32+移遠MC20子產品采用MQTT協定登入OneNet上傳GPS資料

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

#include "stm32f10x.h"
#include "beep.h"
#include "delay.h"
#include "led.h"
#include "sys.h"
#include "usart.h"
#include <string.h>
#include <stdio.h>
#include "timer.h"
#include "mc20.h"
 
//網絡協定層
#include "onenet.h"
 
//協定封裝檔案
#include "dStream.h"
 
//産品ID
char PROID[]="231174";
 
//鑒權資訊
char AUTH_INFO[]="1234567890";
 
//裝置ID
char DEVID[]="523369555";
 
//API KEY
char API_KEY[]="k6vtrrEd1H7UMddiF3DzripS47w=";
 
//緩沖區
char onenet_http_cmd[1024];
 
//伺服器IP位址
#define TCP_SERVER_IP_ADDR "183.230.40.39"
 
//伺服器端口号
#define TCP_SERVER_PORT 6002
 
 
//資料流結構
DATA_STREAM data_stream[1]=
{
    {"gps","88.88",TYPE_JSON,1},
};
 
 
/*
    STM32開發闆接線說明:
    STM32                   MC20
    3.3V    ------> V_IO
    GND     <-----> GND
    PA3     <------ GSM_TX
    PA2     ------> GSM_RX
*/
 
int main()
{   
    u32 time_cnt=0;
    u32 cnt=0;
    double Longitude; //經度
    double latitude;  //緯度
  
    LED_Init();
  BEEP_Init();
    USART_X_Init(USART1,72,115200);
  TIM2_Init(72,20000);                  //輔助序列槽2接收,逾時時間為20ms
  USART_X_Init(USART2,36,9600); //連接配接着MC20(GPS+GPRS)
  
    printf("序列槽準備就緒.....\r\n");
    DelayMs(500);
    
    printf("程式修改時間: %s\r\n",__TIME__);
  while(1)
  {
         u8 stat;
        /*初始化MC20,并連接配接到指定伺服器*/
         MC20_InitConnect(TCP_SERVER_IP_ADDR,TCP_SERVER_PORT);
         
         /*登入OneNET伺服器,上線裝置*/
         stat=OneNet_DevLink();
         if(stat)printf("ERROR:%d,接入OneNET失敗:%d\r\n",stat,cnt++);
         else break; //登入成功
         
         LED1=!LED1;
     delay_ms(200); 
        
         break;//失敗也退出繼續運作下面代碼
  }
    printf("6. OneNET伺服器登入成功!\r\n");
    delay_ms(100);
    
    while(1)
    { 
        /*6. 向OneNet伺服器5秒發送一次資料*/
         time_cnt++;
         DelayMs(1);
         if(time_cnt>=5000)
         {
                    time_cnt=0;
                    /*擷取一次GPS輸出的經緯度資訊*/
                    switch(MC20_GetGPS_Data(&Longitude,&latitude))
                    {
                     case 0: printf("經度:%f,緯度:%f\r\n",Longitude,latitude); break;
                     case 1: printf("ERROR:GPS資料接收失敗!\r\n"); break;
                     case 2: printf("ERROR:GPS定位資料解碼失敗!<請将GPS拿到空曠位置定位>\r\n"); break;
                    }
                    
                    //組裝資料格式
                  sprintf(onenet_http_cmd,"{\"lon\":%f,\"lat\":%f}",Longitude,latitude);
                data_stream[0].dataPoint=onenet_http_cmd; //指派GPS資料
             
          //向雲端發送資料流
          OneNet_SendData(FORMAT_TYPE1,DEVID,API_KEY,data_stream,1);
         }
        
         /*實時接收MC20收到的資料,進行解析*/
     if(USART2_RX_FLAG)
     {
         USART2_RX_BUFF[USART2_RX_CNT]='\0';
                  printf("USART2_RX_BUFF=%s\r\n",USART2_RX_BUFF); //向序列槽列印資訊
               //解析平台傳回的資料
         OneNet_RevPro(USART2_RX_BUFF);
         USART2_RX_CNT=0;
         USART2_RX_FLAG=0;
         memset(USART2_RX_BUFF,0,sizeof(USART2_RX_BUFF));
     }
    }
}      

4.2  mc20.c

#include "mc20.h"
/*
函數功能:向MC20子產品發送指令
函數參數:
                char *cmd  發送的指令
              char *check_data 檢測傳回的資料
傳回值: 0表示成功 1表示失敗
*/
u8 MC20_SendCmd(char *cmd,char *check_data)
{
   u16 i,j;
   for(i=0;i<5;i++) //測試的總次數
   {
      USART2_RX_FLAG=0;
      USART2_RX_CNT=0;
            memset(USART2_RX_BUFF,0,sizeof(USART2_RX_BUFF));
            USART_X_SendString(USART2,cmd); //發送指令
      for(j=0;j<500;j++) //等待的時間(ms機關)
      {
          if(USART2_RX_FLAG)
          {
              USART2_RX_BUFF[USART2_RX_CNT]='\0';
              if(strstr((char*)USART2_RX_BUFF,check_data))
              {
                  return 0;
              }
              else break;
          }
          delay_ms(10); //一次的時間
      }
   }
   return 1;
}
 
 
/*
函數功能:  MC20初始化檢查
*/
u8 MC20_InitCheck(void)
{
        return MC20_SendCmd("AT\r\n","OK\r\n");
}
 
 
/*
函數功能: 開啟GPS功能
返 回 值:0表示成功  1表示失敗
*/
u8 MC20_StartGPS(void)
{
        //先判斷GPS功能是否啟動
        if(MC20_SendCmd("AT+QGNSSC?\r\n","+QGNSSC: 1")) 
        {
                //沒有啟動就啟動GPS功能
                if(MC20_SendCmd("AT+QGNSSC=1\r\n","OK\r\n"))
                {
                        return 1;  //GPS功能啟動失敗
                }
        }
        return 0;
}
 
 
/*
函數功能:從buf裡面得到第cnt個逗号所在的位置
返 回 值:0~254,代表逗号所在位置的偏移.
255,代表不存在第cnt個逗号
*/
u8 GPS_GetCommaOffset(char *buf,u8 cnt)
{
    char *p=buf;
    while(cnt)
    {
        if(*buf=='*'||*buf<' '||*buf>'z')return 255;//遇到'*'或者非法字元,則不存在第cx個逗号
        if(*buf==',')cnt--;
        buf++;
    }
    return buf-p; //計算偏移量
}
 
 
/*
函數功能: 擷取GPS經緯度資料值
函數參數:
        double *Longitude  :經度
        double *latitude   :緯度
傳回值: 0表示定位成功,1表示定位失敗
說明: 解析$GNRMC指令,得到經緯度
$GNRMC,023705.000,A,2842.4164,N,11549.5713,E,1.73,91.65,150319,,,A*41
轉換公式示例:
經度: dddmm.mmmm 東經 11408.4790 114+(08.4790/60)=114.141317
緯度: ddmm.mmmm 北緯 2236.9453 22+(36.9453/60)= 22.615755
*/
u8 GPS_GNRMC_Decoding(char *gps_buffer,double *Longitude,double *latitude)
{
    u8 Offset;
    u32 int_data;
    double s_Longitude,s_latitude;
    char *p;
 
    /*1. 确定下定位是否成功*/
    p=strstr(gps_buffer,"$GNRMC");
    if(!p)return 1;
    
    Offset=GPS_GetCommaOffset(p,2);
    if(Offset==255)return 2;
    if(*(p+Offset)!='A')return 3; //定位不準确
    
    /*2. 得到緯度*/
    Offset=GPS_GetCommaOffset(p,3);
    if(Offset==255)return 4;
    sscanf(p+Offset,"%lf",&s_latitude);
    s_latitude=s_latitude/100;
    int_data=s_latitude;//得到緯度整數部分
    s_latitude=s_latitude-int_data;//得到緯度小數部分
    s_latitude=(s_latitude)*100;
    *latitude=int_data+(s_latitude/60.0); //得到轉換後的值
    
        /*3. 得到經度*/
    Offset=GPS_GetCommaOffset(p,5);
    if(Offset==255)return 5;
    sscanf(p+Offset,"%lf",&s_Longitude);    
    s_Longitude=s_Longitude/100;
    int_data=s_Longitude;//得到經度整數部分
    s_Longitude=s_Longitude-int_data; //得到經度小數部分
    s_Longitude=s_Longitude*100;
    *Longitude=int_data+(s_Longitude/60.0);   
    return 0;
}
 
 
/*
函數功能: 擷取一次GPS經緯度資料
函數參數:
        double *Longitude  :經度
        double *latitude   :緯度
傳回值: 0表示定位成功,1表示資料接收失敗,2表示定位失敗
*/
u8 MC20_GetGPS_Data(double *Longitude,double *latitude)
{
        /*1. 發送擷取GPS資料的指令*/
        if(MC20_SendCmd("AT+QGNSSRD=\"NMEA/RMC\"\r\n", "OK\r\n"))return 1;
        
        /*2. 對GPS資料進行解碼*/
        if(GPS_GNRMC_Decoding((char *)USART2_RX_BUFF,Longitude,latitude))return 2;
        
        //解碼成功
        return 0; 
}
 
/*
函數功能: 連接配接伺服器
函數參數:
        char *server_ip  伺服器IP位址  
                u16 port  伺服器端口号
傳回值: 0表示連接配接成功,1表示連接配接失敗
*/
u8 MC20_Connect_TCP_Server(char *server_ip,u16 port)
{
         char send_buf[100]={0};
         sprintf(send_buf,"AT+QIOPEN=\"TCP\",\"%s\",\"%d\"\r\n",server_ip,port);
         
         //連接配接至伺服器
         if(MC20_SendCmd(send_buf, "CONNECT"))
         {
                return 1; //連接配接失敗
         }
         return 0; //連接配接成功
}
 
 
/*
函數功能: 向伺服器發送資料
函數參數: 
                    u8 *buffer 發送的資料
                    u32 len  發送的長度
返 回 值: 0表示發送成功,1表示準備發送失敗,2表示資料發送失敗
*/
u8 MC20_ClientSendData(u8 *buffer,u32 len)
{
      char send_buf[2];
      /*1. 準備發送資料*/
        if(MC20_SendCmd("AT+QISEND\r\n",">"))
        {
                printf("AT+QISEND->ERROR Info:%s\r\n",USART2_RX_BUFF);
                return 1; 
        }
        
        /*2. 開始發送資料*/
        USART_X_SendData(USART2,buffer,len);
        delay_ms(20);
        
        /*3. 發送結束符*/
        send_buf[0] = 0x1a;
        send_buf[1] = '\0';
        if(MC20_SendCmd(send_buf,"OK\r\n"))
        {
                printf("發送結束符->ERROR Info:%s\r\n",USART2_RX_BUFF);
                return 2;
        }
        return 0;
}
 
 
/*
函數功能: MC20初始化檢查并連接配接至伺服器 
*/
#include "led.h"
void MC20_InitConnect(char *server_ip,u16 port)
{
    /*1. MC20子產品初始化檢查*/
    while(MC20_InitCheck())
    {
            LED1=!LED1;
            printf("ERROR:MC20子產品初始化檢查失敗!\r\n");
            delay_ms(100);
    }
    printf("1. MC20子產品初始化成功!\r\n");
    delay_ms(100);
    
    /*2. 查詢是否有PIN碼鎖定*/
    while(MC20_SendCmd("AT+CPIN?\r\n","READY"))
    {
            LED1=!LED1;
            printf("ERROR:PIN碼鎖定檢查失敗!\r\n");
            delay_ms(100);
    }
    printf("2. PIN碼鎖定檢查成功!\r\n");
    delay_ms(100);
    
    /*3. 查詢SIM卡網絡注冊資訊*/
    if(MC20_SendCmd("AT+CREG?\r\n",",1"))   //本地SIM卡
    {
            if(MC20_SendCmd("AT+CREG?\r\n",",5"))//漫遊SIM卡
            {
                    printf("ERROR:查詢SIM卡網絡注冊資訊失敗!\n");
            }
            else    printf("3. 漫遊SIM卡網絡注冊成功!\n");
    }
    else    printf("3. 本地SIM卡網絡注冊成功!\n");
    delay_ms(100);
    
    /*4. 啟動GPS功能*/
    if(MC20_StartGPS())
    {
            printf("ERROR:GPS功能啟動失敗!\n");
    }
    else printf("4. GPS功能啟動成功!\n");
    delay_ms(100);
    
    /*5. 連接配接指定伺服器*/
    while(MC20_Connect_TCP_Server(server_ip,port))
    {
            printf("ERROR: 連接配接TCP伺服器失敗!\r\n現在正在斷開伺服器,進行重連!\r\n需要保證伺服器位址正确,并且SIM卡可以上網\r\n");
        
            /*先斷開伺服器連接配接 (如果之前沒有連接配接過伺服器,這裡就會出現錯誤)*/
            MC20_SendCmd("AT+QICLOSE\r\n","OK\r\n");
            delay_ms(100);
            
            MC20_SendCmd("AT+QIDEACT\r\n","OK\r\n");
            delay_ms(100);
    }
    printf("5. 連接配接TCP伺服器成功!\n");
    delay_ms(100);
}      

4.2 mc20.h

#ifndef  _MC20_H
#define  _MC20_H
#include "stm32f10x.h"
#include "usart.h"
#include "delay.h"
#include <string.h>
u8 MC20_SendCmd(char *cmd,char *check_data);
u8 MC20_InitCheck(void);
u8 MC20_StartGPS(void);
u8 MC20_GetGPS_Data(double *Longitude,double *latitude);
u8 MC20_Connect_TCP_Server(char *server_ip,u16 port);
u8 MC20_ClientSendData(u8 *buffer,u32 len);
 
 
void MC20_InitConnect(char *server_ip,u16 port);
#endif      

五、OneNet建立産品

連結位址: 

https://open.iot.10086.cn/develop/global/product/#/console
STM32+移遠MC20子產品采用MQTT協定登入OneNet上傳GPS資料

繼續閱讀