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

发布者:qin199099最新更新时间:2022-10-14 来源: csdn关键字:STM32  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模块

 

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

#include

#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("串口准备就绪.....rn");

DelayMs(500);

printf("程序修改时间: %srn",__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失败:%drn",stat,cnt++);

else break; //登录成功

 

LED1=!LED1;

     delay_ms(200); 

break;//失败也退出继续运行下面代码

  }

printf("6. OneNET服务器登录成功!rn");

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,纬度:%frn",Longitude,latitude); break;

case 1: printf("ERROR:GPS数据接收失败!rn"); break;

case 2: printf("ERROR:GPS定位数据解码失败!<请将GPS拿到空旷位置定位>rn"); 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]='';

  printf("USART2_RX_BUFF=%srn",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]='';

              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("ATrn","OKrn");

}

 

 

/*

函数功能: 开启GPS功能

返 回 值:0表示成功  1表示失败

*/

u8 MC20_StartGPS(void)

{

//先判断GPS功能是否启动

if(MC20_SendCmd("AT+QGNSSC?rn","+QGNSSC: 1")) 

{

//没有启动就启动GPS功能

if(MC20_SendCmd("AT+QGNSSC=1rn","OKrn"))

{

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"rn", "OKrn"))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"rn",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+QISENDrn",">"))

{

printf("AT+QISEND->ERROR Info:%srn",USART2_RX_BUFF);

return 1; 

}

/*2. 开始发送数据*/

USART_X_SendData(USART2,buffer,len);

delay_ms(20);

/*3. 发送结束符*/

send_buf[0] = 0x1a;

send_buf[1] = '';

if(MC20_SendCmd(send_buf,"OKrn"))

{

printf("发送结束符->ERROR Info:%srn",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模块初始化检查失败!rn");

delay_ms(100);

}

printf("1. MC20模块初始化成功!rn");

delay_ms(100);

/*2. 查询是否有PIN码锁定*/

while(MC20_SendCmd("AT+CPIN?rn","READY"))

{

LED1=!LED1;

printf("ERROR:PIN码锁定检查失败!rn");

[1] [2]
关键字:STM32  MQTT协议  OneNet  GPS数据 引用地址:STM32+移远MC20模块采用MQTT协议登录OneNet上传GPS数据

上一篇:STM32+BH1750光敏传感器获取光照强度
下一篇:STM32+SIM800C采用MQTT协议登录OneNet上传温湿度、MQ2烟雾浓度、GPS数据

推荐阅读最新更新时间:2024-11-13 03:51

stm32的IO重映射
图片内容来自《电子系统设计与实战 stm32+FPGA控制版》 下面调用GPIO_PinRemapConfig(GPIO_Remap_SPI1,ENABLE);直接就把SPI1的所有IO换成了映射IO。
[单片机]
stm32 C语言的数据类型说明
stm32编程过程经常定义变量类型,经常担心数据运算过程中 超过变量类型范围。因为在编程过程中,不同的CPU,其数据类型的意义各不相同,所以一定要注意相应变量数据类型的定义和转换,否则在计算中可能会出现不确定的错误。所以下面列出常见数据类型: 一、C语言数据类型 stm32使用的数据类型定义在 stm32f4xx.h中 整型定义: #include core_cm4.h /* Cortex-M4 processor and core peripherals */ #include system_stm32f4xx.h #include stdint.h /** @addtogroup Exported
[单片机]
STM32芯片的存储结构
一、前言 本篇介绍STM32芯片的存储结构,ARM公司负责提供设计内核,而其他外设则为芯片商设计并使用,ARM收取其专利费用而不参与其他经济活动,半导体芯片厂商拿到内核授权后,根据产品需求,添加各类组件,生产芯片售卖。图1为STM32的组成示意图,其中Cortex-M3内核、调试系统都是ARM公司设计,内部总线、外设、存储、时钟复位等都由ST公司开发。可以明显看出总线是cpu、内存、外设传递信息的公用通道,芯片上的各个部件通过总线相连接。 图1 STM32芯片简要结构图 内核通过总线访问各个外设,现在通往外设的“路”已经铺好,还需要规定各个外设的“门牌号”,以便精准控制每个外设。ARM Cortex-M3系列的处理器,采用存储
[单片机]
<font color='red'>STM32</font>芯片的存储结构
STM32程序_低功耗设置
STM32F103R8和RC的停机模式的休眠电流还不一样,R8停机模式实测为11uA,RC停机模式实测为30uA,还以为又是我的程序哪里没做好呢,仔细看了PDF,这两个芯片PDF上标的值的确有区别,和我测的值差不多,那我就没有再深究的意义了! 结合下文的高手经验,反复摸索, standby模式1.9uA,PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); stop模式:11uA, PWR_EnterSTANDBYMode(); 实验证明,将IO端口设成IPU/IPD/AIN/PPOUT=1/PPOUT=0/ODOUT=0,电流是基本相
[单片机]
<font color='red'>STM32</font>程序_低功耗设置
stm32学习笔记(十二)ADC实验
#include adc.h #include delay.h ////////////////////////////////////////////////////////////////////////////////// //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK miniSTM32开发板 //ADC 代码 //正点原子@ALIENTEK //技术论坛:www.openedv.com //修改日期:2012/9/7 //版本:V1.0 //版权所有,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2009-2019 //All rights res
[单片机]
STM32中断及NVIC概述
参考资料《STM32F4xx 中文参考手册》第十章-中断和事件、《 ARM Cortex™-M4F 技术参考手册》-4.3 章节:NVIC 和 4.4章节:SCB—4.4.5的 AIRCR。 对51单片机有一定了解的都知道51单片机有5个中断源,2个优先级,通过对IP这个寄存器赋值来进行中断优先级的处理而STM32的中断非常强大,每个外设都可以产生中断,那么STM32如何进行中断优先级的分配呢,这时就用到了NVIC(嵌套向量中断控制器), 支持为数众多的系统异常和外部中断。 下表即为STM32F42系列的中断向量表(了解即可),即中断类型 灰色部分即为内核的系统异常,灰色以外的其他部分即为片上所有外
[单片机]
<font color='red'>STM32</font>中断及NVIC概述
stm32的启动文件--startup_stm32f10x_hd.s
在学习stm32 定时器中断时,发现我写的程序进入不了中断服务程序,而且我也没找到定时器服务程序的注册入口,上网查了一下,大家都使用的都是下面这个函数:void TIM3_IRQHandler(void),那为什么其他人的中断程序可以执行,而我的却执行不了呢。 经过请教得知,我的工程中没有包含该一个叫做startup_stm32f10x_hd.s的文件,而我所谓的中断服务程序的注册入口就是包含在这里。startup_stm32f10x_hd.s是用汇编语言编写的STM32处理器的初始化程序,它规定了系统的堆栈大小等系统信息,也包含了一个向量表,这个向量表中对所有的中断入口函数都进行了分配,如TIM3的中断入口是: ……
[单片机]
关于STM32 ADC时采用DMA的一点疑问
手册上有这样的话:只有ADC1能够产生DMA请求,似乎是只有ADC通道1能采用DMA方式传输数据。 但是万利的开发板上的ADC例子,用的是ADC通道10,还用了DMA 方式传数据。 所以我猜测 “只有ADC1能够产生DMA请求”中提到的ADC1 并不是指ADC 通道1, 而是软件可配置的 ADC 通道的分类形式,可分为ADC1和ADC2. 我们可将 通道10(或其他)配置成ADC1 “模式”。通过函数 /* ADC1 regular channel10 configuration */ ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_5
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved