SHT3x-DIS驱动及应用详解(附源码和手册)

2023-11-11


SHT3x-DIS手册链接
SHT3x-DIS是Sensirion新一代的温湿度传感器,精度为±2%RH和±0.3℃,输入电压范围从2.4V到5.5V,采用IIC总线接口,速率可达1MHz。测量温湿度范围分别为是-40℃ ~ 125℃和0 ~ 100%。

先贴源码以及芯片文档下载链接

一、电路组成

从下图可以看到SHT3x内部集成了湿度传感器和温度传感器,通过ADC采样输入到数据处理和线性化单元,同时带有校正储存器,处理环境对器件测量的影响。通过数字接口IIC读取数据。带警报引脚,可通过修改寄存器的值设定阈值,当测量的温湿度超过阈值时它会被置位。
在这里插入图片描述

引脚分布如下,1和4号脚是IIC总线接口;2号脚是决定地址的引脚,当ADDR接VSS时芯片地址为0x44,接VCC时芯片地址为0x45;3号脚警报引脚(当不使用时浮空),当温湿度超过设定的阈值则该脚会被置位;5号和8号脚是电源引脚;6号引脚是复位引脚(当不使用时接VDD),低电平有效;7号脚是为了封装而保留的引脚。
在这里插入图片描述

下图是设备地址分配情况。
在这里插入图片描述

典型电路如下,由于SCL和SDA为开漏输出,驱动能力不足,需要接上拉电阻。VDD和VSS之间接一个小电容滤除高频杂波,另外nRESET和ALERT根据情况进行选择,若不需要使用,nRESET接高电平,ALERT浮空。Die Pad接地即可。

在这里插入图片描述

二、通讯指令说明

写好IIC驱动程序后,便可以开始和SHT3x进行通讯了,下面是SHT3x的所有指令说明。

(一)、单次获取数据指令

单次获取数据指令(Measurement Commands for Single Shot Data Acquisition Mode)的详细数据格式如下图。首先从表格最上面开始,Repeatability指的是重复性(重复性越高精度越高,可参考手册的Sensor Performance部分),Clock Stretching指的是时钟延伸,它们的作用下面再讲述。数据流动过程如下。

  • 发送起始信号以及由高7位的器件地址和最低位的写信号(WR=0) 组成的一字节地址,等待应答信号。(注意地址位于高7位,所以传址的时候需要将地址左移一位并加上读1/写0信号,如ADDR<<1 | WR)
  • 发送指令的高字节(Most Significant Byte,MSB)并等待应答信号。
  • 发送指令的低字节(Least Significant Byte,LSB)并等待应答信号,之后发送停止信号。
  • 等待一段时间(测量正在进行)
  • 发送起始信号以及由高7位的器件地址和最低位的读信号(RD=1) 组成的一字节地址,然后根据选择的Clock Stretching从两个方向选择。假如失能了时钟延长功能,则等待非应答信号,发送停止信号,延迟一段时间(这步很重要!!延迟时间大约为50ms左右)等待转换结束,然后发送八位的应答信号并等待应答信号,之后便是逐字节分别读取温度和湿度的高字节、低字节以及CRC校验字节,每字节接收完都要发送应答信号,最后发送停止信号即可。而如果使能了是时钟延长功能,则总线的SCL由SHT3x控制,我们只需要通过while(SCL==0)阻塞程序,等待其释放总线然后MCU读取数据即可。

在这里插入图片描述

(二)、周期获取数据指令

周期获取数据指令(Measurement Commands for Periodic Data Acquisition Mode)的详细数据格式如下图。周期获取数据需要先配置读取模式然后再进行读取。

1、配置模式

周期读取数据的配置主要是配置重复性和每秒测量次数。数据发送的方式同上。
在这里插入图片描述

2、读取数据

读取的步骤和上述单次读取数据指令的流程类似,下面大概说一下。

  • 发送起始信号,发送写地址,等待应答信号,注意如果传感器没有测量完,它只会返回非应答信号。
  • 发送16位命令0xE000。
  • 读取初始数据

在这里插入图片描述

(三)、加快响应时间指令

加快响应时间指令(accelerated response time,ART),用于周期读取数据指令,开启后传感器开始采集频率为4Hz的数据。它的使用方法跟上述配置模式相同,在读取之前配置好就可以了。

  • 发送起始信号,发送写地址,等待应答信号
  • 发送16位命令0x2B32,等待应答信号
  • 接着继续配置或者读取数据

