上期我们介绍了一个STM32毕设的器件选型,其中有温湿度传感器,我推荐了SHT30。

在CSDN上一搜温度传感器,冒出来的就是DHT11,大部分朋友在选型时也会选DHT11,是一个实打实的已经“烂大街”的传感器。听一些HR说看到简历上写着DHT11,就知道是什么水准了。

   DHT11采用单总线通讯协议即one-wire,数据以位为单位传输,每个数据位持续 50 微秒。高电平持续 26-28 微秒表示一个逻辑 "1",高电平持续 70 微秒表示一个逻辑 "0"。在学习51单片机的时候使用的非常多。

    而SHT30采用的是标准I2C通讯协议,是多数低速传感器都会采用的通讯协议,相较于DHT11有着更复杂的技术栈和在STM32等更为简单的实现,具有更高的精度和稳定性。

  本期我们介绍如何分别利用STM32和ESP32实现SHT30。

 关于SHT30,其实操作起来比较简单,它的器件地址是0x44,我们只需要对其写入命令,读取数据,查阅数据手册后将相关的命令使用宏定义实现。


// SHT30 I2C地址 (ADDR引脚接GND时为0x44)
#define SHT30_ADDR    0x44    // 7位地址:0x44 (ADDR引脚接GND时)

// SHT30命令列表
#define SHT30_SOFT_RESET    0x30A2  // 软复位
#define SHT30_HIGH_ENABLED  0x2C06  // 周期测量,高重复性
#define SHT30_READ_STATUS   0xF32D  // 读状态寄存器
#define SHT30_CLEAR_STATUS  0x3041  // 清除状态寄存器
#define SHT30_STOP_MEASURE  0x3093  // 停止周期测量
#define SHT30_SINGLE_HIGH   0x2400  // 单次测量,高重复性

    之后利用硬件I2C实现命令发送。


static uint8_t SHT30_Send_Cmd(uint16_t cmd)
{
    uint8_t cmd_buffer[2];
    cmd_buffer[0] = cmd >> 8;    // 高字节
    cmd_buffer[1] = cmd & 0xFF;  // 低字节
    return HAL_I2C_Master_Transmit(&hi2c1, (SHT30_ADDR << 1), cmd_buffer, 2, 0xFF);
}

    它的读取函数也很简单,我们在读取前需要发送单次测量命令,之后直接读取寄存器的值。


// 读取温湿度数据
uint8_t SHT30_Read_Temp_Hum(float *temperature, float *humidity)
{
    uint8_t buffer[6];
    uint16_t temp_raw, hum_raw;
    // 发送单次测量命令
    if(SHT30_Send_Cmd(SHT30_SINGLE_HIGH) != HAL_OK)
        return HAL_ERROR;
    // 等待测量完成
    HAL_Delay(15);
    // 读取6个字节数据,注意这里要用读地址(末位为1)
    if(HAL_I2C_Master_Receive(&hi2c1, (SHT30_ADDR << 1) | 0x01, buffer, 6, 0xFF) != HAL_OK)
        return HAL_ERROR;
    // 温度数据转换
    temp_raw = ((uint16_t)buffer[0] << 8) | buffer[1];
    *temperature = -45 + 175 * ((float)temp_raw / 65535);
    // 湿度数据转换
    hum_raw = ((uint16_t)buffer[3] << 8) | buffer[4];
    *humidity = 100 * ((float)hum_raw / 65535);
    return HAL_OK;
}

    第1,2个字节表示温度数据,第3,4个字节表示湿度数据

    利用公式:温度 = -45 + (175 * (温度数据 / 65536))

    湿度同样如此,我们就可以获取温湿度数据了。

    在此基础上,利用结构体深度封装一下。


typedef struct {
    float temperature;    // 温度值
    float humidity;       // 湿度值
} SHT30_Data_t;

// SHT30设备结构体
typedef struct {
    I2C_HandleTypeDef* hi2c;     // I2C句柄
    uint8_t dev_addr;            // 设备地址
    SHT30_Data_t data;          // 测量数据
    uint8_t init_flag;          // 初始化标志
} SHT30_HandleTypeDef;

    之后就可以在我们的主函数使用了。


 if(SHT30_Init(&hsht30, &hi2c1) != HAL_OK)
  {
     Error_Handler();
  }
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
    if(SHT30_ReadData(&hsht30) == HAL_OK)
    {
        float temp = SHT30_GetTemperature(&hsht30);
        float humi = SHT30_GetHumidity(&hsht30);
    }
    HAL_Delay(1000); 
  }

 关于SHT30,其实操作起来比较简单,它的器件地址是0x44,我们只需要对其写入命令,读取数据,查阅数据手册后将相关的命令使用宏定义实现。


