小项目:使用MQTT上传温湿度到Onenet服务器

前言

我们之前分别编写了 DHT11、ESP8266 和 MQTT 的代码,现在我们将它们仨整合在一起,来做一个温湿度检测小项目。这个项目可以实时地将 DHT11 传感器获取到的温湿度数据上传到 OneNET 平台。通过登录 OneNET,我们随时随地可以查看温湿度数据。

这种环境监测项目的应用场景有很多,其中特别适用于温室环境监测,园丁可以随时随地了解温室中空气情况,以确保温室环境适合娇贵的花草树木生长。

1. 源码下载及前置阅读

本文首发 良许嵌入式网 :https://www.lxlinux.net/e/ ,欢迎关注!

本文所涉及的源码及安装包如下(由于平台限制,请点击以下链接阅读原文下载):

https://www.lxlinux.net/e/stm32/little-project-dht11-esp8266-onenet.html

如果你是嵌入式开发小白,那么建议你先读读下面几篇文章。

  • STM32下载程序的五种方法:https://www.lxlinux.net/e/stm32/five-ways-to-flash-program-to-stm32.html
  • 一文教你使用MDK开发工具:https://www.lxlinux.net/e/stm32/mdk-development-tool-tutorial.html
  • 零基础快速上手STM32开发(手把手保姆级教程):https://www.lxlinux.net/e/stm32/stm32-quick-start-for-beginner.html

前期教程,没看过的小伙伴可以先看下。

  • 手把手教你玩转ESP8266(原理+驱动):https://www.lxlinux.net/e/stm32/esp8266-tutorial.html
  • 手把手教你玩转DHT11(原理+驱动):https://www.lxlinux.net/e/stm32/dht11-tutorial.html
  • 万字猛文:MQTT原理及案例:https://www.lxlinux.net/e/stm32/mqtt-turorial.html

2. 整体系统设计

使用 STM32F103C8T6 作主控芯片,配合 DHT11 温湿度传感器,实时监测周围环境的温湿度变化。通过 ESP8266 模块以 MQTT 协议将获取到的温湿度数据通过无线网络连接上传至 OneNET 平台,以便用户可以随时随地通过手机或电脑查看数据。

3. 硬件选型

本教程使用的硬件如下:

  • 单片机:STM32F103C8T6

这款单片机具有 64K flash,20K RAM,4 个定时器,3 个串口,网络上资料好几吨,非常适合初学者入门,强烈推荐。

  • WiFi模块:ESP-01S(ESP8266)

ESP8266 可以利用串口与单片机进行通讯,从而编程实现控制。

  • 温湿度传感器:DHT11

DHT11 有 3 脚和 4 脚两款,在使用上没有差别,接线都一样,主要接三根,四脚的款式有一脚悬空。四脚款接杜邦线会有点不稳,适合插面包板或开发板上。

DHT11 工作参数:

  1. 湿度测量范围:20~90%RH
  2. 湿度测量精度:±5%RH
  3. 温度测量范围:0~50℃
  4. 温度测量精度:±2℃
  5. 工作电压:DC 3.3V/5V
  • 串口:USB 转 TTL

这种设备主要作用是用来调试或下载程序,本文用于串口输出作调试。价格也很便宜,普遍 5~8 元。

  • 烧录器:ST-LINK V2

ST-Link 是一种用于 STM32 微控制器的调试和编程工具,它可以通过 SWD 或 JTAG 接口与开发板进行通信。本文用做烧录。一般也很便宜,七八元左右。

4. OneNET 物联网平台

MQTT 服务端可以是云平台,OneNET、阿里云、华为云、腾讯云等;也可以自己搭建服务端,用 EMQ 或 Mosquitto 。

本次我们使用 OneNET,接下来我们来配置一下 OneNET。

点开 OneNET 官方网址:中移坤灵 - 中国移动物联网开放平台 (10086.cn)

有账号的登录,没账号的注册一下。

登录好后点击「开发者中心」。

4.1 创建产品

接下来我们先创建一个产品,之后再创建具体的设备。

可按照下图参数创建产品。

4.2 创建物模型

通过物模型我们可以定义设备的属性、服务和事件功能。我们需要创建几个物模型,用于上传数据和事件告警。