在这里插入图片描述

(四)、停止周期读取数据指令

停止周期读取数据指令(Break command / Stop Periodic Data Acquisition Mode),有时为了实现低功耗或暂时不需要传感器测量数据,可以通过该指令进行关闭。

  • 发送起始信号,发送写地址,等待应答信号
  • 发送16位命令0x3093,等待应答信号,发送停止信号

在这里插入图片描述

(五)、复位

复位(RESET)的方式有很多种。

1、IIC接口复位

当通讯设备丢失时,在接下来的信号序列将会复位串口接口,此序列仅重置接口。状态寄存器保留其内容。可以通过下面步骤实现。

  • SDA线置位,翻转SCL线的电平9次以上
  • 接下来必须在下一个命令之前执行传输开始序列。
2、软复位/重新初始化

软复位/重新初始化(Soft Reset / Re-Initialization)的指令格式如下。

  • 发送起始信号,发送写地址,等待应答信号
  • 发送16位命令0x30A2,等待应答信号,发送停止信号

在这里插入图片描述

3、一般呼叫复位指令

一般呼叫复位指令(Reset through General Call)的指令格式如下。

  • 发送起始信号,发送通用呼叫地址0x00,等待应答信号
  • 发送第二个字节0x06,等待应答信号

在这里插入图片描述

4、通过nRESET引脚复位

拉低nRESET引脚的电平(至少350ns)将会产生硬复位信号重置传感器。

5、硬复位

重新上电。

(六)、加热器开启/关闭指令

该指令的用法同上,至于该加热器的作用是什么我也不清楚,明明是测温用的还要加热?!大概是想在温度很低的环境但想要它还能正常工作所以才设置这功能吧。

在这里插入图片描述

(七)、读取状态寄存器

状态寄存器包含有关加热器运行状态、警报模式以及最后一个命令的执行状态和最后一个写序列的信息。

  • 发送起始信号,发送写地址,发送16位命令
  • 发送起始信号,发送读地址,依次接收状态寄存器的高字节、低字节和CRC校验,每次接收都需要发送应答信号,直到接收的最后一个字节发送非应答信号,发送停止信号。

在这里插入图片描述

状态寄存器每一位代表的含义如下所示。

在这里插入图片描述

我们试一下读取状态寄存器看返回什么。可以发现二进制数1000 0000 0001 0000 1110 0001都为上面表格的默认值,至于CRC校验要根据给定公式对前两字节进行计算和比较。下面来讲CRC校验。

在这里插入图片描述

(八)、CRC校验

循环冗余校验(CRC)其实就是一种异或计算(模2运算)。获取的CRC校验码就是模2运算后的余数。
在这里插入图片描述

CRC校验计算的代码如下。

static u8 CRC_Check(u8 *check_data, u8 num, u8 check_crc)
{
    uint8_t bit;        // bit mask
    uint8_t crc = 0xFF; // calculated checksum
    uint8_t byteCtr;    // byte counter
    
 // calculates 8-Bit checksum with given polynomial x8+x5+x4+1
    for(byteCtr = 0; byteCtr < num; byteCtr++)
    {
        crc ^= (*(check_data+byteCtr));
        //crc校验,最高位是1就^0x31
        for(bit = 8; bit > 0; --bit)
        {
            if(crc & 0x80)
                crc = (crc << 1) ^ 0x31;
            else
                crc = (crc << 1);
        }
    }
    if(crc==check_crc)
        return 1;
    else 
        return 0;
}

(九)、转换温湿度数据

由于从传感器获取到的数据不是最终的温湿度,所以我们需要根据公式进行转换,转换公式如下,在计算之前我们要对温湿度数据进行整合。

在这里插入图片描述

    tem = ((buff[0]<<8) | buff[1]);//温度拼接
    hum = ((buff[3]<<8) | buff[4]);//湿度拼接

    Temperature= (175.0*(float)tem/65535.0-45.0) ;  // T = -45 + 175 * tem / (2^16-1)
    Humidity= (100.0*(float)hum/65535.0);           // RH = hum*100 / (2^16-1)

三、代码

(一)、IIC程序

1、iic.c
#include "iic.h"

