【STM32】RTT-Studio中HAL库开发教程三:IIC通信--AHT20

文章目录

    • 一、I2C总线通信协议
    • 二、AHT20传感器介绍
    • 三、STM32CubeMX配置硬件IIC
    • 四、RTT中初始化配置
    • 五、具体实现代码
    • 六、实验现象

一、I2C总线通信协议

使用奥松的AHT20温湿度传感器,对环境温湿度进行采集。AHT20采用的是IIC进行通信,可以使用硬件IIC或者使用模拟IIC进行通信,本例程介绍采用STM32F407芯片自带的硬件IIC进行通讯,具体操作过程如下。

1.I2C介绍
IIC(Inter-Integrated Circuit)总线是一种由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。
在CPU与被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbps 以上。

  • 注意IIC是为了与低速设备通信而发明的,所以IIC的传输速率比不上SPI。
    在这里插入图片描述

2.I2C物理层

  • 它是一个支持设备的总线。“总线”指多个设备共用的信号线。在一个 I2C 通讯总线中,可连接多个 I2C 通讯设备,支持多个通讯主机及多个通讯从机。
  • 一个 I2C 总线只使用两条总线线路,一条双向串行数据线(SDA) ,一条串行时钟线(SCL)。数据线即用来表示数据,时钟线用于数据收发同步。
  • 每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址 进行不同设备之间的访问。
  • 总线通过上拉电阻接到电源。当 I2C 设备空闲时,会输出高阻态,而 当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。
  • 多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定 由哪个设备占用总线。
  • 具有三种传输模式:标准模式传输速率为 100kbit/s,快速模式为 400kbit/s,高速模式下可达 3.4Mbit/s,但目前大多 I2C 设备尚不支持高速模 式。
  • 连接到相同总线的 IC 数量受到总线的最大电容 400pF 限制。
    在这里插入图片描述
    术语:

主机:启动数据传送并产生时钟信号的设备;
从机:被主机寻址的器件;
多主机:同时有多于一个主机尝试控制总线但不破坏传输;
主模式:用 I2CNDAT 支持自动字节计数的模式; 位 I2CRM,I2CSTT,I2CSTP 控制数据的接收和发送;
从模式:发送和接收操作都是由 I2C 模块自动控制的;
仲裁:是一个在有多个主机同时尝试控制总线但只允许其中一个控制总线并 使传输不被破坏的过程;
同步:两个或多个器件同步时钟信号的过程;
发送器:发送数据到总线的器件;
接收器:从总线接收数据的器件

3.I2C协议层
1.起始信号和停止信号
SCL 线为高电平期间,SDA 线由高电平向低电平的变化表示起始信号;SCL 线为高电平期间,SDA 线由低电平向高电平的变化表示终止信号。如下图:
在这里插入图片描述

起始和终止信号都是由主机发出的,在起始信号产生后,总线就处于被占用 的状态;在终止信号产生后,总线就处于空闲状态。

在这里插入图片描述
2.数据有效性规定
I2C 总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保 持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态 才允许变化。每次数据传输都以字节为单位,每次传输的字节数不受限制。如下图
在这里插入图片描述
3.应答和非应答
每当发送器件传输完一个字节的数据后,后面必须紧跟一个校验位,这个校 验位是接收端通过控制 SDA(数据线)来实现的,以提醒发送端数据我这边已经 接收完成,数据传送可以继续进行。这个校验位其实就是数据或地址传输过程中 的响应。响应包括“应答(ACK)”和“非应答(NACK)”两种信号。
在这里插入图片描述
应答信号(ACK)通常是从机向主机发送的信号。
在这里插入图片描述
非应答信号(NACK)是由主机发送的。
在这里插入图片描述
等待应答信号: 一旦主机发送完地址和读写位,它会释放SDA数据线,即将SDA置为高阻态,并等待从机的应答信号。
在这里插入图片描述
4.总线时序图
在这里插入图片描述

  • 初始(空闲)状态:SCL和SDA都保持高电平
  • 起始信号:SCL为高电平,SDA由高电平变为低电平,数据开始发送
  • 结束信号:SCL为高电平,SDA由低电平变为高电平,数据传送结束
  • 有效的数据位传输:在IIC总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,数据在SDA上从高位向低位依次串行传送每一位数据。
  • 应答信号:发送器每发送一个字节(8个bit),就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。
  • 应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节。
  • 应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。

