【STM32】SHT30温湿度芯片驱动

目录

一、简单介绍

二、cubeMX配置

开调试口

开高速外部晶振

开I2C1

时钟设置

三、驱动开发

单次采样

触发采样

读温湿度

温湿度解析

周期采样

触发周期采样

读温湿度

读芯片状态

CRC校验

复位

主函数

四、工程链接


一、简单介绍

I2C通信,典型温度精度0.1度,湿度1.5%。

参考典型应用。

原理图如下:

RESET引脚使能芯片,拉高使能。

ADDR配置I2C总线地址。

如图是0x44。

SHT30上电后等待一段时间才能接收指令,没收到指令就进idle,是为了降低功耗。

采样时间越久,采样一致性越高。

二、cubeMX配置

开调试口

开高速外部晶振

开I2C1

时钟设置

三、驱动开发

芯片有两种测量模式,单次采样和周期采样模式

单次采样

MCU根据采样时间短中长和时钟是否延伸,有6种命令选择。

MCU用命令触发采样后,需要一小会等待,才能从SHT30获取数据。

图中空白是MCU发出,灰色是SHT30发出。

SHT30返回数据被MCU接收到,MCU要发ACK,否则SHT30就不继续回传数据。

先返回温度数据+CRC再返回湿度数据+CRC。

有一个时钟延伸的概念

不开启时钟延伸则发送读请求,SHT30回复NACK直到采集完毕。

开启时钟延伸则SHT30拉低SCL,直到采集完毕。

触发采样

cpp 复制代码
void SHT30_Single_Meas()
{
   uint8_t temp[2] = {0x24, 0x0B};
   HAL_I2C_Master_Transmit(SHT30_I2C, SHT30_I2C_ADDRESS, temp, 2, 0xFF);
}

读温湿度

cpp 复制代码
HAL_StatusTypeDef SHT30_RD_Meas()
{
   HAL_StatusTypeDef ret;
   ret = HAL_I2C_Master_Receive(SHT30_I2C, SHT30_I2C_ADDRESS, re, 6, 0xFF);
   return ret;
}

|----|--------|------|
| | 数据 | CRC |
| 温度 | 0x6663 | 0x66 |
| 湿度 | 0x4AC8 | 0x18 |

转换公式如下:

以摄氏度为例,对温度而言一个LSB大约175/65535=0.00267度。

湿度值=采样值/65565 * 100%。

温度值=采样值*0.00267度 - 45。

当前温度就是0x6663*0.00267 - 45=24.716度。

温湿度解析

cpp 复制代码
SHT30_ValueType SHT30_GetValue()
{
   SHT30_ValueType value;

   value.temp = (float)(re[0] * 256 + re[1]) * 0.00267f - 40.0f;
   value.humid = (float)(re[3] * 256 + re[4]) * 100.0f / 65535.0f;

   if (SHT30_CRC(re, 3) | SHT30_CRC(re + 3, 3))
   {
      /* crc error */
      value.crcError = 1;
   }
   else
   {
      value.crcError = 0;
   }
   return value;
}

周期采样

最快可以1秒采10次,最慢2秒1次。

触发周期采样

cpp 复制代码
void SHT30_Period_Meas()
{
   // uint8_t temp[2] = {0x27, 0x21}; /* 10 MPS */
   // uint8_t temp[2] = {0x23, 0x22}; /* 4 MPS */
   uint8_t temp[2] = {0x21, 0x26};/* 1 MPS */
   HAL_I2C_Master_Transmit(SHT30_I2C, SHT30_I2C_ADDRESS, temp, 2, 0xFF);
}

读温湿度

与单次采样不同,读取周期采样的数据,需要先发送Fetch指令,再读取数据

cpp 复制代码
void SHT_Fetch_Meas()
{
   uint8_t temp[2] = {0xE0, 0x00};
   HAL_I2C_Master_Transmit(SHT30_I2C, SHT30_I2C_ADDRESS, temp, 2, 0xFF);
}

如果选择1sample/s,但是读数据频率却比1hz快,就有概率读不到东西

波形如下

直到数据采集完毕

读芯片状态

发送0xF32D后就可以读回芯片的状态寄存器内容

cpp 复制代码
void SHT30_RD_Status()
{
   uint8_t temp[3] = {0xF3, 0x2D, 0x00};
   HAL_I2C_Master_Transmit(SHT30_I2C, SHT30_I2C_ADDRESS, temp, 2, 0xFF);
   HAL_I2C_Master_Receive(SHT30_I2C, SHT30_I2C_ADDRESS, temp, 3, 0xFF);
   SHT30_status = temp[0] * 256 + temp[1];
}