// SHT30 I2C地址 (ADDR引脚接GND时为0x44)
#define SHT30_ADDR    0x44    // 7位地址:0x44 (ADDR引脚接GND时)

// SHT30命令列表
#define SHT30_SOFT_RESET    0x30A2  // 软复位
#define SHT30_HIGH_ENABLED  0x2C06  // 周期测量,高重复性
#define SHT30_READ_STATUS   0xF32D  // 读状态寄存器
#define SHT30_CLEAR_STATUS  0x3041  // 清除状态寄存器
#define SHT30_STOP_MEASURE  0x3093  // 停止周期测量
#define SHT30_SINGLE_HIGH   0x2400  // 单次测量,高重复性

    之后利用硬件I2C实现命令发送。


static uint8_t SHT30_Send_Cmd(uint16_t cmd)
{
    uint8_t cmd_buffer[2];
    cmd_buffer[0] = cmd >> 8;    // 高字节
    cmd_buffer[1] = cmd & 0xFF;  // 低字节
    return HAL_I2C_Master_Transmit(&hi2c1, (SHT30_ADDR << 1), cmd_buffer, 2, 0xFF);
}

    它的读取函数也很简单,我们在读取前需要发送单次测量命令,之后直接读取寄存器的值。


// 读取温湿度数据
uint8_t SHT30_Read_Temp_Hum(float *temperature, float *humidity)
{
    uint8_t buffer[6];
    uint16_t temp_raw, hum_raw;
    // 发送单次测量命令
    if(SHT30_Send_Cmd(SHT30_SINGLE_HIGH) != HAL_OK)
        return HAL_ERROR;
    // 等待测量完成
    HAL_Delay(15);
    // 读取6个字节数据,注意这里要用读地址(末位为1)
    if(HAL_I2C_Master_Receive(&hi2c1, (SHT30_ADDR << 1) | 0x01, buffer, 6, 0xFF) != HAL_OK)
        return HAL_ERROR;
    // 温度数据转换
    temp_raw = ((uint16_t)buffer[0] << 8) | buffer[1];
    *temperature = -45 + 175 * ((float)temp_raw / 65535);
    // 湿度数据转换
    hum_raw = ((uint16_t)buffer[3] << 8) | buffer[4];
    *humidity = 100 * ((float)hum_raw / 65535);
    return HAL_OK;
}

    第1,2个字节表示温度数据,第3,4个字节表示湿度数据

    利用公式:温度 = -45 + (175 * (温度数据 / 65536))

    湿度同样如此,我们就可以获取温湿度数据了。

    在此基础上,利用结构体深度封装一下。


typedef struct {
    float temperature;    // 温度值
    float humidity;       // 湿度值
} SHT30_Data_t;

// SHT30设备结构体
typedef struct {
    I2C_HandleTypeDef* hi2c;     // I2C句柄
    uint8_t dev_addr;            // 设备地址
    SHT30_Data_t data;          // 测量数据
    uint8_t init_flag;          // 初始化标志
} SHT30_HandleTypeDef;

    之后就可以在我们的主函数使用了。


 if(SHT30_Init(&hsht30, &hi2c1) != HAL_OK)
  {
     Error_Handler();
  }
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
    if(SHT30_ReadData(&hsht30) == HAL_OK)
    {
        float temp = SHT30_GetTemperature(&hsht30);
        float humi = SHT30_GetHumidity(&hsht30);
    }
    HAL_Delay(1000); 
  }

 ESP32上开发相对简单,在Arduino中下载相对应的库。

// 初始化I2C通信,指定ESP32的SDA和SCL引脚
  Wire.begin(SDA_PIN, SCL_PIN);
  // 初始化SHT31D传感器,默认地址0x44
  sht31d.begin(0x44);
  SHT31D result = sht31d.readTempAndHumidity(SHT3XD_REPEATABILITY_HIGH, SHT3XD_MODE_POLLING, 50);
  // 打印温度数据
  Serial.print("温度 (°C): ");
  Serial.println(result.t);
  Serial.println("");
  // 打印湿度数据
  Serial.print("湿度 (%RH): ");
  Serial.println(result.rh);

    之后依据库API打印数据即可。

之后我们可以测试一下,利用ESP32将温湿度数据每隔半小时上传到MQTT服务器,在云服务器部署相应网页。

嘉立创PCB

还没有评论,抢个沙发!