二、AHT20传感器介绍

英文数据手册:AHT20英文手册
中文数据手册:AHT20中文手册
传感器介绍:
1.发送命令
在启动传输后,随后传输的I2C首字节包括7位的IIC设备地址0x38和一个SDA方向位x(读R:‘1’,写W:‘0’)。在第8个SCL时钟下降沿之后,通过拉低 SDA引脚 (ACK位),指示传感器数据接收正常。 在发出初始化命令之后 (‘1011’1110’)代表初始化,‘1010’1100’代表温湿度测量), MCU必须等到测量完成。

  • 地址:
    在这里插入图片描述
    该地址在使用的时候,如果是读设备,地址为0x71,如果是写设备,则地址为0x70。所以在设备进行设备通讯的时候设备地址采用0x70

  • 状态位说明:
    在这里插入图片描述
    在使用的时候需要查询设备状态,常查询的状态为:校准使能位、忙闲指示位

2.读取流程
AHT20传感器的通信过程主要包含以下四个步骤:

  • 上电后要等待40ms,读取温湿度值之前, 首先要看状态字的校准使能位Bit[3]是否为 1(通过发送0x71可以获取一个字节的状态字),如果不为1,要发送0xBE命令(初始化),此命令参数有两个字节, 第一个字节为0x08,第二个字节为0x00。
  • 直接发送 0xAC命令(触发测量),此命令参数有两个字节,第一个字节为 0x33,第二个字节为0x00。
  • 等待75ms待测量完成,忙状态Bit[7]为0,然后可以读取六个字节(发0X71即可以读取)。
  • 计算温湿度值。
    在这里插入图片描述在这里插入图片描述
    在采用HAL库配置的硬件IIC,则直接使用如下两个相关函数即可,无需关注此应答信号。硬件IIC的通信速率比软件IIC更加稳定,速度更快,使用更加方便。
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);

3.数据转换
计算相对湿度公式:
在这里插入图片描述
计算温度公式:
在这里插入图片描述

三、STM32CubeMX配置硬件IIC

1.配置硬件IIC:通过按照下图的配置方式,对IIC进行初始化配置
在这里插入图片描述
2.生成代码:按照下图生成IIC的初始化代码。
在这里插入图片描述

四、RTT中初始化配置

1.生成初始化代码
通过使用STM32CubeMX生成的初始化代码:

/**
 * @brief i2c初始化
 */
static void MX_I2C3_Init(void)
{
    hi2c3.Instance = I2C3;
    hi2c3.Init.ClockSpeed = 100000;
    hi2c3.Init.DutyCycle = I2C_DUTYCYCLE_2;
    hi2c3.Init.OwnAddress1 = 0;
    hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c3.Init.OwnAddress2 = 0;
    hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    if (HAL_I2C_Init(&hi2c3) != HAL_OK)
    {
        Error_Handler();
    }
}

2.在board.c中添加初始化代码
在board.c中需要添加HAL_开头的函数,便于系统调用该函数,对IIC进行初始化。

/**
 * @brief i2c初始化
 * @param i2cHandle
 */
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if (i2cHandle->Instance == I2C3)
    {
        __HAL_RCC_GPIOC_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();

        /**I2C3 GPIO Configuration
         PC9     ------> I2C3_SDA
         PA8     ------> I2C3_SCL
         */
        GPIO_InitStruct.Pin = GPIO_PIN_9;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
        GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

        GPIO_InitStruct.Pin = GPIO_PIN_8;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
        GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        /* I2C3 clock enable */
        __HAL_RCC_I2C3_CLK_ENABLE();
    }
}

3.在board.h中添加宏定义
打开RTT软件中的IIC的宏定义,便于使用IIC的底层驱动。