创建两个物模型:

  • 当前湿度,用于存储实时湿度数据。
  • 当前温度,用于存储实时温度数据。

本教程只用到「当前湿度」和「当前温度」,剩下的物模型是下篇教程使用的。

4.3 创建设备

接下来就开始创建产品下的具体设备。

4.4 生成MQTT三元组

「MQTT 三元组」是 MQTT 协议中至关重要的,就像去考试的时候,一定要带上准考证、身份证才能进考场,要有「MQTT 三元组」才能连接 MQTT 服务端。

得到初步「MQTT 三元组」:

  • 设备 ID:temp01
  • 产品 ID:P2k4KV0low
  • 设备密钥:REhWUEhWbDlIOTdRUFEzU1dGQXk4TlZKZ25oQ0N4S3M=

设备密钥需要经过加密,加密需要用 OneNET 官方的 token 生成工具。

官网下载地址:OneNET - 中国移动物联网开放平台 (10086.cn)

也可以拿文章开头提供的,也是官网下载的。

下载好 token 生成工具,打开界面如下,我来告诉大家每个空填啥。

各个参数介绍如下表:

名称类型参数说明参数示例
resstring访问资源 resource 格式为:products/{产品id}/devices/{设备名字}products/P2k4KV0low/devices/temp01
etint访问过期时间,单位秒,unix 时间。当一次访问参数中的 et 时间小于当前时间时,平台会认为访问参数过期从而拒绝该访问2017881776 表示:北京时间 2033-12-11 10:42:56
keystringMQTT 三元组的设备密钥REhWUEhWbDlIOTdRUFEzU1dGQXk4TlZKZ25oQ0N4S3M=
methodstring加密方式,支持 hmacmd5、hmacsha1、hmacsha256md5(代表使用hmacmd5算法)
sha1(代表使用hmacsha1算法)
sha256(代表使用hmacsha256 算法)
versionstring参数组版本号,日期格式,目前仅支持"2018-10-31"2018-10-31

et 的时间戳可以用这个在线工具转换,网页地址:时间戳(Unix timestamp)转换工具 - 在线工具 (tool.lu)

根据介绍,填好各个参数的空,我们选择 sha1 的加密方式,大家可以选择自己喜欢的。填好如下操作:

得到最终「MQTT 三元组」:

  • 设备 ID:temp01
  • 产品 ID:P2k4KV0low
  • token:version=2018-10-31&res=products%2FP2k4KV0low%2Fdevices%2Ftemp01&et=2017881776&method=sha1&sign=M3jVJvfeFLnggMrUPhYm5uRirXs%3D

4.5 主题订阅格式

4.5.1 OneNET地址

OneNET 服务器地址是 mqtts.heclouds.com : 1883,地址是从 OneNET 文档中心得到的。

4.5.2 订阅主题

选择设置直连设备属性:$sys/P2k4KV0low/{device-name}/thing/property/set

{device-name} 是设备ID,比如我们的就是 temp01。

4.5.3 上报主题

选择直连设备上报属性:$sys/P2k4KV0low/{device-name}/thing/property/post

{device-name} 是设备ID,比如我们的就是 temp01。

5. STM32 设备端开发

5.1 硬件接线

接线可参照下表:

ESP8266DHT11STM32USB 转 TTL
3V33.3
TXA3
RXA2
GNDG
VCC3.3
DATAA5
GNDG
A10TX
A9RX
GGND

烧录的时候接线如下表,如果不会烧录的话可以看我之前的文章 STM32下载程序的五种方法:https://www.lxlinux.net/e/stm32/five-ways-to-flash-program-to-stm32.html。

ST-Link V2STM32
SWCLKSWCLK
SWDIOSWDIO
GNDGND
3.3V3V3

5.2 设备实物图

接好如下图。

5.3 DHT11温湿度传感器代码

详细代码解析可以看手把手教你玩转DHT11(原理+驱动)。

5.3.1 读取1字节数据

将 DHT11 发来的二进制数据存储到 ReadData 变量中,读取一位后,左移一位,循环8次,最终得到 1 byte 数据。

那么如何判断我们读到的数据是 0 还是 1 呢?

