【嵌入式裸机开发】智能家居入门7:最新ONENET,MQTT协议接入,最全最新(微信小程序、MQTT协议、ONENET云平台、STM32)

news2024/12/27 16:34:13

智能家居入门7

    • 前言
    • 一、ONENET云平台创建产品与设备
    • 二、STM32端连接服务器前的准备
    • 三、STM32端实现
    • 四、微信小程序端连接服务器前的准备
    • 五、微信小程序端实现
    • 六、最终测试

前言

本篇文章介绍最新ONENET云平台的MQTT协议接入方法,在STM32上实现数据上云与服务器下发数据解析,以及微信小程序接入服务器。对于智能家居而言,最重要的就是通信,通信是否稳定是否响应快,这是最重要的,外设的连接与控制这些都是很简单的,网上的一搜直接就有现成的代码,所以本篇博客不会介绍关于外设的使用与控制,主要介绍最新ONENET的接入与消息解析,这个框架搭好以后,其它外设连接那都不是事儿。

硬件准备:
STM32F103C8T6
ESP8266-01S
OLED液晶显示屏或串口调试模块(USB转TTL)
DHT11(可有可无,自己虚构上传数据也可以)
烧录器


一、ONENET云平台创建产品与设备

这部分直接以视频的形式给出:

需要注意的点:
①数据协议:
这里选择的是OneJson,当然也可以选择数据流,但是它们对应的发送数据和接收数据的topic是不一样的,所以如果想省事直接使用本文代码,那就选择OneJson。
在这里插入图片描述

②新版三元组:
按照视频创建完毕后,进入设备管理的设备详情中,可以看到后续会用到的三个参数:
在这里插入图片描述


二、STM32端连接服务器前的准备

①token:
首先计算token,在连接时会用到:
在这里插入图片描述
上图中的clienid和username就是新版三元组中包含的其中两个参数:设备名称、产品ID,password就是使用官方软件计算生成的token。
接下来视频演示如何计算token:

重点提取如下:
在这里插入图片描述
纠错:上图中的时间过小,在后面多加随便一个数字既可:2810295937232。

②STM32端OneJson数据协议对应的发布、订阅topic:
在创建产品时我们选择的数据协议是OneJson,文档中有明确给出OneJson数据协议(物模型)的发布和订阅topic,如果数据协议选择数据流的小伙伴,在文档的这个界面往后翻翻就可以看到对应的。
在这里插入图片描述
在代码中,首先连接服务器,成功之后就可以订阅主题或者发布数据到主题中。
我们不止要知道发布订阅主题,对于上传数据而言还要知道上传的数据格式;对于订阅服务器下发的数据而言,还需要知道数据格式,以便于解析,下面第三点来介绍这些。

③STM32端OneJson数据协议对应的数据格式::
1、设备属性上报OneJSON数据格式:
在这里插入图片描述
图中很容易看出来数据格式中有些可以不用填,本文最终上传的数据格式如下:

{
  "id": "123",
  "params": {
    "temp": {
      "value": 25.00,
    },
    "humi": {
      "value": 70.00,
    }
  }
}

2、设备属性设置OneJSON数据格式(服务器下发数据):
在这里插入图片描述
本文代码中订阅话题之后,若是服务器下发数据,STM32端就会收到,打印出接收到的数据如下:

 +MQTTSUBRECV:0,"$sys/bs2u21MIHC/dht11/thing/property/set",54,{"id":"208","version":"1.0","params":{"fan_ctl":true}}

代码中会对此消息进行解析,就可以将控制命令给解出来进行动作了。

④esp8266-01s烧录新的mqtt固件:
下载固件与烧录软件:通过百度网盘分享的文件:new_onenet_mqtt固件烧录.rar
链接:https://pan.baidu.com/s/1aAEqlCVyUB-9ZoaFU0qf2w?pwd=1yjb 提取码:1yjb

具体烧录过程参考:https://blog.csdn.net/jackcsdnfghdtrjy/article/details/104770612

三、STM32端实现