#define BSP_USING_I2C3
#ifdef BSP_USING_I2C3
#define BSP_I2C3_SCL_PIN    GET_PIN(A, 8)
#define BSP_I2C3_SDA_PIN    GET_PIN(C, 9)
#endif

五、具体实现代码

1.AHT20.h代码如下:

#ifndef APPLICATIONS_HARDWARE_INC_AHT20_H_
#define APPLICATIONS_HARDWARE_INC_AHT20_H_

#include <rtthread.h>
#include <rtdevice.h>
#include <drv_common.h>
#include "sys_string.h"

/**====================================================###### 宏定义 ######==================================================*/
#define RT_AHT20_THREAD_STACK_SIZE     (1024)
#define RT_AHT20_THREAD_PRIORITY       (22)
#define RT_AHT20_THREAD_TICK           (20)

#define AHT20_SLAVE_ADDRESS            0x70         // I2C从机地址

// 定义 AHT20 命令
#define AHT20_INIT_COMD                0xBE         // 初始化寄存器地址
#define AHT20_SOFTRESET                0xBA         // 软复位单指令
#define AHT20_TRIGMERSURE_COMD         0xAC         // 触发测量 寄存器地址
/**====================================================#######  END  #######=================================================*/

/**====================================================### 全局变量定义 ####=================================================*/
// aht20温湿度结构体
typedef struct m_AHT20
{
    uint8_t alive;      // 0-器件不存在; 1-器件存在
    uint8_t flag;       // 读取/计算错误标志位。0-读取/计算数据正常; 1-读取/计算设备失败
    uint32_t HT[2];     // 湿度、温度 原始传感器的值(20Bit).

    float RH;           // 湿度,转换单位后的实际值,标准单位%
    float Temp;         // 温度,转换单位后的实际值,标准单位°C

} AHT20_StructureTypedef;

AHT20_StructureTypedef  g_aht20;// aht20结构体信息
/**====================================================#######  END  #######=================================================*/

#endif /* APPLICATIONS_HARDWARE_INC_AHT20_H_ */

2.AHT20.c代码如下:

#include "aht20.h"
#include "i2c.h"
#include "control.h"
#include "power.h"

/*=====================================================### 静态函数调用 ###==================================================*/
#ifdef AHT20_HARDWARE_IIC

/**
 * @brief i2c初始化
 */
static void MX_I2C3_Init(void)
{
    hi2c3.Instance = I2C3;
    hi2c3.Init.ClockSpeed = 100000;
    hi2c3.Init.DutyCycle = I2C_DUTYCYCLE_2;
    hi2c3.Init.OwnAddress1 = 0;
    hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c3.Init.OwnAddress2 = 0;
    hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    if (HAL_I2C_Init(&hi2c3) != HAL_OK)
    {
        Error_Handler();
    }
}

/**
 * @brief 读AHT20 设备状态字
 * @return uint8_t 设备状态字
 */
static uint8_t AHT20_ReadStatusCmd(void)
{
    uint8_t tmp = 0;
    HAL_I2C_Master_Receive(&hi2c3, AHT20_SLAVE_ADDRESS, &tmp, 1, 0xFFFF);

    return tmp;
}

/**
 * @brief 读AHT20设备状态字中的Bit3: 校准使能位
 * @return 1 - 已校准; 0 - 未校准
 */
static uint8_t AHT20_ReadCalEnableCmd(void)
{
    uint8_t tmp = 0;
    tmp = AHT20_ReadStatusCmd();

    return (tmp >> 3) & 0x01;
}

/**
 * @brief AHT20 芯片初始化命令
 */
static void AHT20_IcInitCmd(void)
{
    uint8_t tmp = AHT20_INIT_COMD;
    HAL_I2C_Master_Transmit(&hi2c3, AHT20_SLAVE_ADDRESS, &tmp, 1, 0xFFFF);
}

/**
 * @brief AHT20 软复位命令
 */
static void AHT20_SoftResetCmd(void)
{
    uint8_t tmp = AHT20_SOFTRESET;
    HAL_I2C_Master_Transmit(&hi2c3, AHT20_SLAVE_ADDRESS, &tmp, 1, 0xFFFF);
}

