通用裸机-传感器

1 DHT11温湿度传感器#

img

MCU通过一条数据线与DH11连接,MCU通过这条线发命令给DH11,DH11再通过这条线把数据发送给MCU。只需要一根GPIO就OK了。

核心就是MCU发给DH11的命令格式和DH11返回的数据格式。

1.1 时序解析#

img

  1. MCU发送一个开始信号S,这个开始信号是一个低脉冲,然后再拉高。等待DHT11应答。

  2. DH11拉低,做出一个响应信号,再拉高,准备发送数据。

  3. 接着就是DH11返回的数据。

1.1.1 数据格式#

这些数据一共有40bit,高位先出。(8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和)

数据有40bit: 8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和

1.1.2 时序参数#

img

MCU必须先拉低至少18ms, 然后再拉高20-40us, DH11再拉低80us以响应,最后再拉高80us。

1.1.3 数据传输#

img

Bit0:1bit 50us开始后,DHT11拉低数据时间为30us以内。

img

Bit1: 1bit 50us开始后,DHT11拉低数据时间为超过70us。

1.1.4 代码实现#

img

img

使用GPG5引脚:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
static void dht11_data_cfg_as_output(void) {
GPGCON &= ~(3<<10);
GPGCON |= (1<<10);
}
static void dht11_data_cfg_as_input(void) {
GPGCON &= ~(3<<10);
}

static void dht11_data_set(int val) {
if (val)
GPGDAT |= (1<<5);
else
GPGDAT &= ~(1<<5);
}
static int dht11_data_get(void) {
if (GPGDAT & (1<<5))
return 1;
else
return 0;
}
//DHT11操作:
void dht11_init(void) {
dht11_data_cfg_as_output();
dht11_data_set(1);
mdelay(2000);
}

static void dht11_start(void) {
dht11_data_set(0);
mdelay(20);
dht11_data_cfg_as_input();
}

static int dht11_wait_ack(void) {
udelay(60);
return dht11_data_get();
}

static int dht11_recv_byte(void) {
int i;
int data = 0;

for (i = 0; i < 8; i++) {
if (dht11_wait_for_val(1, 1000)) {
printf("dht11 wait for high data err!\n\r");
return -1;
}
udelay(40);
data <<= 1;
if (dht11_data_get() == 1)
data |= 1;

if (dht11_wait_for_val(0, 1000)) {
printf("dht11 wait for low data err!\n\r");
return -1;
}
}
return data;
}

static int dht11_wait_for_val(int val, int timeout_us) {
while (timeout_us--) {
if (dht11_data_get() == val)
return 0; /* ok */
udelay(1);
}
return -1; /* err */
}

int dht11_read(int *hum, int *temp) {
unsigned char hum_m, hum_n;
unsigned char temp_m, temp_n;
unsigned char check;

dht11_start();

if (0 != dht11_wait_ack()) {
printf("dht11 not ack, err!\n\r");
return -1;
}

if (0 != dht11_wait_for_val(1, 1000)) { /* 等待ACK变为高电平, 超时时间是1000us */
printf("dht11 wait for ack high err!\n\r");
return -1;
}

if (0 != dht11_wait_for_val(0, 1000)) { /* 数据阶段: 等待低电平, 超时时间是1000us */
printf("dht11 wait for data low err!\n\r");
return -1;
}

hum_m = dht11_recv_byte();
hum_n = dht11_recv_byte();
temp_m = dht11_recv_byte();
temp_n = dht11_recv_byte();
check = dht11_recv_byte();

dht11_data_cfg_as_output();
dht11_data_set(1);

if (hum_m + hum_n + temp_m + temp_n == check) {
*hum = hum_m;
*temp = temp_m;
mdelay(2000); /* 读取周期是2S, 不能读太频繁 */
return 0;
} else {
printf("dht11 checksum err!\n\r");
return -1;
}
}

void dht11_test(void) {
int hum, temp;
dht11_init();
while (1) {
if (dht11_read(&hum, &temp) != 0) {
printf("\n\rdht11 read err!\n\r");
dht11_init();
} else {
printf("\n\rDHT11 : %d humidity, %d temperature\n\r", hum, temp);
}
}
}