182 lines
4.6 KiB
C
182 lines
4.6 KiB
C
#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;
|
||
}
|