【STM32】RTT-Studio中HAL库开发教程十:EC800M-4G模块使用

devtools/2024/12/30 1:22:57/

文章目录

    • 一、简介
    • 二、模块测试
    • 三、OneNet物联网配置
    • 四、完整代码
    • 五、测试验证

一、简介

  EC800M4G是一款4G模块,本次实验主要是进行互联网的测试,模块测试,以及如何配置ONENET设备的相关参数,以及使用STM32F4来测试模块的数据上报功能。EC800M4G模块资料

使用的工具如下:

  • 串口助手
  • EC800M4模块以及模块资料
  • STM32F407单片机最小系统板
  • ONENET物联网设备创建

二、模块测试

1.模块测试 :主要使用串口+模块(EC800M)+MQTT.fx进行模块功能的验证。
(1)模块硬件连接
  将配套的 USB 转串口模块的 RX、TX、VCC、GND 分别与模块 TX、RX、VCC、GND 连接,注意在上电之前,先把SIM 卡正确插入卡座内,连接示意图如下:

在这里插入图片描述
(2)测试模块通信
  将串口接入PC端后,使用串口助手通过发送指令的方式验证模块通信。串口配置:波特率115200,8位数据位,1位停止位,没有校验位。

  • 指令测试:
  • (1)开机,本模组为上电后自动开机,回复:RDY 则视为正常情况。
  • (2)发送:AT\r\n,回复:模块回 OK,表示正常。
  • (3)发送:AT+CIMI\r\n,回复:获取 SIM 卡的 CIMI 号,模块回 15 字节数据,切记 SIM 的插卡方向,如无法获取卡号。
  • (4)发送:AT+CEREG?\r\n,回复:检查模块是否注网成功,模块回+CEREG:0,1表示注网成功,如果模块断电冷启动,可能刚刚开始需要一些时间进行注网,切记在注网成功之后,才能进行网络的相关操作。
  • (5)发送:AT+CSQ\r\n,回复:获取 NBIOT 信号强度,模块回+CSQ:23,99,前面一个十进制数表示信号前度,一般情况下要求高于 16,否则可能存在通信失败的情况。
  • 通过以上测试如果都回复正常,则可以进行MQTT正常的模块验证测试。

2.MQTT.fx :相关配置
(1)MQTT安装包-----MQTT.fx-V1.7.1-Windows
(2)MQTT配置
  a):进入设置界面,进行相关配置。

在这里插入图片描述

  b):进入设置界面,配置服务器参数,包括协议类型、服务器地址、端口号等内容。

在这里插入图片描述

  c):进入设置界面,配置用户名、密码、安全设置、和网诺代理配置。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.MQTT和串口通信 :通过MQTT和串口进行数据发送和接收
(1)点击连接服务器,进行配置

在这里插入图片描述
(2)先确保模块可以正常通信和注网成功,再连接MQTT、配置用户名和订阅主题。

在这里插入图片描述

(3)发送数据到MQTT上位机,即可收到串口发送的数据。

在这里插入图片描述
在这里插入图片描述

(4)上位机发送数据到模块。

在这里插入图片描述
在这里插入图片描述


三、OneNet物联网配置

1.创建产品
(1)点击左上角的产品服务,看到物联网开放平台,点进去。

在这里插入图片描述

(2)进入到产品开发-创建产品

在这里插入图片描述

(3)产品种类根据具体产品填写,接入协议也是根据自己的需求选择,我们这里使用的是MQTT协议,数据协议选OneJson,联网方式选择NB,开发方案为标准方案就行,然后点击确定创建成功。

在这里插入图片描述
在这里插入图片描述

(4)此时我们产品创建好了,但是产品下还没有设备,我们来新建一个设备,点击设备管理。填写相关信息,点击确定,设备就添加好了。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(5)设备连接前,可以在设备管理-设备详情里,查询设备所属产品ID和密钥,这些信息在设备连接平台时需要使用,如下:

在这里插入图片描述

(6)设置物模型:进入产品开发-详情页面,这里我们删除了用不上的属性并自定义了下列属性属性。

在这里插入图片描述

2.连接NB-IOT
(1)连接OneNET时,接口地址和端口号:183.230.40.96,1883是平台默认的MQTT接入服务地址和端口,token是通过key计算出来的,通过使用计算工具计算出来,计算方式入下:OneNET-token生成工具安装包

在这里插入图片描述

//配置协议版本信息
AT+QMTCFG="version",0,4
OK//打开MQTT通道,需要等+QMTOPEN: 0,0 URC
AT+QMTOPEN=0,183.230.40.96,1883
OK
+QMTOPEN: 0,0//连接MQTT,需要等+QMTCONN: 0,0,0 URC
AT+QMTCONN=0,"EC800816","WtF1aQE659","version=2018-10-
31&res=products%2FWtF1aQE659%2Fdevices%2FEC800816&et=2537256630&method=md5&sign=VJfBWuWM43wPgj%2BH7B0G8w%3D%3D"
OK