/*
*********************************************************************************************************
*	函 数 名: i2c_Delay
*	功能说明: I2C总线延迟,最快400KHz
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
static void i2c_Delay(void)
{
    __NOP();__NOP();__NOP();__NOP();    __NOP();__NOP();__NOP();__NOP();

}

/*
*********************************************************************************************************
*	函 数 名: i2c_Start
*	功能说明: CPU发起I2C总线启动信号
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void i2c_Start(void)
{
    /* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */
    I2C_SDA_1();
    I2C_SCL_1();
    i2c_Delay();
    I2C_SDA_0();
    i2c_Delay();
    I2C_SCL_0();
    i2c_Delay();
}

/*
*********************************************************************************************************
*	函 数 名: i2c_Start
*	功能说明: CPU发起I2C总线停止信号
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void i2c_Stop(void)
{
    /* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */
    I2C_SDA_0();
    I2C_SCL_1();
    i2c_Delay();
    I2C_SDA_1();
}

/*
*********************************************************************************************************
*	函 数 名: i2c_SendByte
*	功能说明: CPU向I2C总线设备发送8bit数据
*	形    参:_ucByte : 等待发送的字节
*	返 回 值: 无
*********************************************************************************************************
*/
void i2c_SendByte(uint8_t _ucByte)
{
    uint8_t i;

    /* 先发送字节的高位bit7 */
    for (i = 0; i < 8; i++)
    {
        if (_ucByte & 0x80)
        {
            I2C_SDA_1();
        }
        else
        {
            I2C_SDA_0();
        }
        i2c_Delay();
        I2C_SCL_1();
        i2c_Delay();
        I2C_SCL_0();
        if (i == 7)
        {
            I2C_SDA_1(); // 释放总线
        }
        _ucByte <<= 1;	/* 左移一个bit */
        i2c_Delay();
    }
}

/*
*********************************************************************************************************
*	函 数 名: i2c_ReadByte
*	功能说明: CPU从I2C总线设备读取8bit数据
*	形    参:无
*	返 回 值: 读到的数据
*********************************************************************************************************
*/
uint8_t i2c_ReadByte(u8 ack)
{
    uint8_t i;
    uint8_t value;

    /* 读到第1个bit为数据的bit7 */
    value = 0;
    for (i = 0; i < 8; i++)
    {        
        value <<= 1;
        I2C_SCL_1();
        i2c_Delay();
        if (I2C_SDA_READ())
        {
            value++;
        }
        I2C_SCL_0();
        i2c_Delay();
    }
    if(ack==0)
        i2c_NAck();
    else
        i2c_Ack();
    return value;
}

/*
*********************************************************************************************************
*	函 数 名: i2c_WaitAck
*	功能说明: CPU产生一个时钟,并读取器件的ACK应答信号
*	形    参:无
*	返 回 值: 返回0表示正确应答,1表示无器件响应
*********************************************************************************************************
*/
uint8_t i2c_WaitAck(void)
{
    uint8_t try_time = 100;//连接超时次数

    I2C_SDA_1();	        //CPU释放SDA总线
    i2c_Delay();
    I2C_SCL_1();	        //CPU驱动SCL = 1, 此时器件会返回ACK应答
    i2c_Delay(); 

    while(I2C_SDA_READ())//等待SHT30应答
    {
        try_time--;
        i2c_Delay(); 
        if(try_time==0)//超时,无响应
        {
            I2C_SCL_0();
            i2c_Delay();
            return 1;
        }
    }
    I2C_SCL_0();
    i2c_Delay();    
    return 0;
}

/*
*********************************************************************************************************
*	函 数 名: i2c_Ack
*	功能说明: CPU产生一个ACK信号
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void i2c_Ack(void)
{
    I2C_SDA_0();	/* CPU驱动SDA = 0 */
    i2c_Delay();
    I2C_SCL_1();	/* CPU产生1个时钟 */
    i2c_Delay();
    I2C_SCL_0();
    i2c_Delay();
    I2C_SDA_1();	/* CPU释放SDA总线 */
}

/*
*********************************************************************************************************
*	函 数 名: i2c_NAck
*	功能说明: CPU产生1个NACK信号
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void i2c_NAck(void)
{
    I2C_SDA_1();	/* CPU驱动SDA = 1 */
    i2c_Delay();
    I2C_SCL_1();	/* CPU产生1个时钟 */
    i2c_Delay();
    I2C_SCL_0();
    i2c_Delay();
}

