DHT11是一款温湿度传感器,也是使用一根总线来驱动,使用方法和ds18b20温度传感器非常相似。
- 供电电压 3.3~5.5V DC
- 测量范围 湿度5% ~ 95%RH, 温度-20℃ ~ 60℃
- 测量精度 湿度±5%RH, 温度±2℃
- 分 辨 率 湿度1%RH, 温度0.1℃
如下所示 引脚顺序为1、2、3、4,引脚功能如下:
1 | Vcc | 供电引脚 供电范围 3.5V to 5.5V |
---|---|---|
2 | Data | 输出温度和湿度值 |
3 | NC | 不使用,使用时悬空即可。 |
4 | Ground | 接地 |
典型应用电路如下: ??由于单总线在通信时的自由状态下电平较高,因此外部应在2脚上连接一个上拉电阻,因此当总线上没有数据传输时,数据引脚的电平将被外部上拉电阻强制设置为高电平。
通过单总线读取数据分为三个步骤:
- 主机发送请求指令
- 返回相应的指令
- 主机开始从机器上读取数据
1.请求指令: ?当主机发送请求指令时,需要将总线至少降低18ms,然后释放总线40us。 2.响应指令 ?当传感器检测到主机的请求指令时,它会向主机发送响应指令,告诉主机通信已经成功。传感器返回的响应指令是 54us低电平,80us高电平。
3.读取数据 ?当传感器发送响应指令时,将发送40bit的数据,8个bit对于一个数据,共有五个数据,包括当前的温度和湿度数据。前两个数据是湿度数据的整数和小数。接下来的两个数据是温度数据的整数和小数。最后一个数据是前四个数据的验证和验证。
数据的整体格式为8bit湿度数据 8bit湿度小数据 8bi温度整数据 8bit温度小数据 8bit校验和” 数据传输时,发送的数据是0还是1,代表高低电平的时间长短。
??? Bit ‘0’ : ~54uS 低电平 和 ~24uS 高电平
??? Bit ‘1’ : ~54uS 低电平 和 ~70uS 高电平
结束标志:
数据传输完成后,传感器将总线降低54us,然后释放总线,代表数据传输结束,传感器进入睡眠模式,等待下一个请求信号再次醒来。 一次读取数据的完整时序图如下: 首先MCU发送请求命令,然后等待传感器响应。传感器响应完成后,将发送40bit数据,然后发送结束标志。然后自动进入睡眠模式,等待MCU下次唤醒。 时序搞清楚后,下面就可以开始编写代码了。
??代码如下:
#include "dht11.h" #include "stm8s103f3p.h" #include "delay.h" //IO口操作 _Bool DHT11_DQ_OUT @PD_ODR:3; _Bool DHT11_DQ_IN @PD_IDR:3; //PD3 方向设置 void DHT11_IO_IN(void) {
PD_DDR&=~(1<<3); //输入 PD3 PD_CR1|=(1<<3); // } void DHT11_IO_OUT(void) {
PD_DDR|=(1<<3); //输出 PD3 PD_CR1|=(1<<3)
;
//
}
//发送起始信号 低电平18ms
void
DHT11_Rst
(
void
)
{
DHT11_IO_OUT
(
)
;
//设置为输出 DHT11_DQ_OUT
=
0
;
//拉低DQ
delay_ms
(
20
)
;
//拉低至少18ms DHT11_DQ_OUT
=
1
;
//置高DQ
delay_us
(
30
)
;
//主机拉高20--40us
}
//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
unsigned
char
DHT11_Check
(
void
)
{
//DHT输出80us低电平,作为应答信号
//DHT输出80us高电平,通知处理器准备接收数据
unsigned
char retry
=
0
;
DHT11_IO_IN
(
)
;
//SET INPUT
while
(
!DHT11_DQ_IN
&&retry
<
100
)
//DHT11会拉低40~80us
{
retry
++
;
delay_us
(
1
)
;
}
;
if
(retry
>=
100
)
return
1
;
else retry
=
0
;
while
(DHT11_DQ_IN
&&retry
<
100
)
//DHT11拉低后会再次拉高40~80us
{
retry
++
;
delay_us
(
1
)
;
}
;
if
(retry
>=
100
)
return
1
;
return
0
;
}
//从DHT11读取一个位
//返回值:1/0
unsigned
char
DHT11_Read_Bit
(
void
)
{
//数据为“0”格式:50us的低电平 + 26-28us的高电平
//数据为“1”格式:50us的低电平 + 70us的高电平
unsigned
char retry
=
0
;
while
(DHT11_DQ_IN
&& retry
<
100
)
//若为高电平说明上一位数据传输还未结束,等待变为低电平
{
retry
++
;
delay_us
(
1
)
;
} retry
=
0
;
while
(
!DHT11_DQ_IN
&& retry
<
100
)
//若为低电平,说明还未开始传输数据,等待变高电平
{
retry
++
;
delay_us
(
1
)
;
}
delay_us
(
40
)
;
//等待40us 0为 50us低电平 26--28us高电平 1为 50us低电平 70us高电平
if
(DHT11_DQ_IN
)
return
1
;
else
return
0
;
}
//从DHT11读取一个字节
//返回值:读到的数据
unsigned
char
DHT11_Read_Byte
(
void
)
{
unsigned
char i
,dat
; dat
=
0
;
for
(i
=
0
;i
<
8
;i
++
)
{
dat
<<=
1
; dat
|=
DHT11_Read_Bit
(
)
;
}
return dat
;
}
//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
unsigned
char
DHT11_Read_Data
(
unsigned
char
*temp
,
unsigned
char
*humi
)
{
unsigned
char buf
[
5
]
;
unsigned
char i
;
DHT11_Rst
(
)
;
if
(
DHT11_Check
(
)
==
0
)
//读取40位数据
{
for
(i
=
0
;i
<
5
;i
++
)
{
buf
[i
]
=
DHT11_Read_Byte
(
)
;
}
if
(buf
[
0
]
+buf
[
1
]
+buf
[
2
]
+buf
[
3
]
==buf
[
4
]
)
//湿度整数 湿度小数 温度整数 温度小数 校验和
{
*humi
=buf
[
0
]
;
*temp
=buf
[
2
]
;
}
}
else
return
1
;
return
0
;
}
//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在
unsigned
char
DHT11_Init
(
void
)
{
DHT11_IO_OUT
(
)
; DHT11_DQ_OUT
=
1
;
DHT11_Rst
(
)
;
return
DHT11_Check
(
)
;
}
读取温度时,直接在主函数中调用
#include "stm8s103f3p.h"
#include "delay.h"
#include "dht11.h"
//时钟配置 16Mhz
void CLK_Init(void)
{
CLK_SWR=0xe1; //HSI为主时钟源 16MHz CPU时钟频率
CLK_CKDIVR=0x00; //CPU时钟0分频,系统时钟0分频
}
//读取温度湿度数据
void read_tem_hum(void)
{
unsigned char temperature[2]={
0};
unsigned char humidity[2]={
0};
DHT11_Read_Data(temperature,humidity);
}
main()
{
_asm("sim"); //关全部中断
CLK_Init();
delay_init(16);
_asm("rim"); //开全部中断
while (1)
{
read_tem_hum();
}
}
通过单片机的IO口输出高低电平来模拟单总线的时序,这样就可以将温度和湿度的数据读出来了。