通过 3.2.3 的分析可以知道,0 和 1 的时序只是高电平持续时间不同,所以我们只需要在 DHT11 拉低电平之后延时 40~60 微秒(代码中使用 50 微秒),再读取电平状态就可以了,如果是高电平则为 1,低电平则为 0 。

uint8_t DHT_Read_Byte(void)  //从DHT11读取一位(8字节)信号
{
    uint8_t i;
    uint8_t ReadData = 0;    //ReadData用于存放8bit数据,即8个单次读取的1bit数据的组合
    uint8_t temp;            //临时存放信号电平(0或1)

    for(i=0;i<8;i++){
        while(!HAL_GPIO_ReadPin(DHT11_IO, DHT11_PIN));
        Delay_us(50);
        if(HAL_GPIO_ReadPin(DHT11_IO, DHT11_PIN) == 1){
            temp = 1;
            while(HAL_GPIO_ReadPin(DHT11_IO, DHT11_PIN));
        }else{
            temp = 0;
        } 
        ReadData = ReadData << 1;
        ReadData |= temp;
    }
    return ReadData;
}
5.3.2 一次数据读取及显示

根据 DHT11 的时序,我们就可以使用代码实现 DHT11 一次读取数据过程。

注意:DHT11 读取数据间隔至少为 2 秒,否则读取到的数据可能不稳定,所以在最后可以延时 2 秒。

void DHT_Read()
{
    uint8_t i;

    DHT11_Start();
    DHT_GPIO_INPUT();

    for(i= 0;i < 5;i++){
        Data[i] = DHT_Read_Byte();
    }
    if((Data[0]+Data[1]+Data[2]+Data[3])==Data[4])
    {
        printf("湿度: %d.%dRH ,", Data[0], Data[1]);
        printf("温度: %d.%d℃\r\n", Data[2], Data[3]);
    }else{
        printf("ERROR DATA\r\n");
    }
    HAL_Delay(2000);
}

5.4 ESP8266模块代码

详细代码解析可以看手把手教你玩转ESP8266(原理+驱动)。

5.4.1 ESP8266 初始化

按照项目需求编写 ESP8266 初始化代码,我们需要将 ESP8266 设置工作模式为STA、单路连接模式、连接 WIFI 等操作。

uint8_t esp8266_init(uint32_t baudrate)
{
    char ip_buf[16];

    esp8266_uart_init(baudrate);                /* ESP8266 UART初始化 */

    /* 让WIFI退出透传模式 */
    printf("\r\n    退出透传模式\r\n");
    esp8266_exit_unvarnished();

    printf("    1.测试ESP8266是否存在(AT)\r\n");
    while(esp8266_at_test())
        delay_ms(500);

    printf("    2.重启ESP8266(AT+RST)\r\n");
    while(esp8266_sw_reset())
        delay_ms(500);
    while(esp8266_disconnect_tcp_server())
        delay_ms(500);

    printf("    3.设置工作模式为STA(AT+CWMODE=1)\r\n");
    while(esp8266_set_mode(ESP8266_STA_MODE))
        delay_ms(500);

    printf("    4.设置单路连接模式(AT+CIPMUX)\r\n");  //设置单路连接模式,透传只能使用此模式
    while(esp8266_single_connection())
        delay_ms(500);

    printf("    5.连接WiFi,SSID:%s,PWD:%s\r\n", WIFI_SSID, WIFI_PWD);      //连接WIFI
    while(esp8266_join_ap(WIFI_SSID, WIFI_PWD))
        delay_ms(1000);

    printf("    6.获取IP地址(AT+CIFSR):");
    while(esp8266_get_ip(ip_buf))
        delay_ms(500);

    printf("%s\r\n\r\n", ip_buf);

    printf("ESP8266初始化完成\r\n");
    return ESP8266_EOK;
}

初始化结束后连接 OneNET 服务器并进入透传模式。

void esp8266_connect_server(char *server_ip, char *server_port)
{
    esp8266_disconnect_tcp_server();
    printf("    7.连接云服务器(AT+CIPSTART),server_ip:%s,server_port:%s\r\n", server_ip, server_port);
    while(esp8266_connect_tcp_server(server_ip, server_port))
        delay_ms(500);

    printf("    8.进入透传模式(AT+CIPMODE)\r\n");
    while(esp8266_enter_unvarnished())
        delay_ms(500);

    printf("已连接上云服务器并进入透传模式。\r\n");
}