/**
 * @brief AHT20 设备初始化
 * @return 0 - 初始化AHT20设备成功; 1 - 初始化AHT20失败,可能设备不存在或器件已损坏
 */
static uint8_t AHT20_Init(void)
{
    uint8_t rcnt = 2;   // 软复位命令 重试次数,2次
    uint8_t icnt = 2;   // 初始化命令 重试次数,2次

    while (rcnt--)
    {
        // 上电后要等待40ms
        HAL_Delay(40);

        // 读取温湿度之前,首先检查[校准使能位]是否为1,2次重试机会
        while ((!AHT20_ReadCalEnableCmd()) && (icnt--))
        {
            HAL_Delay(1);
            AHT20_IcInitCmd();      // 如果不为1,要发送初始化命令
            HAL_Delay(40);          // 按上电时间算40ms
        }

        // [校准使能位]为1,校准正常
        if (icnt)
        {
            break;
        }
        else
        {
            AHT20_SoftResetCmd();   // 软复位AHT20器件,重试
            HAL_Delay(20);          // 手册标明不超过20ms.
        }
    }

    if (rcnt)
    {
        return 0;        // AHT20设备初始化正常
    }
    else
    {
        return 1;        // AHT20设备初始化失败
    }
}

/**
 * @brief AHT20 触发测量命令
 */
static void AHT20_TrigMeasureCmd(void)
{
    uint8_t tmp[3] = {AHT20_TRIGMERSURE_COMD, 0x33, 0x00};
    HAL_I2C_Master_Transmit(&hi2c3, AHT20_SLAVE_ADDRESS, tmp, 3, 0xFFFF);
}

/**
 * @brief 读AHT20 设备状态字 中的Bit7: 忙标志
 * @return 忙标志:1 - 设备忙; 0 - 设备空闲
 */
static uint8_t AHT20_ReadBusyCmd(void)
{
    uint8_t tmp = 0;
    tmp = AHT20_ReadStatusCmd();
    return (tmp>>7)&0x01;
}

/**
 * @brief AHT20 设备读取 相对湿度和温度(原始数据20Bit)
 * @param HT:存储20Bit原始数据的uint32数组
 * @return 0-读取数据正常; 1-读取设备失败,设备一直处于忙状态,不能获取数据
 */
uint8_t AHT20_ReadHT(uint32_t *HT)
{
    uint8_t cnt = 4;        // 忙标志 重试次数,3次
    uint8_t tmp[6];
    uint32_t RetuData = 0;

    // 发送触发测量命令
    AHT20_TrigMeasureCmd();

    do
    {
        HAL_Delay(75);                      // 等待75ms待测量完成,忙标志Bit7为0
    }
    while (AHT20_ReadBusyCmd() && (--cnt)); // 重试3次

    // 设备闲,可以读温湿度数据
    if (cnt)
    {
        HAL_Delay(5);
        // 读温湿度数据
        HAL_I2C_Master_Receive(&hi2c3, AHT20_SLAVE_ADDRESS, tmp, 6, 0XFFFF);

        // 计算相对湿度RH。原始值,未计算为标准单位%。
        RetuData = 0;
        RetuData = (RetuData | tmp[1]) << 8;
        RetuData = (RetuData | tmp[2]) << 8;
        RetuData = (RetuData | tmp[3]);
        RetuData = RetuData >> 4;
        HT[0] = RetuData;

        // 计算温度T。原始值,未计算为标准单位°C。
        RetuData = 0;
        RetuData = (RetuData | tmp[3]) << 8;
        RetuData = (RetuData | tmp[4]) << 8;
        RetuData = (RetuData | tmp[5]);
        RetuData = RetuData & 0xfffff;
        HT[1] = RetuData;

        return 0;
    }
    else        //设备忙,返回读取失败
    {
        return 1;
    }
}