CRC校验

SHT采用的是CRC8算法。

cpp 复制代码
static uint8_t SHT30_CRC(uint8_t* data, uint8_t len)
{
   uint8_t crc = 0xFF;

   while (len--)
   {
      crc ^= *(data++);
      for (uint8_t i = 0; i < 8; i++)
      {
         if (crc & 0x80)
         {
            crc = (crc << 1) ^ 0x31;
         }
         else
         {
            crc = (crc << 1);
         }
      }
   }
   return crc;
}

复位

芯片支持reset引脚复位和i2c总线指令复位,后者可以单独发送复位指令或者通用复位。

区别在于单独复位指定地址的SHT30还是复位这条i2c总线上的所有SHT30

芯片也提供一个加热器,为了避免出现"少玩5毛钱"的情况,笔者也使用一番。

加热效果微弱,正如手册描述的那样"lies in the range of a few degrees centigrade."

cpp 复制代码
void SHT30_Reset()
{
   uint8_t temp[2] = {0x00, 0x06};
   HAL_I2C_Master_Transmit(SHT30_I2C, SHT30_I2C_ADDRESS, temp, 2, 0xFF);
}

主函数

使用1.54寸TFT彩屏打印采集到的温湿度数据和芯片状态

cpp 复制代码
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t str[20];
SHT30_ValueType temp_humid;
uint16_t deva;
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2C1_Init();
  MX_SPI2_Init();
  /* USER CODE BEGIN 2 */

   ST7789_Init();
   ST7789_Clear(BLACK);
   SHT30_Reset();
   SHT30_CLR_Status();
   HAL_Delay(10);
#ifdef PERIOD
   SHT30_Period_Meas();
#endif
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

   sprintf(str, "temp:%.2f'C  ", temp_humid.temp);
   ST7789_ShowString(0, 90, str, Font_16x26, ST7789_RGB565(0xc0a91e), BLACK);

   sprintf(str, "humid:%.0f%%  ", temp_humid.humid);
   ST7789_ShowString(0, 120, str, Font_16x26, ST7789_RGB565(0x1185e5), BLACK);

   sprintf(str, "CRC:%d", temp_humid.crcError);
   ST7789_ShowString(0, 150, str, Font_16x26, ST7789_RGB565(0xe74033), BLACK);

   sprintf(str, "status:0x%04X", SHT30_status);
   ST7789_ShowString(0, 180, str, Font_16x26, ST7789_RGB565(0x43b131), BLACK);

   sprintf(str, "DEVA:%d", deva);
   ST7789_ShowString(0, 210, str, Font_16x26, ST7789_RGB565(0xca64ea), BLACK);

#ifdef PERIOD
   SHT_Fetch_Meas();
#else
   SHT30_Single_Meas();
   HAL_Delay(20);
#endif
   
   if (SHT30_RD_Meas() != HAL_OK)
   {
      deva++;
   }

   temp_humid = SHT30_GetValue();
   SHT30_RD_Status();
   
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

效果如下

四、工程链接

STM32SHT30温湿度计驱动工程资源-CSDN下载

相关推荐
雾削木2 小时前
STM32 HAL 软件SPI任意GPIO控制st7735
stm32·单片机·嵌入式硬件
Molesidy2 小时前
【Embedded Development】对于MCU的片内内存里的分布区域结构详解
单片机·嵌入式硬件
国科安芯3 小时前
AS32A601型MCU芯片flash模块的擦除和编程
java·linux·前端·单片机·嵌入式硬件·fpga开发·安全性测试
创界工坊工作室11 小时前
DPJ-120 基于STC89C52的多功能清扫消杀车控制系统设计(源代码+proteus仿真)
stm32·单片机·嵌入式硬件·51单片机·proteus
Darken0312 小时前
引脚重映射是什么意思?如何使用?
stm32·单片机·引脚重映射
知南x12 小时前
【正点原子STM32MP157 可信任固件TF-A学习篇】(2) STM32MP1 中的 TF-A
stm32·嵌入式硬件·学习·stm32mp157
逐步前行13 小时前
C51_OLED
单片机
欢鸽儿14 小时前
Vitis】Linux 下彻底清除启动界面 Recent Workspaces 历史路径
linux·嵌入式硬件·fpga
LaoZhangGong12314 小时前
深度学习uip中“uip_arp.c“
c语言·stm32·以太网·arp·uip·enc28j60