上传数据至服务器这部分,是参考的b站视频(彼岸有光我们有船),数据接收与解析为原创,干货来咯。
相较于之前的智能家居stm32端代码,本文的NET相关代码只剩下面两个即可:
在这里插入图片描述

esp8266.cpp:

//单片机头文件
#include "stm32f10x.h"

//网络设备驱动
#include "esp8266.h"

//硬件驱动
#include "delay.h"
#include "usart.h"

//C库
#include <string.h>
#include <stdio.h>
#include "cJSON.h"
#include <stdlib.h>

#define WIFI_SSID 						"wzqzq"								//	WIFI名
#define WIFI_PSWD 						"12345678"				//	WIFI密码

#define ESP8266_WIFI_INFO			"AT+CWJAP=\"" WIFI_SSID "\",\"" WIFI_PSWD "\"\r\n"

#define ESP8266_ONENET_INFO		"AT+MQTTCONN=0,\"mqtts.heclouds.com\",1883,1\r\n"

#define ESP8266_USERCFG_INFO  "AT+MQTTUSERCFG=0,1,\"dht11\",\"bs2u21MIHC\",\"version=2018-10-31&res=produmd5&sign=dkKx5uuWp0sMqet7BJGa2w%3D%3D\",0,0,\"\"\r\n"

const char* pubtopic="$sys/bs2u21MIHC/dht11/thing/property/post";
const char* subtopic="$sys/bs2u21MIHC/dht11/thing/property/set";

unsigned char esp8266_buf[ESP_RX_MAX];
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0;

extern u8 ESP8266_INIT_OK;

char bool_value[12];
char *new_json;

//	函数功能:	清空缓存
void ESP8266_Clear(void)
{
	memset(esp8266_buf, 0, sizeof(esp8266_buf));
	esp8266_cnt = 0;
}

//	函数功能:	等待接收完成
_Bool ESP8266_WaitRecive(void)
{
	if(esp8266_cnt == 0) 							//如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数
		return REV_WAIT;
		
	if(esp8266_cnt == esp8266_cntPre)				//如果上一次的值和这次相同,则说明接收完毕
	{
		esp8266_cnt = 0;							//清0接收计数
			
		return REV_OK;								//返回接收完成标志
	}
		
	esp8266_cntPre = esp8266_cnt;					//置为相同
	
	return REV_WAIT;								//返回接收未完成标志

}

//	函数功能:	发送命令
_Bool ESP8266_SendCmd(char *cmd, char *res)
{
	
	unsigned char timeOut = 200;

	Usart_SendString(USART2, (unsigned char *)cmd, strlen((const char *)cmd));
	
	while(timeOut--)
	{
		if(ESP8266_WaitRecive() == REV_OK)							//如果收到数据
		{
			if(strstr((const char *)esp8266_buf, res) != NULL)		//如果检索到关键词
			{
				ESP8266_Clear();									//清空缓存
				
				return 0;
			}
		}
		
		delay_ms(10);
	}
	
	return 1;

}

//	函数功能:	发送数据
void ESP8266_SendData(double temp,double humi,double adcx)
{
	char cmdBuf[512];
	
	ESP8266_Clear();								//清空接收缓存
	
	//先发送要发送数据的指令做准备
	
	sprintf(cmdBuf, "AT+MQTTPUB=0,\"%s\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"temp\\\":{\\\"value\\\":%.2f\\}\\,\\\"humi\\\":{\\\"value\\\":%.2f\\}\\,\\\"ch4\\\":{\\\"value\\\":%.2f\\}}}\",0,0\r\n",pubtopic,temp,humi,adcx);		//发送命令
	while(ESP8266_SendCmd(cmdBuf, "OK"))
		delay_ms(500);
	memset(cmdBuf,0,sizeof(cmdBuf));
	delay_ms(100);
}

