一、環境介紹
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
#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


轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/282378.html
標籤:其他