/*
*********************************************************************************************************
*	函 数 名: i2c_GPIO_Config
*	功能说明: 配置I2C总线的GPIO,采用模拟IO的方式实现
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void i2c_GPIO_Config(void)
{
    //个人觉得程序初始化就是要通俗易懂,所以习惯用库函数进行
    //但是像改变IIC引脚电平状态,由于需要频繁操作,所以最好还是使用寄存器操作
    GPIO_InitTypeDef GPIO_InitStrcuture;
    
    RCC_APB2PeriphClockCmd(IIC_CLOCK,ENABLE);

    GPIO_InitStrcuture.GPIO_Mode = GPIO_Mode_Out_OD;//开漏输出
    GPIO_InitStrcuture.GPIO_Pin = IIC_SDA_PIN|IIC_SCL_PIN;
    GPIO_InitStrcuture.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(IIC_GPIO,&GPIO_InitStrcuture);
}
/*
*********************************************************************************************************
*	函 数 名: i2c_CheckDevice
*	功能说明: 检测I2C总线设备,CPU向发送设备地址,然后读取设备应答来判断该设备是否存在
*	形    参:_Address:设备的I2C总线地址
*	返 回 值: 返回值 0 表示正确, 返回1表示未探测到
*********************************************************************************************************
*/
uint8_t i2c_CheckDevice(uint8_t _Address)
{
    uint8_t ucAck;
    i2c_GPIO_Config();		/* 配置GPIO */
    i2c_Start();		/* 发送启动信号 */

    /* 发送设备地址+读写控制bit(0 = w, 1 = r) bit7 先传 */
    i2c_SendByte(_Address|I2C_WR);
    ucAck = i2c_WaitAck();	/* 检测设备的ACK应答 */

    i2c_Stop();			/* 发送停止信号 */
    return ucAck;
}
2、iic.h
#ifndef __IIC_H
#define __IIC_H

#include "stm32f10x.h"
#include <stdbool.h>
#include <stdlib.h>
#include <inttypes.h>
#include "bsp_systick.h"
#include "bsp_sys.h"

#define IIC_CLOCK           RCC_APB2Periph_GPIOA
#define IIC_GPIO            GPIOA
#define IIC_SCL_PIN         GPIO_Pin_6
#define IIC_SDA_PIN         GPIO_Pin_7

/* 定义I2C总线连接的GPIO端口, 用户只需要修改下面4行代码即可任意改变SCL和SDA的引脚 */
#define I2C_SCL_1()     PAout(6)=1
#define I2C_SCL_0()     PAout(6)=0
#define I2C_SDA_1()		PAout(7)=1
#define I2C_SDA_0()     PAout(7)=0
#define I2C_SDA_READ()  GPIO_ReadInputDataBit(IIC_GPIO,IIC_SDA_PIN)

#define I2C_WR	0		/* 写控制bit */
#define I2C_RD	1		/* 读控制bit */

void i2c_Start(void);
void i2c_Stop(void);
void i2c_SendByte(uint8_t _ucByte);
uint8_t i2c_ReadByte(uint8_t ack);
uint8_t i2c_WaitAck(void);
void i2c_Ack(void);
void i2c_NAck(void);
uint8_t i2c_CheckDevice(uint8_t _Address);
void i2c_GPIO_Config(void);

#endif

(二)、SHT30程序

1、sht30.c
#include "sht30.h"

float_data humidity;//存储的湿度数据
float_data temperature;//存储的温度数据
u8 status[3];//状态寄存器
u8 status_crc;//CRC校验计算
u8 crc_check;//crc结果

//如果读取不到数据,有可能是读取的时间设得太短导致,我这里的时间是最小可实现读取的时间!!!

//CRC校验
static u8 CRC_Check(u8 *check_data, u8 num, u8 check_crc)
{
    uint8_t bit;        // bit mask
    uint8_t crc = 0xFF; // calculated checksum
    uint8_t byteCtr;    // byte counter
    
 // calculates 8-Bit checksum with given polynomial x8+x5+x4+1
    for(byteCtr = 0; byteCtr < num; byteCtr++)
    {
        crc ^= (*(check_data+byteCtr));
        //crc校验,最高位是1就^0x31
        for(bit = 8; bit > 0; --bit)
        {
            if(crc & 0x80)
                crc = (crc << 1) ^ 0x31;
            else
                crc = (crc << 1);
        }
    }
    if(crc==check_crc)
        return 1;
    else 
        return 0;
}

