文章目录
一、DHTC11 简介
DHTC11 是采用高稳定性电容式感湿元件作为传感元件,经过微处理器采集处理转化成数字信号输出。每一个传感器都经过标定校准和测试。具有长期稳定、可靠性高、 精度高、低功耗等特点。

二、引脚功能

| 引脚 | 功能 |
|---|---|
| VDD | 电源正 |
| SDA | 数据线 |
| NA | 悬空 |
| GND | 电源负 |
三、指令
| 指令 | 功能 |
|---|---|
| CCDDH | 读取湿度校准数 A、B |
| CC10H | 触发温湿度测量 |
| CCBDH | 读取转化结果 |
四、时序与数据
时序说明
DHTC11 为了精确测量气体的湿度,减少温度对测量的影响,DHTC11 传感器在非工作期间,自动转为休眠模式,以降低传感器自身的发热对周围气体湿度的影响。DHTC11 采用被动式工作模式,即主机通过指令唤醒传感器后,传感器才开始测量、应答等动作。通讯结束后,传感器进入休眠状态。

单总线复位时序

单总线写 0 时序

单总线写 1 时序

单总线读取时序

数据说明
发送指令 0xCCDD 获取湿度校准数据 A、B
发送指令 0xCC10 触发温湿度转化。耗时约 30ms
发送指令 0xCCBD 获取温湿度转化结果。
客户同样可以无需等待读取,则此时读取的为上次触发转化的温湿度数据。
通过上面方式可以获得 16bit 温度原始数据 St、16bit 湿度原始数据 Sh
最终带入下面公式

