STM32/C51驱动 DHTC11 温湿度传感器

文章目录


一、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

开发板串口输出如下:

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

相关推荐
QiLinkOS1 小时前
【从实验室到商业战场:发明专利如何重塑科技与企业的共生生态】
大数据·c语言·数据结构·c++·人工智能·单片机·算法
周周记笔记1 小时前
【元器件专题】三极管-如果B极给一个方波信号,那么V0输出也可以设计为一个方波信号
单片机·嵌入式硬件
潜创微科技1 小时前
IT68353:DP 1.4 + HDMI 2.0 + USB-C 三合一转 HDMI 2.0 单芯片KVM切换方案
嵌入式硬件·音视频
HPT_Lt2 小时前
ZCC10012支持100V/1.2A 超低静态电流同步降压转换器 兼容LM5164
单片机·嵌入式硬件
Industio_触觉智能2 小时前
瑞芯微RK3576车载智能场景之ADAS+DMS+NVR
嵌入式硬件·dms·adas·nvr·rk3576·车载智能
2zcode3 小时前
基于STM32的多功能万年历电子闹钟设计与实现
stm32·单片机·嵌入式硬件
一抹晴空3 小时前
Keil MDK AC6 compiler编译报错,与AC5区别
c语言·arm开发·单片机
0南城逆流03 小时前
【STM32】RTT-Studio中HAL库开发教程十四:MSMART串口组件
stm32·单片机·嵌入式硬件
潜创微科技4 小时前
IT6520:USB‑C DP Alt Mode 到 MIPI 单芯片转换方案
嵌入式硬件·音视频