🎬 秋野酱:《个人主页》
🔥 个人专栏:《Java专栏》《Python专栏》
⛺️心若有所向往,何惧道阻且长
文章目录
- DHT11温湿度模块
- 原理图
- 官方参考电路
- 数据线通讯协议
- 单总线传送数据位定义
- 数据格式:
- 校验位数据定义
- 协议实现
DHT11温湿度模块
DHT11 数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有枀高的可靠性与卓越的长期稳定性。传感器包括一个电容式感湿元件和一个 NTC 测温元件,并与一个高性能 8 位单片机相连接。
原理图
● VCC: 电源。供电3v3-5v5
● GND: 接地
● DATA: 数据线
官方参考电路
微处理器与 DHT11 的连接典型应用电路如上图所示,DATA 上拉后与微处理器的 I/O 端口相连。
- 典型应用电路中建议连接线长度短于 5m 时用 4.7K 上拉电阻,大于 5m 时根据实际情况降低上拉电 阻的阻值。
- 使用 3.3V 电压供电时连接线尽量短,接线过长会导致传感器供电不足,造成测量偏差。
- 每次读出的温湿度数值是上一次测量的结果,欲获取实时数据,需连续读取 2 次,但不建议连续多次 读取传感器,每次读取传感器间隔大于 2 秒即可获得准确的数据。
- 电源部分如有波动,会影响到温度。如使用开关电源纹波过大,温度会出现跳动。
数据线通讯协议
DHT11 器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线
完成。设备(主机或从机)通过一个漏极开路或三态端口连至该数据线,以允许设备在不发送数据时能够
释放总线,而让其它设备使用总线;单总线通常要求外接一个约 4.7kΩ 的上拉电阻,这样,当总线闲置时,
其状态为高电平。由于它们是主从结极,只有主机呼叫从机时,从机才能应答,因此主机访问器件都必须
严格遵循单总线序列,如果出现序列混乱,器件将不响应主机。
单总线传送数据位定义
DATA 用于微处理器与 DHT11 之间的通讯和同步,采用单总线数据格式,一次传送 40 位数据,高位先 出。
数据格式:
8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据 + 8bit 校验位。
注:其中湿度小数部分为 0。
校验位数据定义
8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据”8bit 校验位等于 所得结果的末 8 位。
响应的数据时序
协议实现
u8 DHT11_read_data(u8* dat) {
u16 count;
u8 i, j;
// 主机: 总线拉低至少18ms
// 主机发起
DHT = 0;
delay_ms(19);
DHT = 1;
count = 0;
while(DHT == 1 && count < 25) {
count++;
delay1us();
}
if(count > 25) return 1;
count = 0;
while(DHT == 0 && count < 83) {
count++;
delay1us();
}
if(count > 83) return 2;
count = 0;
while(DHT == 1 && count < 87) {
count++;
delay1us();
}
if(count > 87) return 3;
// 开始接收数据
for(i = 0; i < 5; i++) {
for(j = 0; j < 8; j++) {
dat[i] <<= 1;
// 54us低 23-27高电平 表示0
// 54us低 68-74高电平 表示1
count = 0;
//等待变为高电平
while(DHT == 0 && count <= 54) {
count++;
delay1us();
}
if(count > 54) return 4;
count = 0;
// 等待变为低电平
while(DHT == 1 && count <= 74) {
count++;
delay1us();
}
if(count > 27) {
dat[i] |= 1;
}
}
}
if(dat[0] + dat[1] + dat[2] + dat[3] != dat[4]) {
return 5;
}
return 0;
}
实现业务需要参考逻辑分析仪,安装步骤完成数据的解析和分析,大概流程如下
- 主机发起起始信号。先拉低电平18ms,然后拉高。
DHT = 0;
delay_ms(19);
DHT = 1;
count = 0;
while(DHT == 1 && count < 25) {
count++;
delay1us();
}
if(count > 25) return 1;
握手响应。确定传感器是否发出响应信号,信号先低电平83us,然后高电平87us
count = 0;
while(DHT == 0 && count < 83) {
count++;
delay1us();
}
if(count > 83) return 2;
count = 0;
while(DHT == 1 && count < 87) {
count++;
delay1us();
}
if(count > 87) return 3;
握手响应。确定传感器是否发出响应信号,信号先低电平83us,然后高电平87us
count = 0;
while(DHT == 0 && count < 83) {
count++;
delay1us();
}
if(count > 83) return 2;
count = 0;
while(DHT == 1 && count < 87) {
count++;
delay1us();
}
if(count > 87) return 3;
数据接收阶段。进行高低电平的判断,将高低电平的变化转换为 数字的0和1。54us低 23-27高电平 表示0。54us低 68-74高电平 表示1。结果是先高位后低位的形式。
for(i = 0; i < 5; i++) {
for(j = 0; j < 8; j++) {
// 54us低 23-27高电平 表示0
// 54us低 68-74高电平 表示1
count = 0;
//等待变为高电平
while(DHT == 0 && count <= 54) {
count++;
delay1us();
}
count = 0;
// 等待变为低电平
while(DHT == 1 && count <= 74) {
count++;
delay1us();
}
// 先移位
dat[i] <<= 1;
// 后赋值
if(count > 27) {
dat[i] |= 1;
}
}
}
数据校验
if(dat[0] + dat[1] + dat[2] + dat[3] != dat[4]) {
return 5;
}
原始数据获得后,就是将数据转化为温湿度数据。
温度转化:
u8 DHT11_get_temperature(u8 *humidity, float *temperature) {
u8 dat[5];
u8 ret;
u8 retry = 0;
while((ret = DHT11_read_data(dat)) && retry < 10) {
retry++;
}
*humidity = dat[0];// 获得正数部分
*temperature = dat[2] & 0x7F;// 获得正数部分
*temperature += (dat[3] * 0.1);//加上小数部分
if(dat[2] & 0x80) {
//表示负数
*temperature *= -1;
}
return ret;
}