五、程序
C51
DHTC11 .C
c
#include <STC89C5xRC.H>
#include <OneWire.h>
#include <delay.h>
#include <LCD1602.h>
short int OwHumA,OwHumB;//湿度校准数据 A、B
unsigned char IntToString(unsigned char *str, int dat)//整形转字符串
{
signed char i = 0;
unsigned char len = 0;
unsigned char buf[6];
if (dat < 0) //如果为负数,首先取绝对值,并在指针上添加负号
{
dat = -dat;
*str ++ = '-';
len ++;
}
do { //先转换成 低位在前的十进制数组 将低位高位互换
buf[i++] = dat % 10;//取余
dat /= 10;//去掉个位 (/运算结果要舍弃小数)
} while (dat > 0);
len += i; //i 最后的值就是有效字符的个数
while (i -- > 0) //将数组值转换为 ASCII 码反向拷贝到接收指针上
{
*str++ = buf[i] + '0';
}
*str = '\0'; //添加字符串结束符
return len; //返回字符串长度
}
unsigned char CRC8MHT_Cal(unsigned char *serial, unsigned char length)//CRC检验运算 serial数组/字符串,length 长度
{
unsigned char result = 0x00;
unsigned char pDataBuf;
unsigned char i;
while(length--)
{
pDataBuf = *serial++;
for(i=0; i<8; i++)
{
if((result^(pDataBuf))&0x01)
{
result ^= 0x18;
result >>= 1;
result |= 0x80;
}
else
{
result >>= 1;
}
pDataBuf >>= 1;
}
}
return result;
}
void DHTC11_MInit_OW()
{
unsigned char i,crc;
unsigned char ResDat[13];
OneWire_Init(); //初始化 这里没有对返回做判断
OneWire_SendByte(0xcc);
OneWire_SendByte(0xDD); //获取湿度校准数据 A、B
for(i=0;i<13;i++)
{
ResDat[i] = OneWire_ReceiveByte();
}
crc = CRC8MHT_Cal(ResDat,13);
if(crc == 0)
{
OwHumA = ResDat[0];
OwHumA = (OwHumA<<8)|ResDat[1];
OwHumB = ResDat[2];
OwHumB = (OwHumB<<8)|ResDat[3];
}
}
unsigned char DHTC11_Convert(unsigned char Tem[6],unsigned char Hum[6])
{
unsigned char ResDat[5],CRC=1,len;
signed int intT, decT; //温度值的整数和小数部分
signed short int TemBuf;
signed long int HumBuf;//必须定义成长整型,不然计算数据范围不够
OneWire_Init(); //初始化 这里没有对返回做判断
OneWire_SendByte(0xcc);
OneWire_SendByte(0x10); //触发温湿度转化
Delay_x_ms(50);
OneWire_Init(); //初始化 这里没有对返回做判断
OneWire_SendByte(0xcc);
OneWire_SendByte(0xbd); //获取温湿度转化结果
ResDat[0] = OneWire_ReceiveByte();
ResDat[1] = OneWire_ReceiveByte();
ResDat[2] = OneWire_ReceiveByte();
ResDat[3] = OneWire_ReceiveByte();
ResDat[4] = OneWire_ReceiveByte();
CRC = CRC8MHT_Cal(ResDat,5);
if(CRC == 0)
{
TemBuf = (unsigned short int)ResDat[1]<<8|(ResDat[0]);
TemBuf = 400+TemBuf/25.6;//放大10倍方便运算
intT = TemBuf / 10;//取整数
decT = TemBuf % 10;//取小数
len = IntToString(Tem, intT); //整数部分转换为字符串
Tem[len++] = '.'; //添加小数点
Tem[len++] = decT + '0';//小数位转字符
Tem[len] = '\0';//添加字符串结束符
HumBuf = (unsigned short int)ResDat[3]<<8|(ResDat[2]);
HumBuf = (HumBuf-OwHumB)*600/(OwHumA-OwHumB)+300;//放大10倍方便运算
HumBuf = HumBuf + 25*(TemBuf-250)/100;
if(HumBuf >= 1000)HumBuf = 999;//控制湿度范围 0-100%
else if(HumBuf < 0)HumBuf = 0;
intT = HumBuf / 10;//取整数
decT = HumBuf % 10;//取小数
len = IntToString(Hum, intT); //整数部分转换为字符串
Hum[len++] = '.'; //添加小数点
Hum[len++] = decT + '0';//小数位转字符
Hum[len] = '\0';//添加字符串结束符
}
return CRC;
}
main.C
c
#include <STC89C5xRC.H>
#include <delay.h>
#include <uart.h>
#include <DHTC11.h>
void main()
{
unsigned char Tem[6];
unsigned char Hum[6];
uart_init();//9600
DHTC11_MInit_OW();
Delay_x_ms(1000);
while(1)
{
DHTC11_Convert(Tem,Hum);
UART_Send(Tem);UART_SendByte('C');
UART_SendByte('\n');
UART_Send(Hum);UART_Send("%RH");
UART_SendByte('\n');
UART_Send("-----------------");
Delay_x_ms(1000);
}
}
STM32
DHTC11 .C
c
#include "DHTC11.H"
#include "Delay.h"
void IO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PC端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 测试懒得加上拉电阻
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIO8
GPIO_SetBits(GPIOB,GPIO_Pin_8); //输出高
HDCSDA_Output();
HDCSDA_SET();
}
void DQ_Rst(void)
{
HDCSDA_Output();
delay_us(5); //5us 无需严格要求
HDCSDA_CLR();
delay_us(480);; //>480us 典型值 960us 规格书:tRSTL
HDCSDA_SET();
delay_us(8); //8us 无需严格要求
}
u8 DQ_Presence(void)
{
u8 pulse_time = 0;
HDCSDA_Input();
delay_us(5); //5us 无需严格要求
while(HDCGet_SDA() && pulse_time<100 ) //存在检测高电平 15~60us 模块响应高电平时间
{
pulse_time++;
delay_us(10);//>6us
}
if( pulse_time >=20 )
return 0x01;
else
pulse_time = 0;//应答正常
while((HDCGet_SDA()==0) && (pulse_time<240 )) ////存在检测低电平时间 60~240us tPDLOW
{
pulse_time++;
delay_us(5);//1~5us
}
if( pulse_time >=10 )//应答正常
{
return 0x01;
}
else
return 0x0;
}
u8 DQ_Read_Bit(void)
{
u8 dat;
HDCSDA_Output();
HDCSDA_CLR();
delay_us(5); //tINIT>1us 典型 5us <15us
HDCSDA_SET();
HDCSDA_Input();
delay_us(5);//tRC 典型 5us
if(HDCGet_SDA())//tSample
dat = 1;
else
dat = 0;
delay_us(70);//tDelay >60us 确保一帧数据传输完毕
return dat;
}
u8 DQ_Read_Byte(void)
{
u8 i, j, dat = 0;
for(i=0; i<8; i++)
{
j = DQ_Read_Bit();
dat = (dat) | (j<<i);
}
return dat;
}
void DQ_Write_Byte(uint8_t dat)
{
uint8_t i, testb;
HDCSDA_Output();
for( i=0; i<8; i++ )
{
testb = dat&0x01;
dat = dat>>1;
if(testb)//写1
{
HDCSDA_CLR();
delay_us(5);//>1us <15us
HDCSDA_SET();
delay_us(70);//>=60us
}
else//写 0
{
HDCSDA_CLR();
delay_us(70);//MY_DELAY_US(70);>60us
HDCSDA_SET();
delay_us(5);//典型 5us
}
}
}
static u16 OwHumA,OwHumB;
//初始化,获取校准数据A B值
void DHTC11_MInit_OW()
{
uint8_t i,crc;
u8 ResDat[13];
DQ_Rst();
DQ_Presence();
DQ_Write_Byte(0xcc);
DQ_Write_Byte(0xdd);
for(i=0;i<13;i++)
{
ResDat[i] = DQ_Read_Byte();
}
crc = CRC8MHT_Cal(ResDat,13);
if(crc == 0)
{
OwHumA = ResDat[0];
OwHumA = (OwHumA<<8)|ResDat[1];
OwHumB = ResDat[2];
OwHumB = (OwHumB<<8)|ResDat[3];
}
}
u8 CRC8MHT_Cal(u8 *serial, u8 length)
{
u8 result = 0x00;
u8 pDataBuf;
u8 i;
while(length--)
{
pDataBuf = *serial++;
for(i=0; i<8; i++)
{
if((result^(pDataBuf))&0x01)
{
result ^= 0x18;
result >>= 1;
result |= 0x80;
}
else
{
result >>= 1;
}
pDataBuf >>= 1;
}
}
return result;
}
u8 DHTC11_onewire(s16 *tem,u16 *hum)
{
u8 ResDat[5],crc=0;
s16 TemBuf;
s32 CapBuf;
DQ_Rst();
DQ_Presence();
DQ_Write_Byte(0xcc);
DQ_Write_Byte(0x10);
//可以不延时直接读取,但读取到的是上次转化的数据;
delay_ms(35);//2ms*15 35ms 改时间可以去处理其他任务回来读取;
DQ_Rst();
DQ_Presence();
DQ_Write_Byte(0xcc);
DQ_Write_Byte(0xbd);
ResDat[0] = DQ_Read_Byte();
ResDat[1] = DQ_Read_Byte();
ResDat[2] = DQ_Read_Byte();
ResDat[3] = DQ_Read_Byte();
ResDat[4] = DQ_Read_Byte();
crc = CRC8MHT_Cal(ResDat,5);
if(crc == 0)
{
TemBuf = (u16)ResDat[1]<<8|(ResDat[0]);
TemBuf = 400+TemBuf/25.6; //*10 结果*10倍 286即28.6℃;
*tem = TemBuf;
CapBuf = (u16)ResDat[3]<<8|(ResDat[2]);
CapBuf = (CapBuf-OwHumB)*600/(OwHumA-OwHumB)+300;//同样结果*10
//20℃为5个湿度点 即1℃为0.25个湿度点 0.1℃为0.025
CapBuf = CapBuf+ 25*(TemBuf-250)/100;
if(CapBuf>999)CapBuf = 999;
else if(CapBuf<0)CapBuf=0;
*hum = (u16)CapBuf;
}
return crc;
}
main.C
c
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "DHTC11.H"
/*********发送文本串**********/
void Usart1_SandTXString(char *s)
{
u8 i=0;
while(s[i]!=0)
{
USART1->DR=s[i];
i++;
while((USART1->SR&0X40)==0);//等待发送结束
}
}
int main(void)
{
s16 TemResult;
u16 HumResult;
float HumResultF,TemResultF;
char HumD[18] = {0};
char TempD[18] = {0};
delay_init(); //延时函数初始化
NVIC_Configuration();// 设置中断优先级分组
uart_init(9600); //串口初始化为9600
IO_Init();
DHTC11_MInit_OW();//获取校准数据
while(1)
{
DHTC11_onewire(&TemResult,&HumResult);
HumResultF = (float)HumResult/10;
TemResultF = (float)TemResult/10;
sprintf(HumD,"RH:%0.1F",HumResultF);
sprintf(TempD," T:%0.1F℃ ",TemResultF);
Usart1_SandTXString(HumD);
Usart1_SandTXString(TempD);
delay_ms(600);
}
}
六、实验现象
---------------------------------------------------DHTC11接线--------------------------------------------------
51 : SDA-P00
32 : SDA-PB8
开发板串口输出如下:

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