//根据所选获取数据的方式初始化
void SHT30_Init(void)
{
    i2c_GPIO_Config();
    SHT30_General_RESET();//软复位设备
    delay_ms(10);
}

//发送两字节指令,stop确定是否发送停止信号
void SHT30_SendBytes(u16 cmd,u8 stop)
{
    i2c_Start();
    i2c_SendByte(SHT30_ADDR<<1 | I2C_WR);//写7位I2C设备地址加0作为写取位,1为读取位
    i2c_WaitAck();
    i2c_SendByte(cmd>>8);
    i2c_WaitAck();
    i2c_SendByte(cmd&0xFF);
    i2c_WaitAck();
    if(stop)
        i2c_Stop();
}

//软复位
void SHT30_SOFTRESET(void)
{
    SHT30_SendBytes(0x30A2,1);
}

//通用复位
void SHT30_General_RESET(void)
{
    i2c_Start();
    i2c_SendByte(0x00);
    i2c_WaitAck();
    i2c_SendByte(0x06);
    i2c_WaitAck();
}

//获取状态寄存器数据
void SHT30_Get_Status(u8 *buffer)
{
    SHT30_SendBytes(0xF32D,0);
    delay_ms(3);
    i2c_Start();
    i2c_SendByte(SHT30_ADDR<<1 | I2C_RD);//写7位I2C设备地址加0作为写取位,1为读取位
    if(i2c_WaitAck()==0)
    {
        buffer[0]=i2c_ReadByte(1);
        buffer[1]=i2c_ReadByte(1);
        buffer[2]=i2c_ReadByte(1);
        i2c_Stop();
    }
}

//清空状态寄存器
void SHT30_Clear_Status(void)
{
    SHT30_SendBytes(0x3041,1);
}

//返回0代表状态寄存器读取成功,1代表读取错误
u8 SHT30_Status(void)
{
    SHT30_Get_Status(status);
    
    if(CRC_Check(status,2,*(status+2)))
        return 0;//正确
    else
        return 1;//错误
}

//单次读取数据
void SHT30_Single_Shot(u8 *buffer)
{
    u8 try_time=100;
    
    SHT30_SendBytes(0x2C06,1);
    
    delay_ms(20);//很重要!不然读不出数据
    i2c_Start();
    i2c_SendByte(SHT30_ADDR<<1 | I2C_RD);//写7位I2C设备地址加0作为写取位,1为读取位

    while(i2c_WaitAck())
    {
        try_time--;
        delay_us(50);
        if(try_time==0)
            return;
    }
    buffer[0]=i2c_ReadByte(1);
    buffer[1]=i2c_ReadByte(1);
    buffer[2]=i2c_ReadByte(1);
    buffer[3]=i2c_ReadByte(1);
    buffer[4]=i2c_ReadByte(1);
    buffer[5]=i2c_ReadByte(0);
    i2c_Stop();
}

//开启/关闭加热器
void SHT30_Heater(u8 enable)
{
    if(enable)
        SHT30_SendBytes(0x306D,1);
    else
        SHT30_SendBytes(0x3066,1);
}

//加速响应指令
void SHT30_ART(void)
{
    SHT30_SendBytes(0x2B32,0);
}

//配置周期读取重复性和采样速率
void SHT30_Periodic_SetRepeat(void)
{
    SHT30_SendBytes(0x2737,0);//高重复度,mps为10
}

//配置周期读取总配置
void SHT30_Periodic_Config(void)
{
    //配置
    SHT30_Periodic_SetRepeat();
    SHT30_ART();
}
//周期读取数据 如果使用就要在初始化时加上SHT30_Periodic_Config()函数
void SHT30_Periodic(u8 *buffer)
{
    u8 try_time=100;
    
    //获取数据
    SHT30_SendBytes(0xE000,0);
    delay_ms(3);//很重要!不然读不出数据

    i2c_Start();
    i2c_SendByte(SHT30_ADDR<<1 | I2C_RD);//写7位I2C设备地址加0作为写取位,1为读取位
    
    while(i2c_WaitAck())
    {
        try_time--;
        delay_us(50);
        if(try_time==0)
            return;
    }
    buffer[0]=i2c_ReadByte(1);
    buffer[1]=i2c_ReadByte(1);
    buffer[2]=i2c_ReadByte(1);
    buffer[3]=i2c_ReadByte(1);
    buffer[4]=i2c_ReadByte(1);
    buffer[5]=i2c_ReadByte(0);
    i2c_Stop();
}