5.5 MQTT代码

5.5.1 CONNECT 报文

CONNECT 报文的编写及发送代码,报文编写就按照我们7.2节的理论编写即可,报文内容:10+剩余长度+00 04 4D 51 54 54 04 C2+保持连接时间+L+设备 ID+L+产品 ID+L+token。

uint8_t mqtt_connect(char *ClientID,char *Username,char *Password)
{
    uint8_t i,j;
    int ClientIDLen = strlen(ClientID);
    int UsernameLen = strlen(Username);
    int PasswordLen = strlen(Password);
    int DataLen;
    mqtt_txlen=0;
    //可变报头+Payload  每个字段包含两个字节的长度标识
    DataLen = 10 + (ClientIDLen+2) + (UsernameLen+2) + (PasswordLen+2);

    //固定报头
    //控制报文类型
    mqtt_txbuf[mqtt_txlen++] = 0x10;        //MQTT Message Type CONNECT
    //剩余长度(不包括固定头部)
    do
    {
        uint8_t encodedByte = DataLen % 128;
        DataLen = DataLen / 128;
        // if there are more data to encode, set the top bit of this byte
        if ( DataLen > 0 )
            encodedByte = encodedByte | 128;
        mqtt_txbuf[mqtt_txlen++] = encodedByte;
    }while ( DataLen > 0 );

    //可变报头
    //协议名
    mqtt_txbuf[mqtt_txlen++] = 0;            // Protocol Name Length MSB    
    mqtt_txbuf[mqtt_txlen++] = 4;           // Protocol Name Length LSB    
    mqtt_txbuf[mqtt_txlen++] = 'M';            // ASCII Code for M    
    mqtt_txbuf[mqtt_txlen++] = 'Q';            // ASCII Code for Q    
    mqtt_txbuf[mqtt_txlen++] = 'T';            // ASCII Code for T    
    mqtt_txbuf[mqtt_txlen++] = 'T';            // ASCII Code for T    
    //协议级别
    mqtt_txbuf[mqtt_txlen++] = 4;                // MQTT Protocol version = 4    
    //连接标志
    mqtt_txbuf[mqtt_txlen++] = 0xc2;            // conn flags 
    mqtt_txbuf[mqtt_txlen++] = 0;                // Keep-alive Time Length MSB    
    mqtt_txbuf[mqtt_txlen++] = 100;            // Keep-alive Time Length LSB  100S心跳包  

    mqtt_txbuf[mqtt_txlen++] = BYTE1(ClientIDLen);// Client ID length MSB    
    mqtt_txbuf[mqtt_txlen++] = BYTE0(ClientIDLen);// Client ID length LSB      
    memcpy(&mqtt_txbuf[mqtt_txlen],ClientID,ClientIDLen);
    mqtt_txlen += ClientIDLen;

    if(UsernameLen > 0)
    {   
        mqtt_txbuf[mqtt_txlen++] = BYTE1(UsernameLen);        //username length MSB    
        mqtt_txbuf[mqtt_txlen++] = BYTE0(UsernameLen);        //username length LSB    
        memcpy(&mqtt_txbuf[mqtt_txlen],Username,UsernameLen);
        mqtt_txlen += UsernameLen;
    }

    if(PasswordLen > 0)
    {    
        mqtt_txbuf[mqtt_txlen++] = BYTE1(PasswordLen);        //password length MSB    
        mqtt_txbuf[mqtt_txlen++] = BYTE0(PasswordLen);        //password length LSB  
        memcpy(&mqtt_txbuf[mqtt_txlen],Password,PasswordLen);
        mqtt_txlen += PasswordLen; 
    }    

    for(i=0;i<10;i++)
    {
        memset(mqtt_rxbuf,0,mqtt_rxlen);
        mqtt_send_data(mqtt_txbuf,mqtt_txlen);
        for(j=0;j<10;j++)
        {
            delay_ms(50);
            if (esp8266_wait_receive() == ESP8266_EOK)
                esp8266_copy_rxdata((char *)mqtt_rxbuf);

            //CONNECT
            if(mqtt_rxbuf[0]==parket_connetAck[0] && mqtt_rxbuf[1]==parket_connetAck[1] && mqtt_rxbuf[2]==parket_connetAck[2]) //连接成功               
            {
                return 0;//连接成功
            }
        }
    }
    return 1;
}
5.5.2 PUBLISH 报文