//订阅话题
void ESP8266_sub()
{
	char cmdBuf[512];
	
	ESP8266_Clear();								                          //清空接收缓存
	sprintf(cmdBuf, "AT+MQTTSUB=0,\"%s\",0\r\n", subtopic);		//发送命令
	
	while(ESP8266_SendCmd(cmdBuf, "OK"))
		delay_ms(500);
	memset(cmdBuf,0,sizeof(cmdBuf));
	delay_ms(100);
}
//键值对提取
char * extract_json(const char *src) {
    // 找到 "params" 字段的开始位置
    const char *start = strstr(src, "params");
	  DEBUG_LOG("JSON: %s\n",src);
    if (start) {
        // 跳过 "params" 字符串的长度
        start += strlen("params");
        
        // 找到 '{' 字符的位置,表示 params 对象的开始
        while (*start && *start != '{') {
            start++;
        }
        if (*start == '{') {
            // 从 '{' 开始复制,直到 '}' 或字符串结束
            const char *end = strchr((char *)start, '}');
            if (end) {
                // 计算需要复制的长度
                size_t len = (size_t)(end - start);
                // 创建一个新的缓冲区并复制目标字符串
                char *new_json = (char *)malloc(len + 2); // +1 为了空字符,+1 为了避免潜在的 '{'
                if (new_json) {
                    strncpy(new_json, start, len);
                    new_json[len] = '}'; // 添加 '}' 以确保 JSON 结束
                    new_json[len + 1] = '\0'; // 确保以空字符结尾
										DEBUG_LOG("Extracted JSON: %s\n",new_json);
										return new_json;
                }
            }
        }
    }
}

//解析
void parse_onenet_command(const char *json_str) {
    cJSON *json, *led_ctl_item, *fan_ctl_item;
	
	  char* temp = extract_json(json_str);

    json = cJSON_Parse(temp);
    if (json == NULL) {
        // 处理 JSON 解析错误
        const char *error_ptr = cJSON_GetErrorPtr();
        printf("Error parsing JSON: %s\n", error_ptr);
        return;
    }

    // 直接获取 "led_ctl" 的值
    led_ctl_item = cJSON_GetObjectItem(json, "led_ctl");
    if (led_ctl_item != NULL)
		{
			  if(led_ctl_item -> valueint)
				{
						DEBUG_LOG("led open\n");
				}
				else
				{
						DEBUG_LOG("led close\n");
				}
    } 
	fan_ctl_item = cJSON_GetObjectItem(json, "fan_ctl");
	if (fan_ctl_item != NULL)
	{
			if(fan_ctl_item -> valueint)
			{
					DEBUG_LOG("fan open\n");
			}
			else
			{
					DEBUG_LOG("fan close\n");
			}
	}

    // 清理并释放内存
	free(new_json);
	free(temp);
    cJSON_Delete(json);
}


//主函数或者定时器中循环调用,如果esp8266接收到数据,就解析
unsigned char *ESP8266_GetIPD(unsigned short timeOut)
{
	char *ptrIPD = NULL;
	
	do
	{
		if(ESP8266_WaitRecive() == REV_OK)								//如果接收完成
		{
			parse_onenet_command((const char *)esp8266_buf);
		}
		delay_ms(5);
		timeOut--;	//延时等待
	} while(timeOut > 0);
	
	return NULL;														//超时还未找到,返回空指针

}

//	函数功能:	初始化ESP8266
void ESP8266_Init(void)
{
	ESP8266_Clear();
	
	DEBUG_LOG("0. AT - 测试MCU-8266通讯");
	while(ESP8266_SendCmd("AT\r\n", "OK"))
		delay_ms(500);
	
	DEBUG_LOG("1. AT+RST - 软复位8266");
	ESP8266_SendCmd("AT+RST\r\n", "");
		delay_ms(500);
	ESP8266_SendCmd("AT+CIPCLOSE\r\n", "");
		delay_ms(500);
	DEBUG_LOG("2. AT+CWMODE=1,1 - 设置8266工作模式为STA");
	while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))
		delay_ms(500);
	
	DEBUG_LOG("3. AT+CWDHCP=1,1 - 使能STA模式下DHCP");
	while(ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK"))
		delay_ms(500);
	
	DEBUG_LOG("4. AT+CWJAP - 连接WIFI -> [ SSID: %s ]  -> [ Password: %s ] ",WIFI_SSID, WIFI_PSWD);
	while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))
		delay_ms(500);
	
	DEBUG_LOG("6. AT+MQTTUSERCFG=0,1 - 设置user信息:ID,devicename,token");
	while(ESP8266_SendCmd(ESP8266_USERCFG_INFO, "OK"))
		delay_ms(500);

	
	DEBUG_LOG("7. AT+MQTTCONN=0 - 连接服务器:ip,端口号");
	while(ESP8266_SendCmd(ESP8266_ONENET_INFO, "OK"))
		delay_ms(500);
	
	DEBUG_LOG("服务器已连接");
}


