#include "sht40.h" #include "i2cs.h" #include "delay.h" #define SHT40_SDA_PORT I2C1_SDA_GPIO_Port #define SHT40_SDA_PIN I2C1_SDA_Pin #define SHT40_SCL_PORT I2C1_SCL_GPIO_Port #define SHT40_SCL_PIN I2C1_SCL_Pin #define SHT40_I2C_ADDRESS 0x44 #define SHT40_MEASURE_CMD 0xFD // 2*8-bit T-data:8-bit CRC:2*8-bit RH-data: 8-bit CRC static i2c_t *_sht40_i2c; static TIM_TypeDef *_timer_us; static uint8_t crc8(uint8_t *data, uint8_t len); static void _delay_us(uint32_t us) { if (_timer_us != NULL) { delay_hardware_us(_timer_us, us); } else { delay_us(us); } } void sht40_test(void) { float32 temperature = 0; float32 humidity = 0; sht40_read(&temperature, &humidity); __NOP(); } /** * @brief 初始化 SHT40 传感器 * * 该函数用于初始化 SHT40 传感器,包括创建 I2C 通讯所需的 GPIO 引脚和 I2C 通讯对象。 * * 初始化完成后,sht40_i2c 变量将用于后续的 SHT40 传感器通信。 */ void sht40_init(TIM_TypeDef *timer_us) { DBG_ASSERT(timer_us != NULL __DBG_LINE); if (timer_us != NULL) { _timer_us = timer_us; ENABLE_TIM_COUNT(_timer_us); } i2c_gpio_group_t gpios; gpios.scl = gpio_create(SHT40_SCL_PORT, SHT40_SCL_PIN); gpios.sda = gpio_create(SHT40_SDA_PORT, SHT40_SDA_PIN); _sht40_i2c = i2c_create(gpios, 10); DBG_ASSERT(_sht40_i2c != NULL __DBG_LINE); // sht40_test(); // 测试 SHT40 } /** * @brief 初始化 SHT40 传感器 * * 此函数用于初始化 SHT40 温湿度传感器,以便进行后续的温度和湿度测量。 * * 注意:该函数没有返回值,也不接受任何参数。 */ void sht40_dinit(void) { GPIO_SET_ANALOG(SHT40_SDA_PORT, SHT40_SDA_PIN); GPIO_SET_ANALOG(SHT40_SCL_PORT, SHT40_SCL_PIN); } /** * @brief 读取温湿度传感器数据 * * 从温湿度传感器读取温度和湿度数据,并将读取到的数据存储在传入的浮点数指针指向的位置。 * * @param temperature 用于存储读取到的温度值的浮点数指针 * @param humidity 用于存储读取到的湿度值的浮点数指针 */ BOOL sht40_read(float32 *temperature, float32 *humidity) { uint8_t data[6]; osel_memset(data, 0, ARRAY_LEN(data)); // 发送开始信号 _sht40_i2c->interface.start(_sht40_i2c); // 发送写入地址命令 _sht40_i2c->interface.write_byte(_sht40_i2c, SHT40_I2C_ADDRESS << 1); // 等待写入地址命令响应 if (_sht40_i2c->interface.wait_ack(_sht40_i2c) == FALSE) { return FALSE; } // 发送测量命令 _sht40_i2c->interface.write_byte(_sht40_i2c, SHT40_MEASURE_CMD); // 等待测量命令响应 if (_sht40_i2c->interface.wait_ack(_sht40_i2c) == FALSE) { return FALSE; } // 停止I2C总线 _sht40_i2c->interface.stop(_sht40_i2c); _delay_us(10000); // 根据 SHT40 数据手册,等待至少 10ms // 发送开始信号 _sht40_i2c->interface.start(_sht40_i2c); // 发送写入地址命令 _sht40_i2c->interface.write_byte(_sht40_i2c, (SHT40_I2C_ADDRESS << 1) | 1); // 等待写入地址命令响应 if (_sht40_i2c->interface.wait_ack(_sht40_i2c) == FALSE) { return FALSE; } for (uint8_t i = 0; i < ARRAY_LEN(data); i++) { if (i == 5) { data[i] = _sht40_i2c->interface.read_byte(_sht40_i2c, FALSE); } else { data[i] = _sht40_i2c->interface.read_byte(_sht40_i2c, TRUE); } } // 停止I2C总线 _sht40_i2c->interface.stop(_sht40_i2c); *temperature = 0; *humidity = 0; if (crc8(&data[0], 2) != data[2] || crc8(&data[3], 2) != data[5]) { return FALSE; } else { *temperature = (float32)((uint16_t)data[0] << 8 | data[1]) * 175 / 65535 - 45; *humidity = (float32)((uint16_t)data[3] << 8 | data[4]) * 125 / 65535 - 6; if (*humidity > 100) { *humidity = 100; } if (*humidity < 0) { *humidity = 0; } return TRUE; } } /** * @brief crc8校验函数,多项式为 x^8 + x^5 + x^4 + 1 * @param data 要校验的数据 * @param len 要校验的数据的字节数 * @retval 校验结果 * @note 该校验适合SHT3温湿度传感器的数据校验 */ static uint8_t crc8(uint8_t *data, uint8_t len) { const uint8_t polynomial = 0x31; uint8_t crc = 0xFF; int i, j; for (i = 0; i < len; ++i) { crc ^= *data++; for (j = 0; j < 8; ++j) { crc = (crc & 0x80) ? (crc << 1) ^ polynomial : (crc << 1); } } return crc; }