STM32和STM32CubeMX实现SHT30温湿度传感器 保姆级教程

【背景】

公司忽然说要知道产品的工作的环境情况,要知道工作的温度和湿度。那我就在板子上做个温湿度传感器。温湿度传感器很多,有名的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的波形,并不是很好的方波。但是,看起来,信号还算比较完美的。

好了,大功告成,亲个嘴儿。