//	函数功能:	串口2收发中断
void USART2_IRQHandler(void)
{

	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收中断
	{
		if(esp8266_cnt >= sizeof(esp8266_buf))	esp8266_cnt = 0; //防止串口被刷爆
		esp8266_buf[esp8266_cnt++] = USART2->DR;
		
		
		USART_ClearFlag(USART2, USART_FLAG_RXNE);
	}

}

集成到自己的代码时需要修改wifi、产品ID、设备名称、token、发布订阅话题、发送数据中的标识符要与自己在云平台创建的一致。重要代码的注释也写的很清楚了,结合上面讲的那些话题与数据格式,很容易就可以看懂。
这部分代码解决之后就可以使用云平台进行测试了,测试过程如下视频:

四、微信小程序端连接服务器前的准备

跟第二节一样,也需要准备token,前面已经弄好了,直接复制即可。

①onenet 云端API介绍:
通过阅读onenet物联网开放平台的文档,发现OneNET API提供产品、设备、服务等云端API,使用标准HTTP方法实现资源CURD操作,其中URL中的中文参数使用UTF-8编码。具体的大家可以去看文档,写的很清楚,所以微信小程序使用这种方式接入服务器。
在这里插入图片描述
从文档中的接口列表可以看到物模型使用的接口:
在这里插入图片描述

②具体的使用方式如下:
1、设备属性最新数据查询(微信小程序从服务器获取数据):
在这里插入图片描述
文档往下翻可以看到使用示例,微信小程序中参考这种格式即可:
在这里插入图片描述
2、设备属性期望设置(微信小程序发布数据到图中所示的接口地址,此时服务器对应的就会将此数据发布到:$sys/{pid}/{device-name}/thing/property/set这个话题中,这个话题也就是stm32端订阅的话题,这样32端就会接收到微信小程序下发的指令):
在这里插入图片描述
文档往下翻可以看到使用示例,微信小程序中参考这种格式即可:
在这里插入图片描述
有了上面这两个示例,就可以在微信小程序中进行代码的编写了!

五、微信小程序端实现

index.js

