当前位置: 首页 > news >正文

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

文章目录

    • 一、简介
    • 二、模块测试
    • 三、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_ */

五、测试验证

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

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


相关文章:

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

文章目录 一、简介二、模块测试三、OneNet物联网配置四、完整代码五、测试验证 一、简介 EC800M4G是一款4G模块&#xff0c;本次实验主要是进行互联网的测试&#xff0c;模块测试&#xff0c;以及如何配置ONENET设备的相关参数&#xff0c;以及使用STM32F4来测试模块的数据上报…...

增加nginx配置文件(conf.d), 管理多个项目

1.切换到nginx目录下, 新建conf.d文件夹 mkdir conf.d 2.赋予conf.d权限 chmod 777 conf.d 3.进入conf.d, 编辑conf文件 vim zc_travel.conf server { listen 13101; server_name localhost;location / {root /home/baoxin/app/web/insight-radar-rcfx-pre/html_dev;index …...

服务器中了挖矿病毒-应急响应

事件&#xff1a;客户反映服务器响应很慢&#xff0c;出行卡顿&#xff0c;服务器操作系统为windows server 2008。 现场解决步骤&#xff1a; 1、打开任务管理器&#xff0c;看到一个javs.exe的程序&#xff0c;占用CPU使用率比较高&#xff0c;怀疑可能是木马。 2、右键打开…...

pid学习感悟

飞行控制PID算法——无人机飞控_飞控算法-CSDN博客 首先pid是对现测量值和目标值的差值&#xff0c;即偏差值的操作 p是线性操作&#xff0c;偏差越大&#xff0c;则对于控制单元操作的值越大 d是微分操作&#xff0c;我们知道微分其实就是数值变化的斜率&#xff0c;所以当偏…...

Centos7.9安装openldap+phpldapadmin+grafana配置LDAP登录最详细步骤 亲测100%能行

一、部署LDAP 1、安装LDAP yum install -y openldap-servers openldap-clients openldap openldap-devel compat-openldap openldap-servers-sql systemctl start slapd systemctl enable slapd2、创建第一个管理账号密码&#xff08;设置为ldapadmin&#xff09; slappass…...

唯品会C++面试题及参考答案

内存池怎么可以保证不会产生碎片? 内存池通过预先分配一块较大的内存区域,然后对这块内存进行管理,来减少碎片产生。 首先,内存池采用固定大小的内存块分配策略。比如,将内存池划分成大小相同的小块,当有内存分配请求时,就从这些固定大小的块中选取合适的进行分配。这种…...

Flask中@app.route()的methods参数详解

诸神缄默不语-个人CSDN博文目录 在 Flask 中&#xff0c;app.route 是用于定义路由的核心装饰器&#xff0c;开发者可以通过它为应用指定 URL 映射及相应的处理函数。在处理 HTTP 请求时&#xff0c;不同的业务场景需要支持不同的 HTTP 方法&#xff0c;而 app.route 的 metho…...

使用Grafana中按钮插件实现收发HTTP请求

最近项目中需要监控分布式集群的各项指标信息&#xff0c;需要用到PrometheusGrafana的技术栈实现对分布式集群的各个节点状态进行可视化显示&#xff0c;但是要求前端需要提供一个易用的接口让用户可以触发一些操作&#xff0c;例如负载高时进行负载均衡或弹性伸缩。网上找到的…...

workman服务端开发模式-应用开发-vue-element-admin挂载websocket

一、项目根目录main.js添加全局引入 import /utils/websocket 二、在根目录app.vue 中初始化WebSocket连接 <template><div id"app"><router-view /></div> </template><script>import store from ./store export default {n…...

堆排序【东北大学oj数据结构9-4】C++

堆排序是一种基于堆的数据结构的排序&#xff0c;是一种快速排序算法&#xff0c;可以在输入数组中实现排序处理&#xff08;内存高效&#xff09;。 堆排序可以实现如下&#xff1a; maxHeapify(A, i) l left(i) r right(i) // select the node which has the m…...

Linux RTC 驱动框架

目录 一、实时时钟&#xff08;RTC&#xff09;介绍1.1 概述1.2 功能1.3 应用场景1.4 工作原理1.5 对外接口1.6 常见 RTC 芯片1.7 在 Linux 系统中的应用1.8 注意事项 二、Linux 内核 RTC 驱动框架2.1 相关源码文件介绍2.2 核心数据结构2.2.1 struct rtc_device2.2.2 rtc_class…...

智能订餐:基于JSP的管理系统设计与优化

相关技术介绍 2.1 B/S结构 目前使用较多的开发结构模式大致可以包括C/S模式和B/S模式[5]。其中&#xff0c;C/S模式全称为客户端/服务器模式&#xff08;Client/Server模式&#xff09;&#xff0c;B/S模式全称为浏览器/服务器模式&#xff08;Browser/Server模式&#xff09;。…...

Java基本查询(四)

JPA 查询All示例 JPA教程 - JPA查询All示例 我们可以在JPQL中使用带有子查询的ALL运算符。 List l em.createQuery("SELECT e FROM Professor e WHERE e.salary < " "ALL (SELECT d.salary FROM e.directs d)").getResultList();例子 下面的代码来自…...

【双指针算法】--复写零

文章目录 1. 题目2. 题目解析3. 代码 1. 题目 在线oj 给你一个长度固定的整数数组 arr &#xff0c;请你将该数组中出现的每个零都复写一遍&#xff0c;并将其余的元素向右平移。 注意&#xff1a;请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改&a…...

leetcode hot100 两两交换链表之中的节点

24. 两两交换链表中的节点 已解答 中等 相关标签 相关企业 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09; # Definition fo…...

Yolo11改进策略:主干网络改进|FastVit与Yolo11完美融合,重参数重构Yolo11网络(全网首发)

文章目录 摘要FastViT:一种使用结构重新参数化的快速混合视觉变换器1、简介2、相关工作3、体系结构3.1、概述3.2、FastViT3.2.1、重新参数化跳过连接3.2.2、线性训练时间过参数化3.2.3、大核卷积4、实验4.1、图像分类4.2、鲁棒性评价4.3、3D Hand网格估计4.4、语义分割和目标检…...

vscode打开下一个文件的时候上一个文件会关闭

解决方法&#xff1a; 你可以通过设置 workbench.editor.enablePreview 来控制在 VS Code 中打开文件时是否会关闭上一个文件。将其设置为 false 可以防止这种行为。 {"workbench.editor.enablePreview": false } 在设置编辑器中显示 "workbench.editor.enab…...

windows使用zip包安装MySQL

windows通过zip包安装MySQL windows通过zip包安装MySQL下载MySQL的zip安装包创建安装目录和数据目录解压zip安装包创建配置目录 etc 和 配置文件 my.ini安装MySQL进入解压后的bin目录执行命令初始化执行命令安装 验证安装查看服务已安装 启动MySQL查看服务运行情况修改密码创建…...

【LeetCode每日一题】——415.字符串相加

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时空频度】九【代码实现】十【提交结果】 一【题目类别】 字符串 二【题目难度】 简单 三【题目编号】 415.字符串相加 四【题目描述】 给定两个字符…...

基于角色的访问控制(RBAC)在异构系统中的应用

在数字化蓬勃发展的当下&#xff0c;企业运营高度依赖各类异构系统。基于角色的访问控制&#xff08;RBAC&#xff09;成为管理这些系统中用户权限的核心策略。RBAC 依据组织内的岗位、职责定义角色&#xff0c;按角色分配权限&#xff0c;用户凭借所属角色获取相应访问权&…...

FPGA实现MIPI转FPD-Link车载同轴视频传输方案,基于IMX327+FPD953架构,提供工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐本博主所有FPGA工程项目-->汇总目录我这里已有的 MIPI 编解码方案 3、本 MIPI CSI-RX IP 介绍4、详细设计方案设计原理框图IMX327 及其配置FPD-Link视频串化-解串方案MIPI CSI RX图像 ISP 处理图像缓存HDMI输出工程源码架构 5、…...

远程控制macOS一直卡在100%,能连接上了却只显示了壁纸?

前言 前段时间有个朋友过来咨询关于Windows使用第三方远程软件&#xff08;向日葵、Todesk等&#xff09;远程连接控制macOS系统&#xff0c;但出现了一些奇奇怪怪的问题。 比如在连接的时候&#xff0c;一直卡在100%连接&#xff0c;对方的电脑却已经显示已经被控制的状态。…...

springboot中使用gdal将表中的空间数据转shapefile文件

springboot中使用gdal将表中的空间数据转shapefile文件 代码&#xff1a; // 样本导出-将样本表导出为shapefile&#xff0c;复制样本shp文件到临时目录下 sampleDir是文件夹pathpublic void setYbShapeFile(Yb yb, File sampleDir) {// 创建 前时项 和 后时项 文件夹File y…...

捋一捋相关性运算,以及DTD和NLP中的应用

捋一捋相关性运算&#xff0c;以及DTD和NLP中的应用 相关性和相干性,有木有傻傻分不清相关性数字信号的相关运算同维度信号的相关理解 相关--互相关--相干 回声消除过程如何套用这些知识相关性/相干性检测在DT中的应用参考 相关性和相干性,有木有傻傻分不清 这是容易混淆的两个…...

Calcite Web 项目常见问题解决方案

Calcite Web 项目常见问题解决方案 calcite-web Authoritative front-end development resources for Calcite design initiative. Includes extendable base components and styles, as well as a modular and efficient framework for ArcGIS properties. [这里是图片001] 项…...

3090. 每个字符最多出现两次的最长子字符串

题目内容&#xff1a; 给你一个字符串 s &#xff0c;请找出满足每个字符最多出现两次的最长子字符串&#xff0c;并返回该 子字符串 的 最大 长度。 示例 1&#xff1a; 输入&#xff1a; s "bcbbbcba" 输出&#xff1a; 4 解释&#xff1a; 以下子字符串长…...

基于微信小程序的短视频系统(SpringBoot)+文档

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…...

Git的简介

文章目录 一.Git是什么二.核心概念三.工作流程四.Git的优势 下载Git 推荐官网下载 官网地址 一.Git是什么 Git是一个分布式版本控制系统&#xff0c;用于跟踪文件的变化并协调多人对同一项目的开发工作。它就像是一个时光机器&#xff0c;能够记录文件在不同时间点的状态&…...

【XR】ATW

异步时间扭曲&#xff08;Asynchronous Timewarp&#xff0c;简称ATW&#xff09;是一种在虚拟现实&#xff08;VR&#xff09;技术中使用的算法&#xff0c;它通过生成中间帧来减少因帧率不足导致的抖动和延迟&#xff0c;从而提高用户体验。ATW技术在两个线程中完成时间扭曲的…...

记Fastjson2的一个报ConcurrentModificationException的bug

错误背景&#xff1a;fastjson2的parseObject方法&#xff0c;在spring webflux项目中被调用&#xff0c;有时会报java.util.ConcurrentModificationException错误。报错处的代码如下图&#xff1a; 改了半天与并发安全相关的代码&#xff0c;还是会报此错误。后来改变思路搜…...

JAVAweb学习日记(二)JavaScript

一、概念 二、JavaScript引入方式 三、JavaScript书写语法 输出语句&#xff1a; 变量&#xff1a; 数据类型、运算符、流程控制语句&#xff1a; 数据类型&#xff1a; 运算符&#xff1a; 字符串如果是 数字字符构成&#xff0c;先把读到的数字转为数字类型&#xff0c;后续…...

FPGA学习(基于小梅哥Xilinx FPGA)学习笔记

文章目录 一、整个工程的流程二、基于Vivado的FPGA开发流程实践&#xff08;二选一多路器&#xff09;什么是二选一多路器用verilog语言&#xff0c;Vivado软件进行该电路实现1、设计输入&#xff1a;Design Sources中的代码2、分析和综合&#xff1a;分析设计输入中是否有错误…...

Linux的VIM基本操作

编辑模式转换 编辑指令 linux用vim编辑代码&#xff0c;再用gcc进行编译 编辑命令如下 gcc编译如下...

2024年12月英语六级CET6写作与翻译笔记

目录 1 写作 1.1 大学为学生提供了探索各种可能性 1.2 自律在个人成长中的重要性 1.3 切实可行的目标 2 翻译 2.1 洋山港(Yangshan Port) 2.2 中国航天事业 2.3 北斗卫星导航系统 1 写作 1.1 大学为学生提供了探索各种可能性 1.2 自律在个人成长中的重要性 1.3 切实可…...

学习记录:electron主进程与渲染进程直接的通信示例【开箱即用】

electron主进程与渲染进程直接的通信示例 1. 背景&#xff1a; electronvue实现桌面应用开发 2.异步模式 2.1使用.send 和.on的方式 preload.js中代码示例&#xff1a; const { contextBridge, ipcRenderer} require(electron);// 暴露通信接口 contextBridge.exposeInMa…...

领域自适应

领域自适应&#xff08;Domain Adaptation&#xff09;是一种技术&#xff0c;用于将机器学习模型从一个数据分布&#xff08;源域&#xff09;迁移到另一个数据分布&#xff08;目标域&#xff09;。这在源数据和目标数据具有不同特征分布但任务相同的情况下特别有用。领域自适…...

Kubeadm+Containerd部署k8s(v1.28.2)集群(非高可用版)

KubeadmContainerd部署k8s(v1.28.2)集群&#xff08;非高可用版&#xff09; 文章目录 KubeadmContainerd部署k8s(v1.28.2)集群&#xff08;非高可用版&#xff09;一.环境准备1.服务器准备2.环境配置3.设置主机名4.修改国内镜像源地址5.配置时间同步6.配置内核转发及网桥过滤 …...

重温设计模式--职责链模式

文章目录 职责链模式的详细介绍C 代码示例C示例代码2 职责链模式的详细介绍 定义与概念 职责链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为型设计模式&#xff0c;它旨在将请求的发送者和多个接收者解耦&#xff0c;让多个对象都有机会处理请求&a…...

单点登录平台Casdoor搭建与使用,集成gitlab同步创建删除账号

一&#xff0c;简介 一般来说&#xff0c;公司有很多系统使用&#xff0c;为了实现统一的用户名管理和登录所有系统&#xff08;如 GitLab、Harbor 等&#xff09;&#xff0c;并在员工离职时只需删除一个主账号即可实现权限清除&#xff0c;可以采用 单点登录 (SSO) 和 集中式…...

【Rust自学】5.1. 定义并实例化struct

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 5.1.1. 什么是struct struct的中文意思为结构体&#xff0c;它是一种自定义的数据类型&#xff0c;它允许程序为相关联的值命名和打包&am…...

vue-cli 5接入模块联邦 module federation

vue-cli 5接入模块联邦 module federation 模块联邦概念实现思路配置遇到的问题: 模块联邦概念 模块联邦由webpack 5最先推出的,让应用加载远程的代码模块来实现不同的Web应用共享代码片段.模块联邦分为两个角色,一个是生产者,一个是消费者.生产者暴露代码供消费者消费 (用一个…...

[前端]mac安装nvm(node.js)多版本管理

NVM功能简介 NVM&#xff08;Node Version Manager&#xff09;是一个用于管理多个Node.js版本的命令行工具&#xff0c;它允许开发者在同一台机器上安装、切换和卸载不同版本的Node.js&#xff0c;从而解决版本不兼容的问题。以下是NVM的一些主要功能和用途&#xff1a; 安装和…...

thinkphp8+layui分页

前端 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>demo</title><link href"//unpkg.com/layui2.9.20/dist/css/layui.css" rel"stylesheet"> </head> <…...

【NLP高频面题 - Transformer篇】Transformer的位置编码是如何计算的?

【NLP高频面题 - Transformer篇】Transformer的位置编码是如何计算的&#xff1f; 重要性&#xff1a;★★★ NLP Github 项目&#xff1a; NLP 项目实践&#xff1a;fasterai/nlp-project-practice 介绍&#xff1a;该仓库围绕着 NLP 任务模型的设计、训练、优化、部署和应用…...

VSCode搭建Java开发环境 2024保姆级安装教程(Java环境搭建+VSCode安装+运行测试+背景图设置)

名人说&#xff1a;一点浩然气&#xff0c;千里快哉风。—— 苏轼《水调歌头》 创作者&#xff1a;Code_流苏(CSDN) 目录 一、Java开发环境搭建二、VScode下载及安装三、VSCode配置Java环境四、运行测试五、背景图设置 很高兴你打开了这篇博客&#xff0c;更多详细的安装教程&…...

计算机网络压缩版

计算机网络到现在零零散散也算过了三遍&#xff0c;一些协议大概了解&#xff0c;但总是模模糊糊的印象&#xff0c;现在把自己的整体认识总结一下&#xff0c;&#xff08;本来想去起名叫《看这一篇就够了》&#xff0c;但是发现网上好的文章太多了&#xff0c;还是看这篇吧&a…...

大语言模型中的Agent;常见的Agent开发工具或框架

大语言模型中的Agent 大语言模型中的Agent是指以大语言模型为核心驱动,具有自主理解、感知、规划、记忆和使用工具等能力,能够自动化执行复杂任务的系统.以下是一些例子: AutoGPT:它相当于一个完整的工具包,可以为各种项目构建和运行自定义AI Agent。使用OpenAI的GPT-4和…...

设计模式-备忘录模式

背景 游戏角色恢复问题&#xff1a;角色有攻击力和防御力&#xff0c;在Boss站前保存攻击力和防御力&#xff0c;大战之后&#xff0c;攻击力和防御力下降&#xff0c;从备忘录恢复到大战前的状态。 传统思路&#xff1a; 一个游戏对象&#xff0c;对应一个保存状态对象。 …...

重温设计模式--状态模式

文章目录 状态模式&#xff08;State Pattern&#xff09;概述状态模式UML图作用&#xff1a;状态模式的结构环境&#xff08;Context&#xff09;类&#xff1a;抽象状态&#xff08;State&#xff09;类&#xff1a;具体状态&#xff08;Concrete State&#xff09;类&#x…...

道可云人工智能元宇宙每日资讯|2024(GIAC)智能视听大会在青岛举行

道可云元宇宙每日简报&#xff08;2024年12月23日&#xff09;讯&#xff0c;今日元宇宙新鲜事有&#xff1a; 2024&#xff08;GIAC&#xff09;智能视听大会在青岛举行 12月22日&#xff0c;2024&#xff08;GIAC&#xff09;智能视听大会在青岛举行。大会以“数字文化 智能…...