/**
 * @brief AHT20 温湿度信号转换(由20Bit原始数据,转换为标准单位RH=%,T=°C)
 * @param aht:存储AHT20传感器信息的结构体
 * @return 0-计算数据正常; 1-计算数据失败,计算值超出元件手册规格范围
 */
uint8_t StandardUnitCon(AHT20_StructureTypedef *aht)
{
    // 计算温湿度
    aht->RH = (double) aht->HT[0] * 100 / (1 << 20);
    aht->Temp = (double) aht->HT[1] * 200 / (1 << 20) - 50;

    // 限幅,RH=0~100%; Temp=-40~85°C
    if ((aht->RH >= 0) && (aht->RH <= 10000) && (aht->Temp >= -4000) && (aht->Temp <= 8500))
    {
        aht->flag = 0;
        return 0;        // 测量数据正常
    }
    else
    {
        aht->flag = 1;
        return 1;        // 测量数据超出范围,错误
    }
}

/**
 * @brief AHT20 温湿度信号转换(由20Bit原始数据,转换为标准单位RH=%,T=°C)
 * @param p:存储AHT20传感器信息的结构体
 * @return 0-计算数据正常; 1-计算数据失败,计算值超出元件手册规格范围
 */
uint8_t AHT20_Get_Value(AHT20_StructureTypedef *p)
{
    uint8_t temp = 0;

    temp = AHT20_ReadHT(p->HT);

    if (temp == 0)
    {
        temp = StandardUnitCon(p);
    }

    return temp;
}
#endif
/*=====================================================#######  END  #######=================================================*/

3.线程代码如下:

/**
 * @brief 温湿度检测入口函数
 * @param param
 */
void aht20_temp_humidity_entry(void *param)
{
#ifdef AHT20_HARDWARE_IIC

    AHT20_StructureTypedef *pAht20 = (AHT20_StructureTypedef *)param;
    POWER_ENABLE_HIGH();    // 温湿度电源使能

    MX_I2C3_Init();         // i2c初始化
    if(AHT20_Init() != 0)   // AHT20设备初始化
    {
        pAht20->alive = 0;
    }
    else
    {
        pAht20->alive = 1;
    }

#endif

    while (1)
    {
#ifdef AHT20_HARDWARE_IIC

        AHT20_Get_Value(pAht20);                                    // 温湿度查询
        rt_kprintf("T: %d.%d C  H: %d.%d %%\n", (int)pAht20->Temp, (int)(pAht20->Temp * 100) % 100,
                                                (int)pAht20->RH, (int)(pAht20->RH * 100) % 100);

#endif
        HAL_Delay(300);
    }
}

/**
 * @brief  温湿度线程初始化
 * @return
 */
static int aht20_temp_humidity(void)
{
    rt_thread_t ret;

    ret = rt_thread_create("aht20", aht20_temp_humidity_entry, (void *)&g_aht20,
                            RT_AHT20_THREAD_STACK_SIZE,
                            RT_AHT20_THREAD_PRIORITY,
                            RT_AHT20_THREAD_TICK);
    RT_ASSERT(ret != RT_NULL);
    rt_thread_startup(ret);

    return 0;
}
INIT_ENV_EXPORT(aht20_temp_humidity);

/**
 * @brief AHT20工作状态
 * @param argc
 * @param argv
 */
void AHT20_Work_State(int argc, char **argv)
{
    if (argc != 1)
    {
        rt_kprintf("[%s:%d] param error!\n", __FUNCTION__, __LINE__);
        return;
    }
    else
    {
        if (strcmp_nocase(argv[0], "aht20") == 0)
        {
            // 温湿度
            rt_kprintf("aht20_temp: %d.%d C\n", (int)g_aht20.Temp, (int)(g_aht20.Temp * 100) % 100);
            rt_kprintf("aht20_humidity: %d.%d %%\n", (int)g_aht20.RH, (int)(g_aht20.RH * 100) % 100);
        }
    }
}
MSH_CMD_EXPORT_ALIAS(AHT20_Work_State, aht20, AHT20 Work State);

六、实验现象

通过使用aht20指令进行查询温湿度数据,指令主要是通过控制台进行数据指令的读写,这个是RTT中自带的控制台,很方便进行数据的读取。具体实验数据如下:
在这里插入图片描述

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

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