Page({
    data: {
     temp:0.0,
     humi:0.0,
     gas_ch4:0.0,
     fumes:0.0,
     leds:false,
     fen:false,
     water:false
    },
   /* 获取OneNET云平台设备数据 */
     getinfo() {
    /* 发起 HTTPS 网络请求 获取设备参数 */
    wx.request({
        /* 网址、产品ID、设备名 */
        url: "https://iot-api.heclouds.com/thingmodel/query-device-property?product_id=bs2u21MIHC&device_name=dht11",

        header: {
            /* 用户鉴权信息 */
            "authorization": "version=2018-10-31&res=products%2Fbs2u21MIHC%2Fdevices%2Fdht11&et=2810295937232&method=md5&sign"
        },
       
        method: "GET",   /* HTTP 请求方法:获取 */
        success: res => {
            console.log("获取成功", res)
            this.setData({
               humi: res.data.data[3].value,
               temp: res.data.data[5].value,
               gas_ch4: res.data.data[0].value,
            })
        }
    });
  },

   //下发指令:led
   onledsChange(event){
    const that = this
    console.log(event.detail.value);
    const sw = event.detail.value
    that.setData({leds:sw})

    if(sw){
      wx.request({
        url: 'https://iot-api.heclouds.com/thingmodel/set-device-property',
        method: 'POST',
        header: {
            /* 用户鉴权信息 */
            "authorization": "version=2018-10-31&res=products%2Fbs2u21MIHC%2Fdevices%2Fdht11&et=2810295937232&method=md5&sign"
        },
        data: {
            "product_id": "bs2u21MIHC",
            "device_name": "dht11",
            "params": {
                "led_ctl": true   /* 控制板端LED */
            }
        },
         success(res){
           console.log("成功",res.data)
         },
         fail(res){
           console.log("失败",res)
         }
       })
    }else{
      wx.request({
        url: 'https://iot-api.heclouds.com/thingmodel/set-device-desired-property',
        method: 'POST',
        header: {
            /* 用户鉴权信息 */
            "authorization": "version=2018-10-31&res=products%2Fbs2u21MIHC%2Fdevices%2Fdht11&et=2810295937232&method=md5&sign"
        },
        data: {
            "product_id": "bs2u21MIHC",
            "device_name": "dht11",
            "params": {
                "led_ctl": false   /* 控制板端LED */
            }
        },
         success(res){
           console.log("成功",res.data)
         },
         fail(res){
           console.log("失败",res)
         }
       })
    }
  },

 //下发指令:风扇
 onfenChange(event){
  const that = this
  console.log(event.detail.value);
  const sw = event.detail.value
  that.setData({fen:sw})

  if(sw){
    wx.request({
      url: 'https://iot-api.heclouds.com/thingmodel/set-device-desired-property',
      method: 'POST',
      header: {
          /* 用户鉴权信息 */
          "authorization": "version=2018-10-31&res=products%2Fbs2u21MIHC%2Fdevices%2Fdht11&et=2810295937232&method=md5&sign"
      },
      data: {
          "product_id": "bs2u21MIHC",
          "device_name": "dht11",
          "params": {
              "fan_ctl": true   /* 控制板端空调 */
          }
      },
       success(res){
         console.log("成功",res.data)
       },
       fail(res){
         console.log("失败",res)
       }
     })
  }else{
    wx.request({
      url: 'https://iot-api.heclouds.com/thingmodel/set-device-desired-property',
      method: 'POST',
      header: {
          /* 用户鉴权信息 */
          "authorization": "version=2018-10-31&res=products%2Fbs2u21MIHC%2Fdevices%2Fdht11&et=2810295937232&method=md5&sign"
      },
      data: {
          "product_id": "bs2u21MIHC",
          "device_name": "dht11",
          "params": {
              "fan_ctl": false   /* 控制板端空调 */
          }
      },
       success(res){
         console.log("成功",res.data)
       },
       fail(res){
         console.log("失败",res)
       }
     })
  }
},

  sliderChanging:function(e){
    console.log(e.detail.value)
    wx.request({
      url: 'https://iot-api.heclouds.com/thingmodel/set-device-desired-property',
      method: 'POST',
      header: {
          /* 用户鉴权信息 */
          "authorization": "version=2018-10-31&res=products%2Fbs2u21MIHC%2Fdevices%2Fdht11&et=2810295937232&method=md5&sign"
      },
      data: {
          "product_id": "bs2u21MIHC",
          "device_name": "dht11",
          "params": {
              "curtain": e.detail.value   /* 控制板端窗帘,这个例子中stm32端没写 */
          }
      },
       success(res){
         console.log("成功",res.data)
       },
       fail(res){
         console.log("失败",res)
       }
     })
  },

    onLoad() {
      var that = this
      setInterval(function(){
        that.getinfo()
      },5000)
    }
  })
  
  

上面的代码也不是完整的,有了思路和格式就是非常大的帮助,大家可以参照这样的发布与请求数据的格式将代码集成到自己的项目中,进行自己的界面设计,注意替换产品ID、设备名称、鉴权信息(token)等。

六、最终测试

