【背景】
公司忽然说要知道产品的工作的环境情况,要知道工作的温度和湿度。那我就在板子上做个温湿度传感器。温湿度传感器很多,有名的DHT11什么的多得很,我在淘宝上看了一下,发现卖sht系列的比较多,我就选了个sht30的。
【硬件设计】


硬件设计很简单,就是i2c通信就行了。VDD=3.3V
【软件设计】
也很简单。我开始在网上看了一下,用模拟I2C的很多,还有人把程序搞成付费的,没有必要。这程序很简单,用STM32的HAL库最简单了。几句就能搞定。我现在免费的完全公开给大家。
sht30.h
cpp
#ifndef __SHT30_H_
#define __SHT30_H_
#include "main.h"
#include <stdint.h>
#include <sys/types.h>
#include "uart.h"
#include "delay.h"
#define SHT30_ADDRESS 0x44 // I2C address of the SHT30 sensor
#define SHT30_ADDRESS_WRITE (SHT30_ADDRESS << 1) // I2C write address
#define SHT30_ADDRESS_READ (SHT30_ADDRESS << 1) | 0x01 // I2C read address, HAL_I2C_Master_Receive()会自动处理读写位,不需要手动处理,但是手动处理也可以,这个或上的读写位被库函数忽略了。
extern I2C_HandleTypeDef hi2c2;
extern uint8_t sht30_data[6]; // Buffer to store the 6 bytes of data read from the SHT30 sensor
void sht30_read(uint8_t *data, uint16_t len);
uint8_t sht30_crc(const uint8_t *data, uint16_t len);
void sht30_crc_test(void);
#endif /* __SHT30_H_ */
sht30.c
cpp
#include "sht30.h"
// 初始值 0xFF,多项式 0x31
uint8_t sht30_crc(const uint8_t *data, uint16_t len)
{
uint8_t crc = 0xFF; // 初始值为0xFF
for (uint16_t i = 0; i < len; i++)
{
crc ^= data[i]; // 将当前字节与CRC进行异或运算
for (uint8_t j = 0; j < 8; j++)
{
if (crc & 0x80) // 检查最高位是否为1
{
crc = (crc << 1) ^ 0x31; // 左移一位并与多项式0x31进行异或
}
else
{
crc <<= 1; // 仅左移一位
}
}
}
return crc;
}
void sht30_crc_test(void)
{
// Test implementation for CRC calculation
uint8_t crc_test = 0;
uint8_t crc_in_data[2] = {0xbe, 0xef};
crc_test= sht30_crc(crc_in_data, 2);
printf("SHT30 CRC 0x%02X\r\n", crc_test);
delay_ms(1000);
}
void sht30_read(uint8_t *data, uint16_t len)
{
// 发送读取命令
uint8_t cmd[2] = {0x2C, 0x06}; // 高精度测量命令
// uint8_t cmd[2] = {0xE0, 0x00}; // 周期读测量命令
int status=0;
status = HAL_I2C_Master_Transmit(&hi2c2, SHT30_ADDRESS_WRITE, (uint8_t *)cmd, 2, 0xffff); // 发送命令到SHT30, 100ms
if (status != HAL_OK)
{
printf("SHT30 command transmit failed with status: %d\r\n", status);
return;
}
// 等待测量完成,SHT30的测量时间约为15ms
delay_ms(20);
// 接收数据
status = HAL_I2C_Master_Receive(&hi2c2, SHT30_ADDRESS_WRITE, data, len, 0xffff); // 接收数据
if (status != HAL_OK)
{
printf("SHT30 data receive failed with status: %d\r\n", status);
return;
}
if(sht30_crc(data, 2) != data[2] || sht30_crc(data + 3, 2) != data[5])
{
printf("SHT30 CRC check failed\r\n");
return;
}
uint16_t rawTemp = (data[0] << 8) | data[1];
uint16_t rawHum = (data[3] << 8) | data[4];
float temperature = -45 + 175 * ((float)rawTemp / 65535.0);
float humidity = 100 * ((float)rawHum / 65535.0);
printf("SHT30 Temperature: %.2f Degree, Humidity: %.2f%%\r\n", temperature, humidity);
}
I2C使用的i2c2, 时钟是100khz的。
main.c
while(1)里放下列代码
cpp
#if 1
sht30_crc_test();
sht30_read(sht30_data, 6);
printf("SHT30 data read: ");
for (int i = 0; i < 6; i++)
{
printf("0x%02X ", sht30_data[i]);
}
printf("\r\n");
#endif
【结果检验】
打印出来的结果是这样。

办公室的温度是26.64°,湿度49.63%
用示波器看看i2c的波形,如下。

放大点看,是这样的。
这就是i2c的波形,并不是很好的方波。但是,看起来,信号还算比较完美的。