//中断指令/停止周期获取数据功能
void SHT30_Stop_Break(void)
{
    SHT30_SendBytes(0x3093,1);
    delay_ms(15);
}

//获取SHT3x温湿度
void SHT30_Read(void)
{    
    u8 buff[6];//获取raw数据
    u16 tem,hum;//拼接温湿度数据
    u8 crcT,crcH;//温度和湿度的CRC校验

    float Temperature=0;//转换后的温湿度
    float Humidity=0;

    SHT30_Single_Shot(buff);
    //SHT30_Periodic(buff);
    
    tem = ((buff[0]<<8) | buff[1]);//温度拼接
    hum = ((buff[3]<<8) | buff[4]);//湿度拼接

    //计算温度和湿度CRC校验码
    crcT = CRC_Check(buff,2,buff[2]);   //温度
    crcH = CRC_Check(buff+3,2,buff[5]); //湿度
    
    if(crcT&&crcH)//判断CRC校验是否对
    {
        //根据手册计算公式计算
        Temperature= (175.0*(float)tem/65535.0-45.0) ;  // T = -45 + 175 * tem / (2^16-1)
        Humidity= (100.0*(float)hum/65535.0);           // RH = hum*100 / (2^16-1)
        if((Temperature>=-20)&&(Temperature<=125)&&(Humidity>=0)&&(Humidity<=100))//过滤超出测量范围的错误数据
        {
            temperature.fdata=Temperature;
            humidity.fdata=Humidity;
        }
    }
}

2、sht30.h
#ifndef __SHT30_H
#define __SHT30_H

//#include "bsp_iic.h"
#include "iic.h"
#define SHT30_ADDR      0x44

typedef union 
{
    float fdata;
    unsigned char cdata[4];
}float_data;//定义联合体存储float数据,float类型的存储符合IEEE标准,可用于传输数据

void SHT30_Init(void);
void SHT30_SOFTRESET(void);
void SHT30_General_RESET(void);
void SHT30_Stop_Break(void);

void SHT30_Read(void);
void SHT30_SendBytes(u16 cmd,u8 stop);
void SHT30_ART(void);
void SHT30_Single_Shot(u8 *buffer);
void SHT30_Periodic(u8 *buffer);
void SHT30_Heater(u8 enable);

#endif

参考资料:
SHT30使用手册(SHT3x_Datasheet_digital.pdf)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SHT3x-DIS驱动及应用详解(附源码和手册) 的相关文章

