文章目录
摘要:本文详细介绍 DHT30 温湿度传感器模块的引脚功能、I2C 通信时序与数据格式,并给出基于 STM32F103 的完整驱动代码(含 CRC8 校验)与实测串口输出,帮助读者快速上手该传感器的开发与调试。
一、DHT30 简介
DHT30 是一款小尺寸的温湿度传感器模块,采用针型连接器设计,便于集成与更换。模块内部集成了全新优化的 ASIC 专用芯片、高性能的 MEMS 半导体电容式湿度传感元件,以及标准的片上温度传感元件,具有功耗低、精度高的特点,即使在恶劣环境下也能保持稳定的性能。


二、引脚功能
| 引脚 | 功能 |
|---|---|
| 1-VDD | 电源正 |
| 2-SDA | 数据线 |
| 3-GND | 电源负 |
| 4-SCL | 时钟线 |

三、时序与数据说明
时序说明

传感器读取流程 :
传感器的VDD上电后需等待5ms,发送写测量命令0x70 0xAC 0x33 0x00,等待80ms测量完成;
在等待80ms测量完成后,发送 0x71 读传感器,可获取状态字 Status、温湿度校准数据SRH19:0、ST19:0 以及校准字 CRC

数据说明
1.状态字 Status

2.温湿度数据计算