相关文章

2. KNN分类算法与鸢尾花分类任务

鸢尾花分类任务 1. 鸢尾花分类步骤1.1 分析问题&#xff0c;搞定输入和输出1.2 每个类别各采集50朵花1.3 选择一种算法&#xff0c;完成输入到输出的映射1.4 第四步&#xff1a;部署&#xff0c;集成 2. KNN算法原理2.1 基本概念2.2 核心理念2.3 训练2.4 推理流程 3. 使用 skle…

Word参考文献交叉引用

前言 Word自带交叉引用功能&#xff0c;可在正文位置引用文档内自动编号的段落&#xff0c;同时创建超链接&#xff0c;适用于参考文献的引用。使用此方法对参考文献进行引用后&#xff0c;当参考文献的编号发生变化时&#xff0c;只需要更新域即可与正文中的引用相对应。下文…

vue3+TS从0到1手撸后台管理系统

1.路由配置 1.1路由组件的雏形 src\views\home\index.vue&#xff08;以home组件为例&#xff09; 1.2路由配置 1.2.1路由index文件 src\router\index.ts //通过vue-router插件实现模板路由配置 import { createRouter, createWebHashHistory } from vue-router import …

【15】Android基础知识之Window(一)

概述 这篇文章纠结了很久&#xff0c;在想需要怎么写&#xff1f;因为window有关的篇幅&#xff0c;如果需要讲起来那可太多了。从层级&#xff0c;或是从关联&#xff0c;总之不是很好开口。这次也下定决心&#xff0c;决定从浅入深的讲讲window这个东西。 Window Window是…

鸿蒙特色物联网实训室

一、 引言 在当今这个万物皆可连网的时代&#xff0c;物联网&#xff08;IoT&#xff09;正以前所未有的速度改变着我们的生活和工作方式。它如同一座桥梁&#xff0c;将实体世界与虚拟空间紧密相连&#xff0c;让数据成为驱动决策和创新的关键力量。随着物联网技术的不断成熟…

Qt Creator的好用的功能

&#xff08;1&#xff09;ctrlf&#xff1a; 在当前文档进行查询操作 &#xff08;2&#xff09;f3: 找到后&#xff0c;按f3&#xff0c;查找下一个 &#xff08;3&#xff09;shiftf3: 查找上一个 右键菜单&#xff1a; (4)f4&#xff1a;在…

solidity实战练习3——荷兰拍卖

//SPDX-License-Identifier:MIT pragma solidity ^0.8.24; interface IERC721{function transFrom(address _from,address _to,uint nftid) external ; }contract DutchAuction { address payable immutable seller;//卖方uint immutable startTime;//拍卖开始时间uint immut…

钡铼Modbus TCP耦合器BL200实现现场设备与SCADA无缝对接

前言 深圳钡铼技术推出的Modbus TCP耦合器为SCADA系统与现场设备之间的连接提供了强大而灵活的解决方案&#xff0c;它不仅简化了设备接入的过程&#xff0c;还提升了数据传输的效率和可靠性&#xff0c;是工业自动化项目中不可或缺的关键设备。本文将从Modbus TC、SCADA的简要…

基于Ubuntu2204搭建openstack-Y版-手动搭建

openstack手搭Y版 基础环境配置离线环境时间同步&#xff08;双节点&#xff09;安装openstack客户端数据库服务消息队列服务缓存服务 keystone服务部署glance服务部署placement服务部署nova服务部署controllercompute neutron服务部署controller节点配置neutron.conf文件配置m…

leetcode-349.两个数组的交集

题源 349.两个数组的交集 题目描述 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的 交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,2,1], nums2 [2,2] 输出&#xff1a;[2] 示例…

权威认可 | 海云安开发者安全助手系统通过信通院支撑产品功能认证并荣获信通院2024年数据安全体系建设优秀案例