随机推荐

  • 很有道理的十句话

    第一句如果我们之间有1000 步的距离 你只要跨出第1 步我就会朝你的方向走其余的 999步 第二句 通常愿意留下来跟你争吵的人 才是真正爱你的人 第三句付出真心 才会得到真心 却也可能伤得彻底保持距离 就能保护自己 却也注定永远寂寞 第四
  • antd上传组件使用fileList属性展示图片,onchage事件只会执行一次的问题

    在工作中使用到了antd的照片墙组件时 遇到了官方文档上提出的一个问题 然而官方的解答是回退版本 看了github上网友留言 加上自己测试 找到一种解决方式 一定要在判断 等于 uploading状态的时候进行一次setState 之后在d
  • 通过华为杯竞赛、高教社杯和数学建模国赛实现逆袭;助力名利双收

    文章目录 赛事介绍 参赛好处 辅导比赛 写在最后 赛事介绍 华为杯全国研究生数学建模竞赛是由华为公司主办的一项面向全国研究生的数学建模竞赛 该竞赛旨在通过实际问题的建模和解决 培养研究生的创新能力和团队合作精神 推动科技创新和应用 华为杯竞
  • python:类

    类与对象 Python从设计之初就已经是一门面向对象的语言 面向对象编程OOP是一种程序设计思想 它把对象作为程序的基本单元 一个对象包含了数据和操作数据的函数 面向过程的程序设计把计算机程序视为一系列的命令集合 即一组函数的顺序执行 为了
  • Ubuntu20.04系统使用笔记

    笔者安装的ubuntu版本是20 04 双系统安装 参考教程 link 用于深度学习 总共给ubuntu的空间为200GB 交换区分l8GB 16GB内存 EFI系统分区1GB 剩余181GB全给根目录 操作记录 使用命令sudo ubun
  • python + selenium

    selenium是一个模拟浏览器的类库 经常用来做自动化测试 python 可以直接使用安装目录下的Scripts pip工具安装 以windows7 python3 4为例 运行cmd cd C Python34 Scripts pip
  • 【LTspice】005 伯德图绘制

    目录 1 伯德图介绍 2 LTspice 截止频率验证 3 LTspice中如何添加光标 4 LTspice中如何将 幅频 和 相频曲线分开 1 伯德图介绍 Bode图由对数幅频特性和对数相频特性两张图组成 伯德图 百度百科 1 对数幅频特
  • 学习vue之node的安装

    关于node 简单的说 Node js 就是运行在服务端的 JavaScript Node js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 Node js 使用了一个事件驱动 非阻塞式 I O 的模型 使其轻量
  • Java 学习路线一条龙版

    Java 学习路线一条龙版 Java 学习路线一条龙版 by 程序员鱼皮 学习路线来源于 程序员鱼皮 大家可以去b站看看他的视频 视频导读 https www bilibili com video BV1Qf4y1K7ff 大纲 路线特点
  • wireshark抓包数据提取TCP/UDP/RTP负载数据方法

    1 背景 在视频抓包分析过程中 有时候需要从TCP UDP RTP中直接提取payload数据 比如较老的摄像机 有一些直接通过TCP UDP传输视频裸流 或者PS打包的视频流 通过提取TCP和UDP的负载数据就可以直接组成裸流或者PS流文
  • [Unity] AnimatorStates中的write defaults详解

    AnimatorState中有一个参数writeDefaultValues 在Inspector中显示的则是Write Defaults 官方文档对这个参数的解释是 Whether or not the AnimatorStates wri
  • WPF快速搭建MVVM框架

    WPFDemo项目结构 需更改App xaml上的属性StartupUri Views MainWindow xaml Views MainWindow xaml
  • Few-shot learning(少样本学习,入门篇)

    本文介绍一篇来自 https www analyticsvidhya com 关于少样本学习的的博客 原文地址 文章目录 1 少样本学习 1 1 为什么要有少样本学习 什么是少样本学习 1 2 元学习和传统有监督学习的区别是什么 1 3 一
  • 几个特殊TCP报文及TCP

    TCP Window Full 接收方接收缓冲区满了后 导致发送方的发送缓冲区装满待确认数据 此时发送方会发送一个TCP Window Full消息 TCP ZeroWindow 接收方应用没有及时recv消息 导致接收缓冲满 即滑动窗口为
  • Java开发学习----AOP通知获取数据(参数、返回值、异常)

    前面的博客我们写AOP仅仅是在原始方法前后追加一些操作 接下来我们要说说AOP中数据相关的内容 我们将从 获取参数 获取返回值 和 获取异常 三个方面来研究切入点的相关信息 前面我们介绍通知类型的时候总共讲了五种 那么对于这五种类型都会有参
  • Farbic Java SDK 1.4安装方法

    Hyperledger Fabric Java SDK是开发基于Hyperledger Fabric区块链的Java应用之必备开发包 本文将介绍如何在Maven Gradle和Eclipse中安装使用Hyperledger Fabric J
  • 【计算机二级】Python类

    1 程序设计语言的发展经历了从机器语言 汇编语言 到高级语言的发展历程 2 程序设计语言是计算机能够理解和识别用户操作意图的一种交互体系 它按照特定规则组织计算机指令 使计算机能够自动进行各种运算处理 按照程序设计语言规则组织起来的一组计算
  • Apache Flink:特性、概念、组件栈、架构及原理分析

    Table of Contents 1 摘要 2 基本特性 3 流处理特性 4 API支持 5 Libraries支持 6 整合支持 7 基本概念 7 1 Stream Transformation Operator 7 2 Paralle
  • 蓝桥杯2015年第六届真题-广场舞

    说在前面 其他博客中的代码应该保证不了健壮性 我这个 应该 可以 题目 题目链接 题解 数学 计算几何 提示 这题默认好像是顺时针或逆时针输入坐标 也就是说先后输入的两个点一定是多边形的一条边 前置知识 PNPoly算法 何为PNPoly算
  • SHT3x-DIS驱动及应用详解(附源码和手册)

    文章目录 一 电路组成 二 通讯指令说明 一 单次获取数据指令 二 周期获取数据指令 1 配置模式 2 读取数据 三 加快响应时间指令 四 停止周期读取数据指令 五 复位 1 IIC接口复位 2 软复位 重新初始化 3 一般呼叫复位指令 4