PUBLISH 报文的编写及发送代码,报文编写就按照我们7.2节的理论编写即可,报文内容:30 +剩余长度+L+主题+数据(JSON)。

uint8_t mqtt_publish_data(char *topic, char *message, uint8_t qos)
{  
    int topicLength = strlen(topic);    
    int messageLength = strlen(message);     
    static uint16_t id=0;
    int DataLen;
    mqtt_txlen=0;
    //有效载荷的长度这样计算:用固定报头中的剩余长度字段的值减去可变报头的长度
    //QOS为0时没有标识符
    //数据长度             主题名   报文标识符   有效载荷
    if(qos)    DataLen = (2+topicLength) + 2 + messageLength;       
    else    DataLen = (2+topicLength) + messageLength;   

    //固定报头
    //控制报文类型
    mqtt_txbuf[mqtt_txlen++] = 0x30;    // MQTT Message Type PUBLISH  

    //剩余长度
    do
    {
        uint8_t encodedByte = DataLen % 128;
        DataLen = DataLen / 128;
        // if there are more data to encode, set the top bit of this byte
        if ( DataLen > 0 )
            encodedByte = encodedByte | 128;
        mqtt_txbuf[mqtt_txlen++] = encodedByte;
    }while ( DataLen > 0 );    

    mqtt_txbuf[mqtt_txlen++] = BYTE1(topicLength);//主题长度MSB
    mqtt_txbuf[mqtt_txlen++] = BYTE0(topicLength);//主题长度LSB 
    memcpy(&mqtt_txbuf[mqtt_txlen],topic,topicLength);//拷贝主题
    mqtt_txlen += topicLength;

    //报文标识符
    if(qos)
    {
        mqtt_txbuf[mqtt_txlen++] = BYTE1(id);
        mqtt_txbuf[mqtt_txlen++] = BYTE0(id);
        id++;
    }
    memcpy(&mqtt_txbuf[mqtt_txlen],message,messageLength);
    mqtt_txlen += messageLength;

//    int i = 0;
//    for(i=0;i<mqtt_txlen;i++)
//        printf("%02X ", mqtt_txbuf[i]);
//    printf("\r\n");
    mqtt_send_data(mqtt_txbuf,mqtt_txlen);
    return mqtt_txlen;
}

5.6 主函数逻辑代码

主函数代码如下:

#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "esp8266.h"
#include "onenet.h"
#include "dht11.h"


extern char dht11_data[5];

int main(void)
{
    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);         /* 设置时钟,72M */
    delay_init(72);                             /* 初始化延时函数 */
    usart_init(115200);                         /* 波特率设为115200 */

    printf("初始化ESP8266...\r\n");
    esp8266_init(115200);

    printf("初始化MQTT...\r\n");
    mqtt_init();

    printf("MQTT连接...\r\n");
    mqtt_connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord);

    while(1)
    {
        uint8_t data_send_buff[512];
        memset(data_send_buff, 0, sizeof(data_send_buff));
        dht11_read();
        sprintf((char *)data_send_buff,"{\"id\":\"1386772172\",\"version\":\"1.0\",\"params\":{\"temperature\":{\"value\":%d.%d},\"humidity\":{\"value\":%d.%d}}}"
            ,dht11_data[2], dht11_data[3], dht11_data[0], dht11_data[1]);
        mqtt_publish_data(POST_TOPIC, (char *)data_send_buff, 0);
        HAL_Delay(3000);        //3s发送一次

        printf("\r\n~~~~~~~~发送心跳包~~~~~~~~\r\n");
        mqtt_send_heart();
        printf("~~~~~~~~心跳包发送结束~~~~~~~~\r\n");
    }
}

5.7 运行过程

烧录好后,串口效果如下:

OneNET 平台效果如下:

总结