(2)订阅通信主题:物联网平台中,服务端和设备端通过通信主题Topic实现消息通信,设备可以通过发布消息到系统 topic 调用服务接口,也可以订阅系统 topic 用于接收服务消息通知,服务提供的系统 topic可在物模型 -下一步 - topic管理 - 物模型topic中查看。

设备侧需要收到平台下发的数据topic为:

$sys/{pid}/{device-name}/thing/property/set

属性上报的topic为:

$sys/{pid}/{device-name}/thing/property/post

订阅这2个topic的AT指令如下:

AT+QMTSUB=0,1,"$sys/WtF1aQE659/EC800816/thing/property/post/reply",0,"$sys/WtF1aQE659/EC800816/thing/property/set",0

接收到OK +QMTSUB: 0,1,0,0,0则表示订阅成功。

(3) 事件上报:我们把设备信息上报到平台,对应的AT指令:

//发布消息,133为数据⻓度,出来> 后发送数据,需要等+QMTPUBEX: 0,0,0 URC才能发下
⼀条数据
AT+QMTPUBEX=0,0,0,0,"$sys/WtF1aQE659/EC800816/thing/property/post",110
> {"id":"19","version":"1.0","params":{"humidity":{"value":54.23},"temp":{"value":42.56},"key":{"value":true}}}
OK
+QMTPUBEX: 0,0,0

上报数据成功后,订阅的属性上报会返回success:
在这里插入图片描述
进入设备管理-设备详情,可以查看设备上报的属性数据。
在这里插入图片描述

(4)设置属性:在页面设备管理-详情-设备调试-应用模拟器-属性期望值设置,可设置设备属性。串口收到如下数据:

+QMTRECV: 0,0,"$sys/WtF1aQE659/EC800816/thing/property/set","{"id":"20","version":"1.0","params":{"humidity":65,"key":false,"temp":55}}"

在这里插入图片描述
综合上述的所有操作即可实现串口数据到OneNET数据的下发和上报功能。


四、完整代码

1.main.c 主函数用来进行初始化和执行完之后LED等闪烁功能。

#include <rtthread.h>
#include <drv_common.h>
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include "ec800m.h"int main(void)
{int count = 1;rt_pin_mode(GET_PIN(E, 12), PIN_MODE_OUTPUT);create_work_test(LTEDemoPath_ONENET);   // 创建工作测试while (count){rt_pin_write(GET_PIN(E, 12), PIN_HIGH);rt_thread_mdelay(1000);rt_pin_write(GET_PIN(E, 12), PIN_LOW);rt_thread_mdelay(1000);}return RT_EOK;
}

2.ec800m.c 包含两部分代码:串口线程和IOT的任务函数。
(1)串口线程:主要是串口的初始化配置,串口发送数据函数,以及串口接收线程。当接收到数据之后,需要和校验数据进行校验,只有校验通过之后,才表示发送数据设置成功。