近日&#xff0c;2024全球数字经济大会——数字安全生态建设专题论坛&#xff08;以下简称“论坛”&#xff09;在京成功举办。由全球数字经济大会组委会主办&#xff0c;中国信息通信研究院及公安部第三研究所共同承办&#xff0c;论坛邀请多位专家和企业共同参与。 会上颁发…

android预置apk

在framework开发中&#xff0c;有一些需求是需要预装应用的&#xff0c;有些是预置应用源码&#xff0c;有些是预置apk。今天我们就分享下怎样预置apk 一般系统有自定义的目录&#xff0c;比如我的项目中根目录下有一个文件夹vendor&#xff0c;这里没都是自定义的一些功能。预…

Redis系列命令更新--Redis列表命令

Redis列表 1、Redis Blpop命令&#xff1a; &#xff08;1&#xff09;说明&#xff1a;Redis Blpop命令移出并获取列表的第一个元素&#xff1b;如果列表没有元素会阻塞列表直到等到超时或发现可弹出元素为止 &#xff08;2&#xff09;语法&#xff1a;redis 127.0.0.1:63…

leetcode-三数之和

视频&#xff1a;https://www.bilibili.com/video/BV1bP411c7oJ/?spm_id_from333.788&vd_sourcedd84879fcf1be72f360461b01ecab0d6 从两数之和开始&#xff0c;排序后的两数之和&#xff0c;利用好升序的性质&#xff0c;可以将时间复杂度从on2降到on; class Solution …

「AI得贤招聘官」通过首批“AI产业创新场景应用案例”评估

近日&#xff0c;上海近屿智能科技有限公司的「AI得贤招聘官」&#xff0c;经过工业和信息化部工业文化发展中心数字科技中心的严格评估&#xff0c;荣获首批“AI产业创新场景应用案例”。 据官方介绍&#xff0c;为积极推进通用人工智能产业高质量发展&#xff0c;围绕人工智能…

自适应简约大气科技数码产品公司网站源码系统 模版一键搭建 可自定义带源代码包以及搭建部署教程

系统概述 在当今这个数字化、信息化的时代&#xff0c;科技数码产品行业正处于高速发展的黄金时期。为了在这个竞争激烈的市场中脱颖而出&#xff0c;科技数码产品公司不仅需要拥有卓越的产品和技术&#xff0c;还需要一个能够完美展现其品牌形象和产品特色的网站。为此&#…

【数据结构】算法复杂度

算法复杂度 数据结构算法复杂度 大o渐进表示法空间复杂度 数据结构 数据结构&#xff1a;是计算机存储和组织数据的方式。 比如打开一个网页&#xff0c;我们看到的文字就是数据&#xff0c;这些数据需要用一个结构来把他管理起来&#xff0c;我们称之为&#xff1a;数据结构 …

2024-07-12升级问题:Android SDK升级导致 Canvas.FULL_COLOR_LAYER_SAVE_FLAG 等标志位无法使用

Canvas.FULL_COLOR_LAYER_SAVE_FLAG 是一个标志位&#xff0c;用于在 Android 的 Canvas 类中保存画布的颜色层。当使用 saveLayer() 方法时&#xff0c;可以传递这个标志位来指示保存整个颜色层。这样&#xff0c;在恢复画布状态时&#xff0c;颜色层也会被恢复。 工程从Andr…

EasyAnimate-v3版本支持I2V及超长视频生成

阿里云人工智能平台&#xff08;PAI&#xff09;自研开源的视频生成项目EasyAnimate正式发布v3版本&#xff1a; 支持 图片&#xff08;可配合文字&#xff09; 生成视频 支持 上传两张图片作为起止画面 生成视频 最大支持720p&#xff08;960*960分辨率&#xff09; 144帧视…

使用 Python 爬虫实现自动获取天气信息并语音播报

简介 在本文中&#xff0c;我将介绍如何使用 Python 编写一个简单的爬虫程序&#xff0c;该程序可以自动获取某个城市的天气信息&#xff0c;并使用语音库将这些信息播报出来。我们将使用 pyttsx3 库进行语音播报&#xff0c;以及 requests 和 lxml 库来获取和解析网页数据。 …