driver/sht40.c

182 lines
4.6 KiB
C
Raw Permalink 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.

#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;
}