微信小程序代码也调试好之后,就可以进行联调了,开发板上电连接上服务器中,微信小程序观察能否接收到数据,并测试能否下发指令控制开发板,具体如下视频:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2065663.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

影像组学与病理组学在鼻咽癌领域的最新研究进展|文献速递·24-08-23

小罗碎碎念 今天这期推文收纳了人工智能在鼻咽癌领域的最新研究进展&#xff0c;既涉及影像组学也涉及病理组学。 在写这期推文的时候&#xff0c;刚好看到了国自然基金放榜的消息&#xff0c;在这里也祝各位关注小罗的老师能如愿上榜&#xff01;&#xff01; 正在积极备战…

LangChain框架深度解析:对Chains组件的全方位探索与实战案例

文章目录 前言一、Chains二、LLMChain⭐1.LLMChain介绍2.LLMChain案例 三、SimpleSequentialChain⭐1.SimpleSequentialChain介绍2.SimpleSequentialChain案例 四、SequentialChain⭐1.SequentialChain介绍2.SequentialChain案例 五、RouterChain⭐1.RouterChain介绍2.RouterCh…

ArcGIS空间自相关 (Global Moran‘s I)——探究人口空间格局的20年变迁

先了解什么是莫兰指数&#xff1f; 莫兰指数&#xff08;Morans I&#xff09;是一种用于衡量空间自相关性的统计量&#xff0c;即它可以帮助我们了解一个地理区域内的观测值是否彼此相关以及这种相关性的强度和方向。 白话版&#xff1a;一句话就是判断数据在空间上有没有自…

ChatGPT3.5/新手使用手册——在线使用详细操作步骤

成长路上不孤单&#x1f60a;【14后小学生一枚&#xff0c;C爱好者&#xff0c;持续分享所学&#xff0c;今日分享主题【ChatGPT新手使用手册】&#xff0c;需要欢迎收藏转发&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&…

学习笔记七:基于Jenkins+k8s+Git+DockerHub等技术链构建企业级DevOps容器云平台

基于Jenkinsk8sGitDockerHub等技术链构建企业级DevOps容器云平台 安装Jenkins在kubernetes中部署jenkins创建名称空间创建pv,上传pv.yaml创建pvc创建一个sa账号通过deployment部署jenkins更新资源清单文件把jenkins前端加上service&#xff0c;提供外部网络访问 配置Jenkins获取…

MQ的优缺点及适用场景

MQ的优缺点及适用场景 1、MQ的优点2、MQ的缺点 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 消息队列&#xff08;MQ&#xff09;在软件开发中扮演重要角色&#xff0c;带来解耦、异步、削峰等好处。然而&#xff0c;MQ的引入也伴随着一些…

【Hot100】LeetCode—101. 对称二叉树

目录 1- 思路借助队列 2- 实现⭐101. 对称二叉树——题解思路 3- ACM 实现 原题连接&#xff1a;101. 对称二叉树 1- 思路 借助队列 1- 创建队列&#xff1a;Queue<TreeNode> queue&#xff0c;初始化加入 root.left 和 root.right2- 判断逻辑&#xff1a;while(!queu…

为什么要进行微隔离

在当今数字化时代&#xff0c;随着云计算、大数据、物联网等技术的飞速发展&#xff0c;企业网络环境日益复杂&#xff0c;传统的网络边界防护策略面临着前所未有的挑战。传统的防火墙、入侵检测系统等安全设备虽然在一定程度上能够抵御外部威胁&#xff0c;但在内部网络的安全…

回归分析系列16— 多层次模型

119 多层次模型 19.1 简介 多层次模型&#xff08;也称为层次线性模型或混合效应模型&#xff09;在处理具有嵌套结构的数据时非常有用。例如&#xff0c;在教育数据中&#xff0c;学生嵌套在班级中&#xff0c;班级嵌套在学校中。多层次模型允许我们同时建模这些不同层次的影…

政安晨【零基础玩转各类开源AI项目】基于本地Linux Ubuntu系统部署及应用强大的开源AI音乐生成工具:AudioCraft