把前面学的知识整合成一个小项目后是不是成就感爆棚了,接下来会不断继续优化这个小项目,让它更完整,更人性。感谢各位看官,love and peace!


另外,想进大厂的同学,一定要好好学算法,这是面试必备的。这里准备了一份 BAT 大佬总结的 LeetCode 刷题宝典,很多人靠它们进了大厂。

刷题 | LeetCode算法刷题神器,看完 BAT 随你挑!

有收获?希望老铁们来个三连击,给更多的人看到这篇文章

推荐阅读:

  • 程序员必备编程资料大全
  • 程序员必备软件资源

欢迎关注我的博客:良许嵌入式教程网,满满都是干货!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

macOS与Linux相互投屏的方法

很多人面对跨系统投屏都望而却步。其实只要找对方法&#xff0c;两台不同系统的电脑也可以相互投屏。 今天就来看看Linux系统和macOS系统如何相互投屏&#xff01; 第一步&#xff0c;将Linux系统电脑和macOS系统电脑连接同一网络。假设是macOS系统投屏到Linux系统&#xff0c;…

javaweb项目,springboot幼儿园健康管理系统,界面美观,增删改查。

javaweb项目&#xff0c;幼儿园健康管理系统&#xff0c;界面美观&#xff0c;增删改查。 管理员&#xff0c;老师&#xff0c;学生三个角色。 功能&#xff1a;权限管理&#xff0c;咨询列表&#xff0c;教师列表&#xff0c;班级列表&#xff0c;健康档案列表&#xff0c;评…

使用QT实现播放gstreamer的命令(二)

一、前言 上一篇文章写到了&#xff0c;如何快速使用C来执行gstreamer的命令&#xff0c;如何在QT中显示gstreamer的画面&#xff0c;原文如下&#xff1a; https://blog.csdn.net/Alon1787/article/details/135107958 二、近期的其他发现&#xff1a; 1.gstreamer的画面显示在…

代码训练营Day.48 | 198. 打家劫舍、213. 打家劫舍II、337. 打家劫舍III

198. 打家劫舍 1. LeetCode链接 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 2. 题目描述 3. 解法 可以看作一个01背包问题。背包容量为所有房子中存储的金钱总数。 1. dp数组含义&#xff1a;dp[i][j]表示前i个房子在背包容量为j的情况下可以…

Arrays.asList()方法调用add()或remove()抛出java.lang.UnsupportedOperationException问题

在使用Arrays.asList方法将以,分割的字符串转为list集合时&#xff0c;调用add和remove等方法时会抛出java.lang.UnsupportedOperationException。以下为原因和解决方法。 原因&#xff1a; Arrays.asList()方法返回了一个Arrays类的一个继承了AbstractList的ArrayList内部类…

Python面向对象-类专题

在Python中&#xff0c;if __name__ __main__: 这一句是一个常见的模式&#xff0c;用于判断当前的模块是被直接运行还是被导入到其他模块中。 当Python文件被直接运行时&#xff0c;其内置的__name__变量被设置为__main__。但如果这个文件被其他文件导入&#xff0c;__name__…

面向云服务的GaussDB全密态数据库

前言 全密态数据库&#xff0c;顾名思义与大家所理解的流数据库、图数据库一样&#xff0c;就是专门处理密文数据的数据库系统。数据以加密形态存储在数据库服务器中&#xff0c;数据库支持对密文数据的检索与计算&#xff0c;而与查询任务相关的词法解析、语法解析、执行计划生…

海外云手机为什么吸引用户?

近年来&#xff0c;随着全球化的飞速发展&#xff0c;海外云手机逐渐成为各行各业关注的焦点。那么&#xff0c;究竟是什么让海外云手机如此吸引用户呢&#xff1f;本文将深入探讨海外云手机的三大吸引力&#xff0c;揭示海外云手机的优势所在。 1. 高效的社交媒体运营 海外云…

盒子模型的内容总结

知识引入 1.认识盒子模型 在浏览网站时我们会发现内容都是按照区域划分的。这使得网页很工整、美观。在页面中&#xff0c;每一块区域分别承载不同的内容&#xff0c;使得网页的内容虽然零散&#xff0c;但是在版式排列上依然清晰有条理。如图1 图1 *承载内容的区域称为盒子…