3. CRC校验
将测量读取到的Status、SRH19:0、ST19:0进行CRC8检验,CRC初始值为0xFF,CRC8校验多项式为:CRC7:0=1+x4+x5+x8, CRC计算代码如下:
c
//**********************************************************//
//CRC校验类型:CRC8
//多项式:X8+X5+X4+1
//Poly:0011 0001 0x31
unsigned char Calc_CRC8(unsigned char *message,unsigned char Num)
{
unsigned char i;
unsigned char byte;
unsigned char crc =0xFF;
for (byte = 0;byte<Num;byte++)
{
crc^=(message[byte]);
for(i=8;i>0;--i)
{
if(crc&0x80)
crc=(crc<<1)^0x31;
else
crc=(crc<<1);
}
}
Return crc;
}
//**********************************************************/
四、程序
STM32
DHTC11 .C
c
#include "stm32f10x.h"
#include <stdio.h>
#include <Delay.h>
/*=========================================================
* DHT30
*
* 7位I2C地址:0x38
* 写地址:0x70
* 读地址:0x71
*=========================================================*/
#define DHT30_ADDR 0x38
/*=========================================================
* USART1
*
* PA9 -> TX
* PA10 -> RX
*
* 115200 8-N-1
*=========================================================*/
void USART1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_USART1,ENABLE);
/* PA9 -> TX */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* PA10 -> RX */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* USART */
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
/*=========================================================
* printf 重定向
*=========================================================*/
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (uint8_t)ch);
while (USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
return ch;
}
/*=========================================================
* I2C1初始化
*
* PB6 -> SCL
* PB7 -> SDA
*
* 100kHz
*=========================================================*/
void I2C1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
/* GPIOB时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
/* I2C1时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
/* PB6 SCL、PB7 SDA */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
/* I2C参数 */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C1,&I2C_InitStructure);
I2C_Cmd(I2C1,ENABLE);
}
/*=========================================================
* DHT30 CRC8
*
* 初始值:0xFF
* 多项式:0x31
*=========================================================*/
uint8_t DHT30_CRC8(uint8_t *data,uint8_t len)
{
uint8_t i;
uint8_t j;
uint8_t crc = 0xFF;
for (i = 0; i < len; i++)
{
crc ^= data[i];
for (j = 0; j < 8; j++)
{
if (crc & 0x80)
{
crc = (crc << 1) ^ 0x31;
}
else
{
crc <<= 1;
}
}
}
return crc;
}
/*=========================================================
* DHT30开始测量
*
* 发送:
* 0x70 0xAC 0x33 0x00
*=========================================================*/
uint8_t DHT30_StartMeasure(void)
{
uint32_t timeout;
/* 等待I2C空闲 */
timeout = 100000;
while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY))
{
if (--timeout == 0)
return 0;
}
/* START */
I2C_GenerateSTART(I2C1,ENABLE);
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT))
{
if (--timeout == 0)
return 0;
}
/* 发送DHT30写地址:0x70 */
I2C_Send7bitAddress(I2C1,DHT30_ADDR << 1,I2C_Direction_Transmitter);
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if (I2C_GetFlagStatus(I2C1,I2C_FLAG_AF))
{
I2C_ClearFlag(I2C1,I2C_FLAG_AF);
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
if (--timeout == 0)
{
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
}
/* 0xAC */
I2C_SendData(I2C1,0xAC);
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if (--timeout == 0)
{
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
}
/* 0x33 */
I2C_SendData(I2C1,0x33);
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if (--timeout == 0)
{
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
}
/* 0x00 */
I2C_SendData(I2C1,0x00);
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if (--timeout == 0)
{
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
}
/* STOP */
I2C_GenerateSTOP(I2C1,ENABLE);
return 1;
}
/*=========================================================
* 读取DHT30 7字节
*
* data[0] = Status
* data[1] = RH[19:12]
* data[2] = RH[11:4]
* data[3] = RH[3:0] + T[19:16]
* data[4] = T[15:8]
* data[5] = T[7:0]
* data[6] = CRC
*=========================================================*/
uint8_t DHT30_ReadData(uint8_t *data)
{
uint32_t timeout;
uint8_t i;
/* 打开ACK */
I2C_AcknowledgeConfig(I2C1,ENABLE);
/* 等待总线空闲 */
timeout = 100000;
while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY))
{
if (--timeout == 0)
return 0;
}
/* START */
I2C_GenerateSTART(I2C1,ENABLE);
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT))
{
if (--timeout == 0)
return 0;
}
/* DHT30读地址:0x71 */
I2C_Send7bitAddress(I2C1,DHT30_ADDR << 1,I2C_Direction_Receiver);
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
{
if (--timeout == 0)
{
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
}
/* 读取前6字节 */
for (i = 0; i < 6; i++)
{
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED))
{
if (--timeout == 0)
{
I2C_AcknowledgeConfig(I2C1,ENABLE);
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
}
data[i] = I2C_ReceiveData(I2C1);
}
/* 最后一个字节关闭ACK */
I2C_AcknowledgeConfig(I2C1,DISABLE);
timeout = 100000;
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED))
{
if (--timeout == 0)
{
I2C_AcknowledgeConfig(I2C1,ENABLE);
I2C_GenerateSTOP(I2C1,ENABLE);
return 0;
}
}
/* STOP */
I2C_GenerateSTOP(I2C1,ENABLE);
/* CRC */
data[6] = I2C_ReceiveData(I2C1);
/* 恢复ACK */
I2C_AcknowledgeConfig(I2C1,ENABLE);
return 1;
}
/*=========================================================
* DHT30读取温湿度
*=========================================================*/
uint8_t DHT30_Read(float *temperature,float *humidity)
{
uint8_t data[7];
uint8_t crc;
uint32_t raw_humidity;
uint32_t raw_temperature;
/* 启动测量 */
if (!DHT30_StartMeasure())
{
printf("Measure Start Error\r\n");
return 0;
}
/*
* 等待DHT30完成测量
* 手册要求约80ms
*/
Delay_ms(100);
/* 读取7字节 */
if (!DHT30_ReadData(data))
{
printf("I2C Read Error\r\n");
return 0;
}
/* CRC校验 */
crc = DHT30_CRC8(data,6);
if (crc != data[6])
{
printf("CRC Error\r\n");
return 0;
}
/* BUSY检查 */
if (data[0] & 0x80)
{
printf("DHT30 Busy\r\n");
return 0;
}
/*
* 湿度20位
*/
raw_humidity =((uint32_t)data[1] << 12) |((uint32_t)data[2] << 4) |((data[3] >> 4) & 0x0F);
/*
* 温度20位
*/
raw_temperature =((uint32_t)(data[3] & 0x0F) << 16) |((uint32_t)data[4] << 8) |data[5];
/*
* 湿度 RH = raw / 2^20 × 100
*/
*humidity = ((float)raw_humidity * 100.0f) / 1048576.0f;
/*
* 温度 T = raw / 2^20 × 200 - 50
*/
*temperature =((float)raw_temperature * 200.0f) / 1048576.0f - 50.0f;
return 1;
}
/*=========================================================
* MAIN
*=========================================================*/
int main(void)
{
float temperature;
float humidity;
/* USART1 */
USART1_Init();
/* I2C1 */
I2C1_Init();
/*
* DHT30上电延时稳定
*/
Delay_ms(100);
while (1)
{
if(DHT30_Read(&temperature,&humidity))
{
printf("T=%.2f C, H=%.2f %%RH\r\n",temperature,humidity);
}
Delay_ms(1000);
}
}
五、驱动测试现象
---------------------------------------------------DHT30接线--------------------------------------------------
PA9 ->TX
PA10->RX
PB6 ->SCL
PB7 ->SDA
注:(收到优信电子的DHT30模块后可以看到IIC接口并没有上拉,建议实际使用给模块的IIC接口上拉4.7K电阻)
开发板串口输出如下:

以上内容个人理解,如有不正欢迎指正,需要资料及工程可留言邮箱