在DHT11的手册中,DHT11仅有3根线,连接示意图如下,包括一根电源,一根地线,一根信号线

由于这里不存在什么协议,因此信号线可以任意选择一个GPIO接口即可实现信号传输,因此我选用了Mikro Bus Connector右下角的三个排母接口,其中这里的SDA对应了PTB4

我基于开发的工程是peripheral_hr

定义基本参数
/* DHT11 sensor on PTB4 */ #define DHT11_NODE DT_NODELABEL(gpiob) #define DHT11_PIN 4 static const struct device *dht11_dev; static struct k_mutex dht11_mutex;
设置us级的延时用于DHT11温湿度获取的延时
/* Simple delay using nop loops - avoids k_busy_wait overhead */
static inline void delay_us(uint32_t us)
{
for (volatile uint32_t i = 0; i < us * 8; i++) {
__asm__ volatile("nop");
}
}DHT11初始化和读取函数
static int dht11_init(void)
{
dht11_dev = DEVICE_DT_GET(DHT11_NODE);
if (!device_is_ready(dht11_dev)) {
printk("DHT11: GPIO device not ready\n");
return -ENODEV;
}
k_mutex_init(&dht11_mutex);
int ret = gpio_pin_configure(dht11_dev, DHT11_PIN, GPIO_OUTPUT);
if (ret < 0) {
printk("DHT11: config failed (err %d)\n", ret);
return ret;
}
gpio_pin_set(dht11_dev, DHT11_PIN, 1);
k_sleep(K_MSEC(1000));
return 0;
}
static int dht11_read(int16_t *temp_x10, int16_t *hum_x10)
{
uint8_t data[5] = {0};
int ret = 0;
unsigned int irq_key = 0;
uint32_t w;
k_mutex_lock(&dht11_mutex, K_FOREVER);
/*
* Start: pull low 20ms, then release high 30us
*/
gpio_pin_configure(dht11_dev, DHT11_PIN, GPIO_OUTPUT);
gpio_pin_set(dht11_dev, DHT11_PIN, 0);
k_sleep(K_MSEC(20));
gpio_pin_set(dht11_dev, DHT11_PIN, 1);
delay_us(30);
/*
* Switch to input. DHT11 will respond within ~40us.
*/
gpio_pin_configure(dht11_dev, DHT11_PIN, GPIO_INPUT);
irq_key = irq_lock();
/*
* Wait for DHT11 response: low ~80us, then high ~80us.
* Then DHT11 pulls low to start first data bit (50us low).
* We eat that first 50us low here so bit loop is clean.
*/
w = 0;
while (gpio_pin_get(dht11_dev, DHT11_PIN) == 1) {
if (++w > 500) { printk("DHT11: no resp\n"); ret = -ETIMEDOUT; goto out; }
delay_us(1);
}
w = 0;
while (gpio_pin_get(dht11_dev, DHT11_PIN) == 0) {
if (++w > 200) { ret = -ETIMEDOUT; goto out; }
delay_us(1);
}
w = 0;
while (gpio_pin_get(dht11_dev, DHT11_PIN) == 1) {
if (++w > 200) { ret = -ETIMEDOUT; goto out; }
delay_us(1);
}
/*
* Read 40 bits. Bit format:
* - 50us low
* - ~27us high = 0
* - ~70us high = 1
*
* After DHT11's 80us high response, the line falls for ~50us.
* That fall is the start of bit 0 byte 0. We already consumed
* the 80us high above, and the next edge we see will be the
* 50us low of bit 0. So our first loop action (wait for low end)
* correctly syncs to bit 0.
*/
for (int b = 0; b < 5; b++) {
uint8_t val = 0;
for (int i = 0; i < 8; i++) {
/* Wait for 50us low to end */
w = 0;
while (gpio_pin_get(dht11_dev, DHT11_PIN) == 0) {
if (++w > 200) { ret = -ETIMEDOUT; goto out; }
delay_us(1);
}
/* Wait 35us from rising edge. At this point:
* - bit 0: 27us pulse is over, pin is low
* - bit 1: 70us pulse still active, pin is high
*/
delay_us(35);
val <<= 1;
if (gpio_pin_get(dht11_dev, DHT11_PIN) == 1) {
val |= 1;
/* Consume remainder of 70us high */
w = 0;
while (gpio_pin_get(dht11_dev, DHT11_PIN) == 1) {
if (++w > 200) break;
delay_us(1);
}
}
}
data[b] = val;
}
irq_unlock(irq_key);
irq_key = 0;
/*
* Parse DHT11 data
*/
printk("DHT11 raw: %02x %02x %02x %02x %02x\n",
data[0], data[1], data[2], data[3], data[4]);
*hum_x10 = (int16_t)data[0] * 10 + (int16_t)data[1];
*temp_x10 = (int16_t)data[2] * 10 + (int16_t)data[3];
ret = 0;
out:
if (irq_key) {
irq_unlock(irq_key);
}
gpio_pin_configure(dht11_dev, DHT11_PIN, GPIO_OUTPUT);
gpio_pin_set(dht11_dev, DHT11_PIN, 1);
k_mutex_unlock(&dht11_mutex);
return ret;
}完整main.c如下,其余部分主要是蓝牙,对温湿度获取没什么太大影响
/* main.c - Application main entry point */
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys/printk.h>
#include <zephyr/irq.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/services/bas.h>
#include <zephyr/bluetooth/services/hrs.h>
/* DHT11 sensor on PTB4 */
#define DHT11_NODE DT_NODELABEL(gpiob)
#define DHT11_PIN 4
static const struct device *dht11_dev;
static struct k_mutex dht11_mutex;
/* Simple delay using nop loops - avoids k_busy_wait overhead */
static inline void delay_us(uint32_t us)
{
for (volatile uint32_t i = 0; i < us * 8; i++) {
__asm__ volatile("nop");
}
}
static int dht11_init(void)
{
dht11_dev = DEVICE_DT_GET(DHT11_NODE);
if (!device_is_ready(dht11_dev)) {
printk("DHT11: GPIO device not ready\n");
return -ENODEV;
}
k_mutex_init(&dht11_mutex);
int ret = gpio_pin_configure(dht11_dev, DHT11_PIN, GPIO_OUTPUT);
if (ret < 0) {
printk("DHT11: config failed (err %d)\n", ret);
return ret;
}
gpio_pin_set(dht11_dev, DHT11_PIN, 1);
k_sleep(K_MSEC(1000));
return 0;
}
static int dht11_read(int16_t *temp_x10, int16_t *hum_x10)
{
uint8_t data[5] = {0};
int ret = 0;
unsigned int irq_key = 0;
uint32_t w;
k_mutex_lock(&dht11_mutex, K_FOREVER);
/*
* Start: pull low 20ms, then release high 30us
*/
gpio_pin_configure(dht11_dev, DHT11_PIN, GPIO_OUTPUT);
gpio_pin_set(dht11_dev, DHT11_PIN, 0);
k_sleep(K_MSEC(20));
gpio_pin_set(dht11_dev, DHT11_PIN, 1);
delay_us(30);
/*
* Switch to input. DHT11 will respond within ~40us.
*/
gpio_pin_configure(dht11_dev, DHT11_PIN, GPIO_INPUT);
irq_key = irq_lock();
/*
* Wait for DHT11 response: low ~80us, then high ~80us.
* Then DHT11 pulls low to start first data bit (50us low).
* We eat that first 50us low here so bit loop is clean.
*/
w = 0;
while (gpio_pin_get(dht11_dev, DHT11_PIN) == 1) {
if (++w > 500) { printk("DHT11: no resp\n"); ret = -ETIMEDOUT; goto out; }
delay_us(1);
}
w = 0;
while (gpio_pin_get(dht11_dev, DHT11_PIN) == 0) {
if (++w > 200) { ret = -ETIMEDOUT; goto out; }
delay_us(1);
}
w = 0;
while (gpio_pin_get(dht11_dev, DHT11_PIN) == 1) {
if (++w > 200) { ret = -ETIMEDOUT; goto out; }
delay_us(1);
}
/*
* Read 40 bits. Bit format:
* - 50us low
* - ~27us high = 0
* - ~70us high = 1
*
* After DHT11's 80us high response, the line falls for ~50us.
* That fall is the start of bit 0 byte 0. We already consumed
* the 80us high above, and the next edge we see will be the
* 50us low of bit 0. So our first loop action (wait for low end)
* correctly syncs to bit 0.
*/
for (int b = 0; b < 5; b++) {
uint8_t val = 0;
for (int i = 0; i < 8; i++) {
/* Wait for 50us low to end */
w = 0;
while (gpio_pin_get(dht11_dev, DHT11_PIN) == 0) {
if (++w > 200) { ret = -ETIMEDOUT; goto out; }
delay_us(1);
}
/* Wait 35us from rising edge. At this point:
* - bit 0: 27us pulse is over, pin is low
* - bit 1: 70us pulse still active, pin is high
*/
delay_us(35);
val <<= 1;
if (gpio_pin_get(dht11_dev, DHT11_PIN) == 1) {
val |= 1;
/* Consume remainder of 70us high */
w = 0;
while (gpio_pin_get(dht11_dev, DHT11_PIN) == 1) {
if (++w > 200) break;
delay_us(1);
}
}
}
data[b] = val;
}
irq_unlock(irq_key);
irq_key = 0;
/*
* Parse DHT11 data
*/
printk("DHT11 raw: %02x %02x %02x %02x %02x\n",
data[0], data[1], data[2], data[3], data[4]);
*hum_x10 = (int16_t)data[0] * 10 + (int16_t)data[1];
*temp_x10 = (int16_t)data[2] * 10 + (int16_t)data[3];
ret = 0;
out:
if (irq_key) {
irq_unlock(irq_key);
}
gpio_pin_configure(dht11_dev, DHT11_PIN, GPIO_OUTPUT);
gpio_pin_set(dht11_dev, DHT11_PIN, 1);
k_mutex_unlock(&dht11_mutex);
return ret;
}
static bool hrf_ntf_enabled;
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA_BYTES(BT_DATA_UUID16_ALL,
BT_UUID_16_ENCODE(BT_UUID_HRS_VAL),
BT_UUID_16_ENCODE(BT_UUID_BAS_VAL),
BT_UUID_16_ENCODE(BT_UUID_DIS_VAL)),
};
static const struct bt_data sd[] = {
BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
};
enum {
STATE_CONNECTED,
STATE_DISCONNECTED,
STATE_BITS,
};
static ATOMIC_DEFINE(state, STATE_BITS);
static void connected(struct bt_conn *conn, uint8_t err)
{
if (err) {
printk("Connection failed, err 0x%02x %s\n", err, bt_hci_err_to_str(err));
} else {
printk("Connected\n");
(void)atomic_set_bit(state, STATE_CONNECTED);
}
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
printk("Disconnected, reason 0x%02x %s\n", reason, bt_hci_err_to_str(reason));
(void)atomic_set_bit(state, STATE_DISCONNECTED);
}
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
};
static void hrs_ntf_changed(bool enabled)
{
hrf_ntf_enabled = enabled;
printk("HRS notification status changed: %s\n", enabled ? "enabled" : "disabled");
}
static struct bt_hrs_cb hrs_cb = {
.ntf_changed = hrs_ntf_changed,
};
static void auth_cancel(struct bt_conn *conn)
{
char addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
printk("Pairing cancelled: %s\n", addr);
}
static struct bt_conn_auth_cb auth_cb_display = {
.cancel = auth_cancel,
};
static void bas_notify(void)
{
uint8_t battery_level = bt_bas_get_battery_level();
battery_level--;
if (!battery_level) {
battery_level = 100U;
}
bt_bas_set_battery_level(battery_level);
}
static void hrs_notify(void)
{
static uint8_t heartrate = 90U;
heartrate++;
if (heartrate == 160U) {
heartrate = 90U;
}
if (hrf_ntf_enabled) {
bt_hrs_notify(heartrate);
}
}
int main(void)
{
int err;
printk("Initializing DHT11 sensor on PTB4...\n");
err = dht11_init();
if (err) {
printk("DHT11: Init failed (err %d)\n", err);
} else {
printk("DHT11: Init OK\n");
int16_t temperature_x10;
int16_t humidity_x10;
int read_ret = dht11_read(&temperature_x10, &humidity_x10);
if (read_ret == 0) {
printk("Temperature: %d.%d C, Humidity: %d.%d %%RH\n",
temperature_x10 / 10, temperature_x10 % 10,
humidity_x10 / 10, humidity_x10 % 10);
} else {
printk("DHT11: first read failed (err %d)\n", read_ret);
}
}
while (1) {
k_sleep(K_SECONDS(2));
if (dht11_dev != NULL) {
int16_t temperature_x10;
int16_t humidity_x10;
if (dht11_read(&temperature_x10, &humidity_x10) == 0) {
printk("Temperature: %d.%d C, Humidity: %d.%d %%RH\n",
temperature_x10 / 10, temperature_x10 % 10,
humidity_x10 / 10, humidity_x10 % 10);
}
}
}
return 0;
}串口输出如下,输出包括原始数据和解析得到的温湿度数据

用嘴巴对着温湿度计哈气,可以看到温湿度均升高了

完整工程代码如下
我要赚赏金