Windows系统安装OpenSSH+VS Code结合内网穿透实现远程开发

文章目录 前言1、安装OpenSSH2、vscode配置ssh3. 局域网测试连接远程服务器4. 公网远程连接4.1 ubuntu安装cpolar内网穿透4.2 创建隧道映射4.3 测试公网远程连接 5. 配置固定TCP端口地址5.1 保留一个固定TCP端口地址5.2 配置固定TCP端口地址5.3 测试固定公网地址远程 前言 远程…

【Lazy ORM 整合druid 实现mysql监控】

Lazy ORM 整合druid 实现mysql监控 JDK 17 Lazy ORM框架地址 up、up欢迎start、issues 当前项目案例地址 框架版本描述spring-boot3.0.7springboot框架wu-framework-web1.2.2-JDK17-SNAPSHOTweb容器Lazy -ORM1.2.2-JDK17-SNAPSHOTORMmysql-connector-j8.0.33mysql驱动druid-…

【人工智能课程】计算机科学博士作业二

使用TensorFlow1.x版本来实现手势识别任务中&#xff0c;并用图像增强的方式改进&#xff0c;基准训练准确率0.92&#xff0c;测试准确率0.77&#xff0c;改进后&#xff0c;训练准确率0.97&#xff0c;测试准确率0.88。 1 导入包 import math import warnings warnings.filt…

七、内存管理单元(MMU)

前言 在多任务的处理器上&#xff0c;往往运行着许多的用户进程&#xff0c;这些进程之间相互隔离&#xff0c;它们都有自己的虚拟存储空间。要实现这样的虚拟存储空间&#xff0c;需要可以进行地址重分配以及虚拟地址到物理地址的转换。 MMU就是实现这种功能的硬件部件&…

哨兵1号回波数据(L0级)提取与SAR成像(全网首发)

本专栏目录:全球SAR卫星大盘点与回波数据处理专栏目录 本文先展示提取出的回波结果,然后使用RD算法进行成像,展示成像结果,最后附上哨兵1号回波提取的MATLAB代码。 1. 回波提取 回波提取得到二维复矩阵数据,对其求模值后绘图如下(横轴为距离向采样点,纵轴为方位向采样…

如何高效复制加密狗:一篇加密狗复制的常见方法全面指南

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通Golang》…

C++实现通讯录管理系统

目录 1、系统需求 2、创建项目 2.1 创建项目 3、菜单功能 4、退出功能 5、添加联系人 5.1 设计联系人结构体 5.2 设计通讯录结构体 5.3 main函数中创建通讯录 5.4 封装联系人函数 5.5 测试添加联系人功能 6、显示联系人 6.1 封装显示联系人函数 7、删除联系人 7.1…

Spring Security简介

什么是Spring Security Spring Security是 Spring提供的安全认证服务的框架。 使用Spring Security可以帮助我 们来简化认证和授权的过程。 官网&#xff1a;Spring Security 对应的maven坐标&#xff1a; <!--security启动器--> <dependency><groupId>or…

Scala入门01

Spark入门 1.入门 spark采用Scala语言开发 Spark是用来计算的 Scala掌握&#xff1a;特性&#xff0c;基本操作&#xff0c;集合操作&#xff0c;函数&#xff0c;模式匹配&#xff0c;trait&#xff0c;样例类&#xff0c;actor等内容。 2.内容讲解 2.1 Scala简介 在http…

Missing or invalid credentials.(Git push报错解决方案)

前言 本文主要讲解git push后报错Missing or invalid credentials的解决方案。这里针对的是windows的。 编程环境&#xff1a;VsCode 问题原因 问题翻译起来就是 凭据缺失或无效。这里我们解决方案是取消vscode里面默认的控制终端git凭据来解决,具体方案如下. 解决方案 1…

金田金业:中国大妈十年炒黄金后有何启发? 黄金交易要有策略

十多年前的2013年中国大妈炒黄金曾威震华尔街&#xff0c;一度成为投资界佳话。当时经过经历2008年全球金融危机五年后随着美国经济持续改善、美国缩减量化宽松规模&#xff0c;在美元强力反弹压制下&#xff0c;国际现货黄金从1700美元下跌到1300美元左右。正是在这个相对低点…