Files
ETH_TCP_Demo/app/sht40.c
2026-03-09 15:34:18 +08:00

250 lines
6.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* SHT40 温湿度传感器驱动
* 功能通过I2C1读取SHT40传感器的温湿度数据
* 依赖STM32 HAL库
* 跨平台仅适用于STM32F4系列使用HAL库的I2C接口
*/
#include "sht40.h"
#include "board.h"
#include "osal.h"
#include "hal.h"
/* 硬件抽象层操作结构体 */
const hal_ops_t *hal_ops = NULL;
/* CRC校验函数 */
static uint8_t sht40_crc8(const uint8_t *data, uint8_t len)
{
const uint8_t POLYNOMIAL = 0x31;
uint8_t crc = 0xFF;
for (uint8_t i = 0; i < len; i++)
{
crc ^= data[i];
for (uint8_t j = 0; j < 8; j++)
{
if (crc & 0x80)
{
crc = (crc << 1) ^ POLYNOMIAL;
}
else
{
crc <<= 1;
}
}
}
return crc;
}
/**
* @brief 初始化SHT40传感器
* @return 0成功-1失败
*/
int sht40_init(void)
{
/* 初始化硬件抽象层操作结构体 */
hal_ops = hal_get_ops();
if (hal_ops == NULL)
{
osal_log_e("SHT40: Failed to get HAL ops");
return -1;
}
return sht40_reset();
}
/**
* @brief 重置SHT40传感器
* @return 0成功-1失败
*/
int sht40_reset(void)
{
uint8_t cmd = SHT40_CMD_RESET;
osal_log_i("SHT40: Sending reset command 0x%02X", cmd);
if (hal_ops->i2c->master_transmit(SHT40_I2C_ADDR << 1, &cmd, 1, 1000) != HAL_STATUS_OK)
{
osal_log_e("SHT40 reset failed");
return -1;
}
osal_thread_mdelay(1); // 重置需要<1ms
osal_log_i("SHT40: Reset successful");
return 0;
}
/**
* @brief 读取SHT40传感器的序列号
* @param serial 序列号4字节
* @return 0成功-1失败
*/
int sht40_read_serial(uint32_t *serial)
{
uint8_t cmd = SHT40_CMD_READ_SERIAL;
uint8_t data[6];
//osal_log_i("SHT40: Sending read serial command 0x%02X", cmd);
if (hal_ops->i2c->master_transmit(SHT40_I2C_ADDR << 1, &cmd, 1, 1000) != HAL_STATUS_OK)
{
osal_log_e("SHT40 send read serial command failed");
return -1;
}
osal_thread_mdelay(1);
if (hal_ops->i2c->master_receive(SHT40_I2C_ADDR << 1, data, 6, 1000) != HAL_STATUS_OK)
{
osal_log_e("SHT40 read serial data failed");
return -1;
}
/* 校验数据 */
if (sht40_crc8(&data[0], 2) != data[2])
{
osal_log_e("SHT40 serial CRC error (bytes 0-2)");
return -1;
}
if (sht40_crc8(&data[3], 2) != data[5])
{
osal_log_e("SHT40 serial CRC error (bytes 3-5)");
return -1;
}
*serial = (uint32_t)(data[0] << 24) | (data[1] << 16) | (data[3] << 8) | data[4];
//osal_log_i("SHT40: Serial number: 0x%08X", *serial);
return 0;
}
/**
* @brief 开启SHT40传感器的加热器
* @param power_level 功率级别0=低功率(20mW), 1=中功率(110mW), 2=高功率(200mW)
* @return 0成功-1失败
*/
int sht40_heater_enable(uint8_t power_level)
{
uint8_t cmd;
switch (power_level)
{
case 0:
cmd = SHT40_CMD_HEATER_LOW;
//osal_log_i("SHT40: Enabling heater (low power, 20mW)");
break;
case 1:
cmd = SHT40_CMD_HEATER_MED;
//osal_log_i("SHT40: Enabling heater (medium power, 110mW)");
break;
case 2:
cmd = SHT40_CMD_HEATER_HIGH;
//osal_log_i("SHT40: Enabling heater (high power, 200mW)");
break;
default:
osal_log_e("SHT40: Invalid heater power level");
return -1;
}
if (hal_ops->i2c->master_transmit(SHT40_I2C_ADDR << 1, &cmd, 1, 1000) != HAL_STATUS_OK)
{
osal_log_e("SHT40 heater enable failed");
return -1;
}
osal_thread_mdelay(1000); // 加热器持续1秒
//osal_log_i("SHT40: Heater operation completed");
return 0;
}
/**
* @brief 读取SHT40传感器的温湿度数据支持不同精度
* @param temperature 温度值(摄氏度)
* @param humidity 湿度值(百分比)
* @param precision 精度级别0=低精度, 1=中精度, 2=高精度
* @return 0成功-1失败
*/
int sht40_read_temperature_humidity_with_precision(float *temperature, float *humidity, uint8_t precision)
{
uint8_t cmd;
uint16_t delay_ms;
switch (precision)
{
case 0:
cmd = SHT40_CMD_MEASURE_LOW_PRECISION;
delay_ms = 2; // 1.8ms
//osal_log_i("SHT40: Using low precision measurement");
break;
case 1:
cmd = SHT40_CMD_MEASURE_MED_PRECISION;
delay_ms = 5; // 4.5ms
//osal_log_i("SHT40: Using medium precision measurement");
break;
case 2:
default:
cmd = SHT40_CMD_MEASURE_HIGH_PRECISION;
delay_ms = 10; // 8.2ms
//osal_log_i("SHT40: Using high precision measurement");
break;
}
uint8_t data[6];
//osal_log_i("SHT40: Sending measure command 0x%02X to address 0x%02X", cmd, SHT40_I2C_ADDR);
/* 发送测量命令 */
if (hal_ops->i2c->master_transmit(SHT40_I2C_ADDR << 1, &cmd, 1, 1000) != HAL_STATUS_OK)
{
osal_log_e("SHT40 send measure command failed");
return -1;
}
//osal_log_i("SHT40: Measure command sent successfully");
/* 等待测量完成 */
osal_thread_mdelay(delay_ms);
/* 读取测量结果 */
//osal_log_i("SHT40: Reading 6 bytes of data");
if (hal_ops->i2c->master_receive(SHT40_I2C_ADDR << 1, data, 6, 1000) != HAL_STATUS_OK)
{
osal_log_e("SHT40 read data failed");
return -1;
}
//osal_log_i("SHT40: Data read successfully: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X",
// data[0], data[1], data[2], data[3], data[4], data[5]);
/* 校验温度数据 */
if (sht40_crc8(&data[0], 2) != data[2])
{
osal_log_e("SHT40 temperature CRC error");
return -1;
}
/* 校验湿度数据 */
if (sht40_crc8(&data[3], 2) != data[5])
{
osal_log_e("SHT40 humidity CRC error");
return -1;
}
/* 计算温度值 */
uint16_t temp_raw = (data[0] << 8) | data[1];
*temperature = -45.0f + 175.0f * (float)temp_raw / 65535.0f;
/* 计算湿度值 */
uint16_t hum_raw = (data[3] << 8) | data[4];
*humidity = -6.0f + 125.0f * (float)hum_raw / 65535.0f;
/* 湿度值范围限制 */
if (*humidity < 0.0f) *humidity = 0.0f;
if (*humidity > 100.0f) *humidity = 100.0f;
return 0;
}
/**
* @brief 读取SHT40传感器的温湿度数据默认高精度
* @param temperature 温度值(摄氏度)
* @param humidity 湿度值(百分比)
* @return 0成功-1失败
*/
int sht40_read_temperature_humidity(float *temperature, float *humidity)
{
return sht40_read_temperature_humidity_with_precision(temperature, humidity, 2); // 默认使用高精度
}