目录 简介 部署 下载项目 创建虚拟环境 激活虚拟环境 安装依赖 启动 成功 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 简介 A…

c++每日练习记录4-(递归思想)

题解1迭代&#xff1a; 利用利用两个新的指针&#xff0c;一个用于保存输出的初始节点&#xff0c;另外一个用于地址的迭代指向。 ListNode *mergeTwoLists(ListNode *list1, ListNode *list2){ListNode *list_node new ListNode(0);ListNode *list_node1 list_node;while (l…

看图学sql之sql 中的UNION 和union all

UNION 用于合并两个或者多个 SELECT 语句的结果集 语法&#xff1a; SELECT column1, column2 ... FROM table1, table2 [WHERE condition1]UNION / UNION ALLSELECT column1, column2 ... FROM table1, table2 [WHERE condition2] 数据分析社区直达 免费数据分析资料下载。…

C#使用 ModeBusTCP读取汇川Easy521PLC

Modbus TCP是一种基于以太网TCP/IP的Modbus协议变种&#xff0c;它允许Modbus协议在以太网网络上运行&#xff0c;使得设备之间可以通过IP网络交换数据。Modbus由MODICON公司于1979年开发&#xff0c;是一种工业现场总线协议标准&#xff0c;广泛应用于工业自动化领域。 #regio…

【嵌入式】总结指南——Linux下的裸机驱动开发

板型:正点原子 I.MX6UL MINI 屏幕&#xff1a;7寸 1024*600 立意&#xff1a;既是这一段学习的总结&#xff0c;也可作为入门指南的参考&#xff0c;不过并不能作为教程来看&#xff0c;实际学习还是要找相应的视频或文章教程。 一、历程 应该和使用这块板子的大部分人一样&a…

理解List AbstractList ArrayList

ArrayList 实现了 List 接口&#xff0c;继承了 AbstractList 抽象类。 Q: 为什么要ArrayList继承AbstractList&#xff0c;让AbstractList实现List&#xff1f;而不是让ArrayList直接实现List&#xff1f; A: 接口中全都是抽象的方法&#xff0c;而抽象类中可以有抽象方法&am…

【达梦数据库】shell脚本获取集群内确认监视器地址

目录 1、需求2、想法3、实现代码4、检验效果4.1、集群内任意节点使用非dmdba用户执行4.2、集群内任意节点使用dmdba用户执行4.2.1、数据库主备节点执行4.2.1、数据库确认监视器节点执行 4.3、非集群内节点执行 1、需求 有确认监视器的集群&#xff0c;在集群的任何一个集群上执…

Android13 app后台无法启动Abort background activity starts from

总纲 android13 rom 开发总纲说明 目录 1.前言 2.log分析 3.代码查找分析 4.修改方法 5.编译测试 6彩蛋 1.前言 Android13 用户app后台无法启动,提示Abort background activity starts from 10111 2.log分析 08-07 21:37:36.703: W/ActivityTaskManager(440): Back…

Llama3.1大模型

背景 Llama 3.1是一款由Meta&#xff08;前Facebook&#xff09;推出的先进大型语言模型。它在自然语言处理领域具有显著优势&#xff0c;为用户提供高质量的文本生成、理解和推理能力。 Transformer架构 Transformer是一种神经网络架构&#xff0c;可以处理文本、音频、视频和…

无线数传模块有啥特点?

一 、 模块特点  支持 RS485RTU 、RS232、UART 标准协议  AES加密  供电电压DC4.5V——5.5V  工作频段 410~525MHz, 免申请频段  标准配置提供多达 115信道 …

数据结构-递归算法-第四天

参考文献&#xff1a; 华为云 博客园 labuladong 的算法笔记 递归是一种编程技巧&#xff0c;一种解决问题的思维方式&#xff1b;分治算法和动态规划很大程度上是递归思想基础上的&#xff08;虽然动态规划的最终版本大都不是递归了&#xff0c;但解题思想还是离不开递归&…