#include "ec800m.h"
#include "lte_at.h"/*=====================================================##### 串口线程 #####==================================================*/
/*** @brief IOT发送数据* @param buffer:发送的数据* @param size:数据大小*/
void Iot_Send_Data(const void *buffer, rt_size_t size)
{rt_device_write(g_ec800m.dev, 0, buffer, size);
}/*** @brief 接收回调函数* @param size:接收数据的大小* @return*/
rt_err_t Rx_Data_Callback(rt_device_t dev, rt_size_t size)
{rt_sem_release(g_ec800m.sem);return RT_EOK;
}/*** @brief 接收线程回调函数*/
void Iot_Thread_Entry(void *parameter)
{rt_err_t result;char ch;iot_t *pIot = (iot_t *)parameter;while (1){result = rt_sem_take(pIot->sem, RT_WAITING_FOREVER);if (result == RT_EOK){rt_device_read(pIot->dev, 0, &ch, 1);g_ec800m.rx_data[g_ec800m.rx_cnt++] = ch;
//            rt_kprintf("%c", ch);if (rt_strstr(g_ec800m.rx_data, g_ec800m.check_data) != NULL){
//                rt_kprintf("success!!\n");memset(g_ec800m.recv_data, 0, MAX_AT_RESPONSE_LEN);memcpy(g_ec800m.recv_data, g_ec800m.rx_data, strlen(g_ec800m.rx_data));g_ec800m.check_flag = CHECK_OK;g_ec800m.rx_cnt = 0;memset(g_ec800m.rx_data, 0, MAX_AT_RESPONSE_LEN);}}else{g_ec800m.rx_cnt = 0;memset(g_ec800m.rx_data, 0, MAX_AT_RESPONSE_LEN);}}
}/*** @brief IOT模块初始化*/
static int Iot_EC800M_Init(void)
{// 初始化参数g_ec800m.rx_data = rt_malloc(MAX_AT_RESPONSE_LEN);
//    memcpy(g_ec800m.check_data, IOT_CHECK_READY, strlen(IOT_CHECK_READY));// 查找设备句柄g_ec800m.dev = (rt_device_t) rt_device_find(IOT_UART_DEV_NAME);RT_ASSERT(g_ec800m.dev != RT_NULL);// 打开设备rt_err_t ret = rt_device_open(g_ec800m.dev, RT_DEVICE_FLAG_INT_RX);RT_ASSERT(ret == RT_EOK);// 串口初始化struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;config.baud_rate = BAUD_RATE_115200;config.data_bits = DATA_BITS_8;config.parity = PARITY_NONE;rt_device_control(g_ec800m.dev, RT_DEVICE_CTRL_CONFIG, (void *)&config);// 接收回调函数rt_device_set_rx_indicate(g_ec800m.dev, Rx_Data_Callback);// 创建信号量g_ec800m.sem = rt_sem_create("rx_sem", 0, RT_IPC_FLAG_PRIO);// 创建线程g_ec800m.thread = rt_thread_create("usart_rx", Iot_Thread_Entry,&g_ec800m.dev, 2048, 16, 20);if (g_ec800m.thread == RT_NULL){rt_kprintf("thread create fail...\n");}else{// 启动线程rt_thread_startup(g_ec800m.thread);}return RT_EOK;
}
INIT_ENV_EXPORT(Iot_EC800M_Init);
/*=====================================================#######  END  #######=================================================*/

(2)IOT任务函数:主要是创建IOT初始化以及数据上报的整个流程函数,并且使用的是ONENET数据上报。

/*=====================================================##### IOT任务函数 #####===========================================*/
/*** @brief 创建的ONENET任务*/
void lte_onenet_task_entry( void )
{int32_t  atRet = AT_FAILED;uint32_t count = 0;char     sendData[256];float    humidity = 56.45, temp = 24.23;char     key[10] = "false";rt_kprintf("\n[INFO]This is lte_onenet_task_entry!\n");/* 1.初始化模块 */atRet = lte_mqtt_init();/* 2.打开MQTT通道 */atRet |= lte_mqtt_open(IOT_ONNET_brokerAddress, IOT_ONNET_port, "3.1.1");if (atRet != 0){rt_kprintf("[ERROR]lte_mqtt_init fail \r\n");return;}/* 3.连接MQTT */atRet = lte_mqtt_conn(IOT_ONNET_cientId, IOT_ONNET_userName, IOT_ONNET_password);if (atRet != 0){rt_kprintf("[ERROR]lte_mqtt_conn fail \r\n");return;}/* 4.订阅消息 */atRet = lte_mqtt_sub( IOT_ONNET_subtopic);if (atRet != 0){rt_kprintf("[ERROR]onenet Mqtt Subscriber error \r\n");return;}/* 5.更改数据并上报 */while ( 1 ){count++;/* 数据sendData *//* {"id":"19","version":"1.0","params":{"humidity":{"value":98.33},"temp":{"value":55.23},"key":{"value":true}}} */sprintf(sendData, IOT_MESSAGE, humidity, temp, key);rt_kprintf("\r\n[INFO]**********************************************************************************\r\n");rt_kprintf("[INFO]Onenet send %d-->%s\r\n", count, sendData);/* 发送数据 */atRet = lte_mqtt_pubex(IOT_ONNET_pubtopic, sendData);if (atRet != 0)return;/* 数据变化 */temp += 0.1;temp = temp > 38.0 ? 24.0 : temp;humidity += 0.5;humidity = humidity > 99.9 ? 24.0 : humidity;if (count % 2 == 0){strcpy(key, "false");}else{strcpy(key, "true");}if (count > 10){count = 1;break;}/* 上传至少3S */rt_thread_mdelay(5000);}
}/*** @brief LTE任务* @param protocolType:连接方式* @return 工作状态*/
uint32_t lte_task( LTEAppDemoPath_t protocolType )
{uint32_t uwRet = 0;void     (*threadLTE_entry)();switch (protocolType){case LTEDemoPath_UDP:       threadLTE_entry = NULL;                  break;case LTEDemoPath_TCP:       threadLTE_entry = NULL;                  break;case LTEDemoPath_MQTT:      threadLTE_entry = NULL;                  break;case LTEDemoPath_ONENET:    threadLTE_entry = lte_onenet_task_entry; break;case LTEDemoPath_ALIYUN:    threadLTE_entry = NULL;                  break;case LTEDemoPath_ALIYUN_GPS:threadLTE_entry = NULL;                  break;}threadLTE_entry();return (uwRet);
}/*** @brief 创建工作测试* @param protocolType:连接方式* @return 返回工作状态*/
uint32_t create_work_test( LTEAppDemoPath_t protocolType )
{uint32_t uwRet = 0;uwRet = lte_task(protocolType);if (uwRet != 0){return (0);}return (uwRet);
}
/*=====================================================#######  END  #######=================================================*/

3.ecm800.h 主要是暴扣使用的一些头文件

#ifndef APPLICATIONS_EC800M_H_
#define APPLICATIONS_EC800M_H_#include <rtthread.h>
#include <drv_common.h>
#include <string.h>
#include <stdio.h>/**====================================================###### 宏定义 ######==================================================*/
#define IOT_CHECK_READY            "RDY"                // 就绪#define IOT_ONNET_brokerAddress    "183.230.40.96"      // ONENET地址
#define IOT_ONNET_port             (1883)               // ONENET端口号
#define IOT_ONNET_cientId          "EC800M"             // 设备名称
#define IOT_ONNET_userName         "4S62S0ii0j"         // 产品ID
#define IOT_ONNET_password         "version=2018-10-31&res=products%2F4S62S0ii0j%2Fdevices%2FEC800M&et=2537256630&method=md5&sign=7afdqXTkvNhV%2F4k%2BFHis8Q%3D%3D"
#define IOT_ONNET_subtopic         "$sys/4S62S0ii0j/EC800M/thing/property/set"  // 设置主题
#define IOT_ONNET_pubtopic         "$sys/4S62S0ii0j/EC800M/thing/property/post" // 上传主题
#define IOT_MESSAGE                "{\"id\":\"20\",\"version\":\"1.0\",\"params\":{\"humidity\":{\"value\":%2.2f},\"temp\":{\"value\":%2.2f},\"key\":{\"value\":%s}}}"#define CHECK_OK       1            // 校验通过
#define CHECK_FAILED   0            // 校验失败#define MAX_AT_RESPONSE_LEN 512     // AT响应数据的最大长度
#define TIMEOUT_TIME_SEC    3       // 超时时间
/**====================================================#######  END  #######=================================================*//**====================================================### 全局变量定义 ####=================================================*/
#define IOT_UART_DEV_NAME  "uart2"/* LTE通信模式 */
typedef enum
{LTEDemoPath_UDP,LTEDemoPath_TCP,LTEDemoPath_MQTT,LTEDemoPath_ONENET,LTEDemoPath_ALIYUN,LTEDemoPath_ALIYUN_GPS,} LTEAppDemoPath_t;typedef struct
{rt_device_t dev;            // 串口设备rt_sem_t sem;               // 创建信号量rt_thread_t thread;         // 创建线程rt_size_t rx_cnt;           // 接收计数rt_uint8_t check_flag;      // 校验标志位uint8_t mqttOpenOkFlage;    // 打开成功标志uint8_t mqttConnetOkFlage;  // 连接成功标志char *rx_data;              // 接收数据临时缓冲区char check_data[256];       // 校验数据char recv_data[512];        // 接收的有效数据char send_data[512];        // 发送数据缓冲器} iot_t;iot_t g_ec800m;
/**====================================================#######  END  #######=================================================*//**==================================================##### 函数及变量声明 #####==============================================*/
extern void Iot_Send_Data(const void *buffer, rt_size_t size);      // IOT发送数据
extern uint32_t create_work_test(LTEAppDemoPath_t protocolType);    // 创建工作测试
/**====================================================#######  END  #######=================================================*/#endif /* APPLICATIONS_EC800M_H_ */

4.lte_at.c 主要是包括AT发送指令函数,发送指令,API接口函数
(1)AT发送函数:主要是用来发送每条AT指令,并且需要接收数据的返回,并且进行数据校验,校验成功才能正常进行。

#include "lte_at.h"/*======================================================##### AT指令 #####==============================================*/
/*** @brief 发送函数* @param cmd        :发送的指令* @param ack        :应答数据* @param waittime   :超时时间* @param outResponse:接收数据缓冲区* @return AT_OK--校验通过   AT_FAILED--校验失败*/
uint8_t LTEAT_sendCmd( char *cmd, char *ack, uint32_t waittime, uint8_t *outResponse )
{uint8_t  ret     = AT_OK;uint16_t sendLen = 0;g_ec800m.check_flag = 0;memset(g_ec800m.check_data, 0, sizeof(g_ec800m.check_data));memcpy(g_ec800m.check_data, ack, strlen(ack));memset(g_ec800m.send_data, 0, sizeof(g_ec800m.send_data));sendLen = sprintf(g_ec800m.send_data, "%s\r\n", cmd);/* 发送命令 */Iot_Send_Data(g_ec800m.send_data, sendLen);/* 需要等待应答 */if (ack && waittime){/* 等待倒计时 */while (--waittime){rt_thread_mdelay(1);/* 接收到期待的应答结果 */if (g_ec800m.check_flag == CHECK_OK){g_ec800m.check_flag = 0;if (outResponse != NULL){memcpy(outResponse, g_ec800m.recv_data, strlen(g_ec800m.recv_data));rt_kprintf("[%d][DATA]%s\n", waittime, outResponse);}else{rt_kprintf("[%d][DATA]%s\n", waittime, g_ec800m.recv_data);}memset(g_ec800m.recv_data, 0, MAX_AT_RESPONSE_LEN);memset(g_ec800m.check_data, 0, sizeof(g_ec800m.check_data));break;}}/* 等待超时 */if (waittime == 0){ret = AT_FAILED;memset(g_ec800m.recv_data, 0, MAX_AT_RESPONSE_LEN);memset(g_ec800m.rx_data, 0, MAX_AT_RESPONSE_LEN);memset(g_ec800m.check_data, 0, sizeof(g_ec800m.check_data));}}return ret;
}/*** @brief AT指令发送函数调用* @param cmd     :指令* @param len     :指令长度* @param suffix  :校验字符串* @param resp_buf:接收缓冲区* @param resp_len:接收长度* @return AT_OK--校验通过   AT_FAILED--校验失败*/
int32_t at_cmd(int8_t *cmd, int32_t len, const char *suffix, char *resp_buf, int* resp_len)
{int result;rt_kprintf("[SEND]%s\n", cmd);result = LTEAT_sendCmd((char *) cmd, (char *) suffix, AT_CMD_TIMEOUT, (uint8_t *) resp_buf);if (result == 0){if (resp_len != NULL)*resp_len = strlen(resp_buf);}return (result);
}
/*=====================================================#######  END  #######=================================================*/

(2)发送指令:主要是包含所有的发送指令

/*======================================================##### 发送指令 #####=================================================*/
/*** @brief 等待准备就绪* @param waittime:超时时间(s)* @return AT_OK--校验通过   AT_FAILED--校验失败*/
uint8_t Iot_Wait_Ready(uint32_t waittime)
{uint8_t ret = AT_FAILED;memcpy(g_ec800m.check_data, IOT_CHECK_READY, strlen(IOT_CHECK_READY));while (waittime--){if (g_ec800m.check_flag == CHECK_OK){g_ec800m.check_flag = CHECK_FAILED;ret = AT_OK;memset(g_ec800m.recv_data, 0, MAX_AT_RESPONSE_LEN);rt_kprintf("[INFO]Check Passed And Ready\r\n");break;}rt_thread_delay(1);}/* 等待超时 */if (waittime == 0){ret = AT_FAILED;memset(g_ec800m.recv_data, 0, MAX_AT_RESPONSE_LEN);memset(g_ec800m.rx_data, 0, MAX_AT_RESPONSE_LEN);memset(g_ec800m.check_data, 0, sizeof(g_ec800m.check_data));}return ret;
}/*** @brief 模块复位* @return AT_OK--校验通过   AT_FAILED--校验失败*/
int32_t LTE_pwrdown( void )
{int32_t ret = 0;ret = at_cmd((int8_t *) AT_IOT_QPOWD, strlen(AT_IOT_QPOWD), "OK", NULL, NULL);if (ret == 0){rt_kprintf("[INFO]Restart Response Success\r\n");}else{rt_kprintf("[INFO]Restart Response Fail\r\n");}return (ret);
}/*** @brief 状态查询* @return AT_OK--校验通过   AT_FAILED--校验失败*/
int32_t LTE_checkDevice(void)
{int32_t ret = 0;ret = at_cmd((int8_t *) AT_IOT_AT, strlen(AT_IOT_AT), "OK", NULL, NULL);if (ret == 0){rt_kprintf("[INFO]Reboot Response Success\r\n");}else{rt_kprintf("[INFO]Reboot Response Fail\r\n");}return (ret);
}/*** @brief 设置回显* @param enable:使能状态* @return AT_OK--校验通过   AT_FAILED--校验失败*/
int32_t LTE_setATI(uint8_t enable)
{int ret;char buf[64] = {0};if (enable == 0){ret = at_cmd((int8_t *) AT_IOT_ATE0, strlen(AT_IOT_ATE0), "OK", NULL, NULL);if (ret == 0){rt_kprintf("[INFO]Close ECHO Success\r\n");}else{rt_kprintf("[INFO]Close ECHO Fail\r\n");}}else{ret = at_cmd((int8_t *) AT_IOT_ATE1, strlen(buf), "OK", NULL, NULL);if (ret == 0){rt_kprintf("[INFO]Open ECHO Success\r\n");}else{rt_kprintf("[INFO]Open ECHO Fail\r\n");}}return (ret);
}/*** @brief 查询卡号* @return AT_OK--校验通过   AT_FAILED--校验失败*/
int32_t LTE_getCimi(void)
{char recvBuf[64];int  recvLen;int  ret;ret = at_cmd((int8_t *) AT_IOT_CIMI, strlen(AT_IOT_CIMI), "OK", recvBuf, &recvLen);if (recvLen < 64){recvBuf[recvLen] = '\0';
//        rt_kprintf("[INFO]CIMI:%s", recvBuf);}return (ret);
}/*** @brief 查询设备识别码* @return AT_OK--校验通过   AT_FAILED--校验失败*/
int32_t LTE_getCGSN(void)
{char recvBuf[64];int  recvLen;int  ret;ret = at_cmd((int8_t *) AT_IOT_CGSN, strlen( AT_IOT_CGSN), "OK", recvBuf, &recvLen);if (recvLen < 64){recvBuf[recvLen] = '\0';
//        rt_kprintf("[INFO]CGSN:%s", recvBuf);}return (ret);
}/*** @brief 查询当前 PS 域状态* @return AT_OK--校验通过   AT_FAILED--校验失败*/
int32_t LTE_netstat(void)
{char *cmd = "AT+CGATT?";return (at_cmd((int8_t *) cmd, strlen(cmd), "CGATT: 1", NULL, NULL));
}/*** @brief 查询信号强度* @return AT_OK--校验通过   AT_FAILED--校验失败*/
int32_t LTE_checkCsq(void)
{char *cmd = "AT+CSQ";return (at_cmd((int8_t *) cmd, strlen(cmd), "+CSQ:", NULL, NULL));
}/*** @brief 查询网络注册状态* @return AT_OK--校验通过   AT_FAILED--校验失败*/
int32_t LTE_getCereg(void)
{char recvBuf[64];int recvLen;int ret;ret = at_cmd((int8_t *) AT_IOT_CEREG, strlen( AT_IOT_CEREG), "0,1", recvBuf, &recvLen);if (recvLen < 64){recvBuf[recvLen] = '\0';
//        printf("[INFO]Cereg:%s\r\n", recvBuf);}return (ret);
}/*** @brief 显示 PDP 地址* @return AT_OK--校验通过   AT_FAILED--校验失败*/
int32_t LTE_queryIp(void)
{char *cmd = "AT+CGPADDR=1";return (at_cmd((int8_t *) cmd, strlen(cmd), "+CGPADDR", NULL, NULL));
}/*** @brief 发送AT指令打开MQTT通道* @param brokerAddress:地址* @param port         :端口号* @param protocolVer  :版本信息* @return AT_OK--校验通过   AT_FAILED--校验失败* @note AT+QMTOPEN=0,123.207.210.43,1883*/
int32_t LTE_EC800_mqttOpen(char* brokerAddress, uint16_t port, char* protocolVer)
{int  ret;char buf[256];// 配置协议版本信息if (protocolVer != NULL && strstr(protocolVer, "3.1.1") != NULL){snprintf(buf, sizeof(buf), "AT+QMTCFG=\"version\",0,4");ret = at_cmd((int8_t *) buf, strlen(buf), "OK", NULL, NULL);if (ret < 0){rt_kprintf("[ERROR]QMTCFG ERROR\n");return (ret);}}// 打开MQTT通道snprintf(buf, sizeof(buf), "AT+QMTOPEN=0,%s,%d", brokerAddress, port);ret = at_cmd((int8_t *) buf, strlen(buf), "+QMTOPEN: 0,0", NULL, NULL);if (ret < 0){rt_kprintf("[ERROR]MQTTOPEN ERROR\n");return (ret);}return (AT_OK);
}/*** @brief 设置连接用户信息* @param clientID:连接ID* @param userName:用户名* @param password:用户密码* @return AT_OK--校验通过   AT_FAILED--校验失败* @note AT+QMTCONN=0,"clientExample"*/
int32_t LTE_EC800_mqttConnet(char *clientID, char *userName, char *password)
{int  ret;char buf[256];if (userName != NULL && password != NULL){snprintf(buf, sizeof(buf), "AT+QMTCONN=0,%s,%s,%s", clientID, userName, password);}else{snprintf(buf, sizeof(buf), "AT+QMTCONN=0,%s", clientID);}ret = at_cmd((int8_t *) buf, strlen(buf), "+QMTCONN: 0,0,0", NULL, NULL);if (ret < 0){printf("[ERROR]MQTTCON ERROR\n");return (ret);}return (AT_OK);
}/*** @brief 订阅MQTT消息* @param topic:主题* @return AT_OK--校验通过   AT_FAILED--校验失败* @note AT+QMTSUB=0,1,"topic/example_8808",0*/
int32_t LTE_EC800_mqttSub(char* topic)
{int ret;char wbuf[256];snprintf(wbuf, sizeof(wbuf), "AT+QMTSUB=0,1,\"%s\",0", topic);ret = at_cmd((int8_t *) wbuf, strlen(wbuf), "+QMTSUB: 0,1,0,0", NULL, NULL);if (ret < 0){return (ret);}return (ret);
}/*** @brief 发布MQTT消息、用于长数据发送* @param topic :主题* @param msg   :数据* @param msgLen:数据长度* @return AT_OK--校验通过   AT_FAILED--校验失败*/
int32_t LTE_EC800_mqttPubEX(char* topic, char* msg, uint32_t msgLen)
{int  ret;char wbuf[256];snprintf(wbuf, sizeof(wbuf), "AT+QMTPUBEX=0,0,0,0,\"%s\",%d", topic, strlen(msg));ret = at_cmd((int8_t *) wbuf, strlen(wbuf), ">", NULL, NULL);if (ret != AT_OK){return (ret);}snprintf(wbuf, sizeof(wbuf), "%s", msg);ret = at_cmd((int8_t *) wbuf, strlen(wbuf), "+QMTPUBEX: 0,0,0", NULL, NULL);if (ret != AT_OK){return (ret);}return (ret);
}
/*=====================================================#######  END  #######=================================================*/

(3)API函数:主要是用来对接初始化或者数据上报流程的函数

/*=====================================================##### API函数 #####==============================================*/
/*** @brief 模块上电通用初始化* @return AT_OK--校验通过   AT_FAILED--校验失败*/
static int lte_comm_init(void)
{int ret;int timecnt = 0;/* 等待就绪 */ret = Iot_Wait_Ready(POWER_ON_WAIT_TIME);if (ret == AT_FAILED){rt_kprintf("[INFO]Restart IOT Module...\n");/* 复位模块 */for (int i = 0; i < 3; ++i){ret = LTE_pwrdown();if (ret == AT_OK){Iot_Wait_Ready(10000);break;}}if (ret == AT_FAILED){return ret;}}/* 延时缓冲 */rt_thread_delay(2000);/* 状态查询 */ret = LTE_checkDevice();/* 关闭回显 */LTE_setATI(0);/* 查询卡号、设备识别码信息 */while (1){ret = AT_OK;ret |= LTE_getCimi();ret |= LTE_getCGSN();if (ret == AT_OK)break;rt_thread_delay(500);}/* 延时缓冲 */rt_thread_delay(2000);/* 等待注网成功 */while (timecnt < 10){ret = LTE_netstat();rt_kprintf("[INFO]Waiting for join network\n");ret = LTE_checkCsq();rt_kprintf("[INFO]LTE_checkCsq\n");ret = LTE_getCereg();rt_kprintf("[INFO]LTE_getCereg\n");ret |= LTE_queryIp();rt_kprintf("[INFO]LTE_queryIp\n");if (ret == AT_OK){break;}rt_thread_delay(500);timecnt++;}rt_kprintf("[INFO]Join network success!\r\n");return (ret);
}/*** @brief MQTT通信方式下,模块初始化* @return 返回初始化状态*/
int lte_mqtt_init(void)
{int ret;ret = lte_comm_init();return (ret);
}/*** @brief 打开MQTT通道* @param brokerAddress:地址* @param port         :端口号* @param protocolVer  :版本信息* @return AT_OK--校验通过   AT_FAILED--校验失败*/
int lte_mqtt_open(char * brokerAddress, uint16_t port, char* protocolVer)
{int ret;ret = LTE_EC800_mqttOpen(brokerAddress, port, protocolVer);if (ret == AT_OK)rt_kprintf("[INFO]LTE_EC800_mqtt open\r\n");return (ret);
}/*** @brief MQTT通信方式下,模块连接* @param clientID:* @param userName:* @param password:* @return AT_OK--校验通过   AT_FAILED--校验失败*/
int lte_mqtt_conn(char *clientID, char *userName, char *password)
{int ret;ret = LTE_EC800_mqttConnet(clientID, userName, password);if (ret == AT_OK)rt_kprintf("[INFO]LTE_EC800_mqtt set config success\r\n");return (ret);
}/*** @brief MQTT通信方式下,模块订阅消息* @param topic:主题* @return AT_OK--校验通过   AT_FAILED--校验失败*/
int lte_mqtt_sub(char* topic)
{int ret;ret = LTE_EC800_mqttSub(topic);if (ret == AT_OK)rt_kprintf("[INFO]lte_mqtt_sub sub success\r\n");return (ret);
}/*** @brief MQTT通信方式下,模块上报数据* @param topic:主题* @param buf  :数据缓冲区* @return AT_OK--校验通过   AT_FAILED--校验失败*/
int lte_mqtt_pubex(char* topic, char* buf)
{return (LTE_EC800_mqttPubEX(topic, buf, strlen(buf)));
}
/*=====================================================#######  END  #######=================================================*/

5.lte_at.h 主要是AT指令所用的宏定义

#ifndef APPLICATIONS_INC_LTE_AT_H_
#define APPLICATIONS_INC_LTE_AT_H_#include <rtthread.h>
#include <drv_common.h>
#include "ec800m.h"/**=====================================================###### 宏定义 ######=================================================*/
#define AT_OK              0            // AT成功
#define AT_FAILED          1            // AT失败#define POWER_ON_WAIT_TIME 3000         // 上电等待时间
#define RESTART_WAIT_TIME  8000         // 重启等待时间
#define AT_CMD_TIMEOUT     1000         // AT指令超时时间#define AT_IOT_AT          "AT"                 // 模块状态
#define AT_IOT_ATE0        "ATE0"               // 关闭回显
#define AT_IOT_ATE1        "ATE1"               // 打开回显
#define AT_IOT_QPOWD       "AT+QPOWD"           // 模块复位
#define AT_IOT_CIMI        "AT+CIMI"            // 查询卡号
#define AT_IOT_CGSN        "AT+CGSN=1"          // 查询设备识别码
#define AT_IOT_CEREG       "AT+CEREG?"          // 查询网络注册状态#define DELAY_us(x)        rt_hw_us_delay(x)    // us延时函数/**====================================================#######  END  #######=================================================*//**==================================================##### 函数及变量声明 #####==============================================*/
extern void lte_onenet_dataIoctl(const char *buf, unsigned long size);              // 数据处理函数
extern int lte_mqtt_init(void);                                                     // MQTT通信方式下,模块初始化
extern int lte_mqtt_open(char * brokerAddress, uint16_t port, char* protocolVer);   // 打开MQTT通道
extern int lte_mqtt_conn(char *clientID, char *userName, char *password);           // MQTT通信方式下,模块连接
extern int lte_mqtt_sub(char* topic);                                               // MQTT通信方式下,模块订阅消息
extern int lte_mqtt_pubex(char* topic, char* buf);                                  // MQTT通信方式下,模块上报数据
/**====================================================#######  END  #######=================================================*/#endif /* APPLICATIONS_INC_LTE_AT_H_ */

五、测试验证

  通过验证初始化过程中需要合理使用延时函数,因为有时候会初始化失败,需要等待时间才能初始化完成,实际测试的效果如下所示,测试的结果可证将数据正常上报,并且每个初始化的数据也都和实际过程中接收的数据一致,所以测试成功。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述



http://www.ppmy.cn/devtools/145449.html

相关文章

深度学习-77-大模型量化之Post Training Quantization训练后量化PTQ

文章目录 1 PTQ1.1 动态量化1.2 静态量化2 四位量化的领域2.1 GPTQ2.2 GGUF(可用CPU)2.3 定点量化技术3 参考附录1 PTQ 训练后量化 :Post-Training Quantization (PTQ),模型训练完成后进行量化。 较流行的量化技术的方法之一是post-training quantization(PTQ),是指在训练后…

软件测试框架有什么作用?好用的测试框架分享

在当今软件开发中&#xff0c;软件测试框架扮演着至关重要的角色。测试框架是指用于支持自动化测试及测试管理的环境或平台。它提供了一系列的规则、标准和工具&#xff0c;以确保软件产品的质量。框架涵盖了测试的所有层面&#xff0c;包括单元测试、集成测试和系统测试等。更…

【Java数据结构】LinkedList

认识LinkedList LinkedList就是一个链表&#xff0c;它也是实现List接口的一个类。LinkedList就是通过next引用将所有的结点链接起来&#xff0c;所以不需要数组。LinkedList也是以泛型的方法实现的&#xff0c;所以使用这个类都需要实例化对象。 链表分为很多种&#xff0c;比…

在【Arduino IDE】中在线下载和离线下载【ESP系列开发板的SDK】

在线下载 打开Arduino IDE&#xff0c;依次点击 文件➔首选项➔其他开发板管理器地址&#xff0c;复制粘贴以下的开发板管理地址&#xff1a; https://arduino.me/packages/esp8266.json https://git.oschina.net/dfrobot/FireBeetle-ESP32/raw/master/package_esp32_index.j…

OpenEuler 22.03 安装 flink-1.17.2 集群

零&#xff1a;规划 本次计划安装三台OpenEuler 22.03 版本操作系统的服务器&#xff0c;用于搭建 flink 集群。这里使用flink1.17.2 的原因&#xff0c;是便于后续与springboot的整合 服务器名IP地址作用其他应用flink01192.168.159.133主jdk11、flink-1.17.2flink02192.168.…

C++map、set

1.引言 不同于之前介绍过的string、vector、list、deque、等容器&#xff0c;它们在逻辑结构上是线性的&#xff0c;并且两个位置存储的值之间没有紧密的关联&#xff0c;比如说交换或修改一下&#xff0c;还是原来的容器结构&#xff1b;今天要介绍的map和set在逻辑结构上是非…

JAVA HTTP压缩数据

/*** 压缩数据包** param code* param data* param resp* throws IOException*/protected void writeZipResult(int code, Object data, HttpServletResponse resp) throws IOException {resp.setHeader("Content-Encoding", "gzip");// write到客户端resp…

IDEA使用Alt + Enter快捷键自动接受返回值一直有final修饰的问题处理

在使用IDEA的过程中&#xff0c;使用快捷键Alt Enter在接收返回值时&#xff0c;可以快速完成参数接收&#xff0c;但前面一直会出现接收参数前面有final修饰的情况&#xff0c;效果如下所示&#xff1a; 看着真烦人呢&#xff0c;我们会发现在接受到返回值是上方有个 Declare…