mirror of
https://github.com/stasenso/Thermometr_pico.git
synced 2026-06-26 21:42:42 +03:00
Add Russian educational comments for DHT22 module
This commit is contained in:
+84
-58
@@ -1,90 +1,116 @@
|
||||
#include "dht22.h"
|
||||
#include "dht22.h" // публичный интерфейс драйвера
|
||||
|
||||
#include "dht22.pio.h"
|
||||
#include "hardware/clocks.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "dht22.pio.h" // сгенерированная PIO-программа
|
||||
#include "hardware/clocks.h" // частота системного такта
|
||||
#include "hardware/gpio.h" // управление GPIO
|
||||
#include "pico/stdlib.h" // время и задержки
|
||||
|
||||
#define DHT22_START_LOW_US 1200u
|
||||
#define DHT22_PREPARE_US 30u
|
||||
#define DHT22_WORD_TIMEOUT_US 2000u
|
||||
#define DHT22_START_LOW_US 1200u // стартовый импульс хоста
|
||||
#define DHT22_PREPARE_US 30u // пауза перед захватом
|
||||
#define DHT22_WORD_TIMEOUT_US 2000u // таймаут на один байт
|
||||
|
||||
/*
|
||||
* Ждёт появления одного слова в RX FIFO state machine.
|
||||
* На вход принимает:
|
||||
* pio - блок PIO, из которого читается FIFO;
|
||||
* sm - номер state machine;
|
||||
* out - указатель, куда будет записано прочитанное слово;
|
||||
* timeout_us - максимальное время ожидания в микросекундах.
|
||||
* Возвращает true, если слово получено, иначе false по таймауту.
|
||||
*/
|
||||
static bool wait_for_rx_word(PIO pio, uint sm, uint32_t *out, uint32_t timeout_us) {
|
||||
uint64_t deadline = time_us_64() + timeout_us;
|
||||
while (pio_sm_is_rx_fifo_empty(pio, sm)) {
|
||||
if (time_us_64() > deadline) {
|
||||
return false;
|
||||
uint64_t deadline = time_us_64() + timeout_us; // вычисляем момент истечения таймаута
|
||||
while (pio_sm_is_rx_fifo_empty(pio, sm)) { // ждём появления слова в FIFO
|
||||
if (time_us_64() > deadline) { // проверяем превышение таймаута
|
||||
return false; // данных не дождались
|
||||
}
|
||||
}
|
||||
*out = pio_sm_get(pio, sm);
|
||||
return true;
|
||||
*out = pio_sm_get(pio, sm); // забираем слово из FIFO
|
||||
return true; // чтение прошло успешно
|
||||
}
|
||||
|
||||
/*
|
||||
* Инициализирует драйвер DHT22.
|
||||
* На вход принимает:
|
||||
* dev - структуру, куда сохраняется состояние драйвера;
|
||||
* pio - блок PIO, который будет выполнять программу чтения;
|
||||
* sm - номер state machine внутри выбранного PIO;
|
||||
* pin - GPIO, к которому подключена линия данных датчика.
|
||||
* Ничего не возвращает.
|
||||
*/
|
||||
void dht22_init(dht22_t *dev, PIO pio, uint sm, uint pin) {
|
||||
dev->pio = pio;
|
||||
dev->sm = sm;
|
||||
dev->pin = pin;
|
||||
dev->offset = pio_add_program(pio, &dht22_program);
|
||||
dev->pio = pio; // сохраняем выбранный блок PIO
|
||||
dev->sm = sm; // сохраняем номер state machine
|
||||
dev->pin = pin; // сохраняем номер GPIO
|
||||
dev->offset = pio_add_program(pio, &dht22_program); // загружаем программу в PIO
|
||||
|
||||
pio_gpio_init(pio, pin);
|
||||
pio_gpio_init(pio, pin); // подключаем GPIO к PIO
|
||||
|
||||
pio_sm_config c = dht22_program_get_default_config(dev->offset);
|
||||
sm_config_set_in_pins(&c, pin);
|
||||
sm_config_set_clkdiv(&c, (float)clock_get_hz(clk_sys) / 1000000.0f);
|
||||
sm_config_set_in_shift(&c, false, true, 8);
|
||||
pio_sm_config c = dht22_program_get_default_config(dev->offset); // берём базовую конфигурацию
|
||||
sm_config_set_in_pins(&c, pin); // читаем биты с нужного пина
|
||||
sm_config_set_clkdiv(&c, (float)clock_get_hz(clk_sys) / 1000000.0f); // делаем шаг PIO равным 1 мкс
|
||||
sm_config_set_in_shift(&c, false, true, 8); // сдвигаем вход и автопушим по 8 бит
|
||||
|
||||
pio_sm_init(pio, sm, dev->offset, &c);
|
||||
pio_sm_set_enabled(pio, sm, false);
|
||||
pio_sm_init(pio, sm, dev->offset, &c); // записываем конфигурацию в SM
|
||||
pio_sm_set_enabled(pio, sm, false); // пока не запускаем автомат
|
||||
|
||||
gpio_init(pin);
|
||||
gpio_pull_up(pin);
|
||||
gpio_set_dir(pin, GPIO_IN);
|
||||
gpio_init(pin); // инициализируем GPIO со стороны CPU
|
||||
gpio_pull_up(pin); // включаем подтяжку вверх
|
||||
gpio_set_dir(pin, GPIO_IN); // отпускаем линию в режим входа
|
||||
}
|
||||
|
||||
/*
|
||||
* Выполняет одно чтение DHT22.
|
||||
* На вход принимает:
|
||||
* dev - ранее инициализированный дескриптор датчика;
|
||||
* temperature_x10 - указатель, куда будет записана температура в десятых долях градуса;
|
||||
* humidity_x10 - указатель, куда будет записана влажность в десятых долях процента.
|
||||
* Возвращает код результата: успех, таймаут, ошибка контрольной суммы или залипшая шина.
|
||||
*/
|
||||
dht22_status_t dht22_read(dht22_t *dev, int16_t *temperature_x10, uint16_t *humidity_x10) {
|
||||
if (!gpio_get(dev->pin)) {
|
||||
return DHT22_BUS_STUCK;
|
||||
if (!gpio_get(dev->pin)) { // линия должна быть в единице в покое
|
||||
return DHT22_BUS_STUCK; // иначе шина залипла
|
||||
}
|
||||
|
||||
gpio_set_dir(dev->pin, GPIO_OUT);
|
||||
gpio_put(dev->pin, 0);
|
||||
sleep_us(DHT22_START_LOW_US);
|
||||
gpio_set_dir(dev->pin, GPIO_OUT); // временно берём линию под управление CPU
|
||||
gpio_put(dev->pin, 0); // тянем линию вниз для старта обмена
|
||||
sleep_us(DHT22_START_LOW_US); // держим стартовый импульс
|
||||
|
||||
gpio_set_dir(dev->pin, GPIO_IN);
|
||||
gpio_pull_up(dev->pin);
|
||||
sleep_us(DHT22_PREPARE_US);
|
||||
gpio_set_dir(dev->pin, GPIO_IN); // отпускаем линию датчику
|
||||
gpio_pull_up(dev->pin); // оставляем подтяжку вверх
|
||||
sleep_us(DHT22_PREPARE_US); // даём датчику начать ответ
|
||||
|
||||
pio_sm_set_enabled(dev->pio, dev->sm, false);
|
||||
pio_sm_clear_fifos(dev->pio, dev->sm);
|
||||
pio_sm_restart(dev->pio, dev->sm);
|
||||
pio_sm_set_enabled(dev->pio, dev->sm, true);
|
||||
pio_sm_set_enabled(dev->pio, dev->sm, false); // останавливаем SM перед новым чтением
|
||||
pio_sm_clear_fifos(dev->pio, dev->sm); // чистим FIFO от старых данных
|
||||
pio_sm_restart(dev->pio, dev->sm); // сбрасываем состояние SM
|
||||
pio_sm_set_enabled(dev->pio, dev->sm, true); // запускаем захват битов
|
||||
|
||||
uint8_t data[5] = {0};
|
||||
for (uint i = 0; i < 5; ++i) {
|
||||
uint32_t word = 0;
|
||||
if (!wait_for_rx_word(dev->pio, dev->sm, &word, DHT22_WORD_TIMEOUT_US)) {
|
||||
pio_sm_set_enabled(dev->pio, dev->sm, false);
|
||||
return DHT22_TIMEOUT;
|
||||
uint8_t data[5] = {0}; // буфер пяти байт DHT22
|
||||
for (uint i = 0; i < 5; ++i) { // читаем все 40 бит по байтам
|
||||
uint32_t word = 0; // временное слово из FIFO
|
||||
if (!wait_for_rx_word(dev->pio, dev->sm, &word, DHT22_WORD_TIMEOUT_US)) { // ждём очередной байт
|
||||
pio_sm_set_enabled(dev->pio, dev->sm, false); // останавливаем SM при ошибке
|
||||
return DHT22_TIMEOUT; // выходим по таймауту
|
||||
}
|
||||
data[i] = (uint8_t)word;
|
||||
data[i] = (uint8_t)word; // сохраняем младший байт
|
||||
}
|
||||
|
||||
pio_sm_set_enabled(dev->pio, dev->sm, false);
|
||||
pio_sm_set_enabled(dev->pio, dev->sm, false); // останавливаем SM после чтения
|
||||
|
||||
uint8_t checksum = (uint8_t)(data[0] + data[1] + data[2] + data[3]);
|
||||
if (checksum != data[4]) {
|
||||
return DHT22_CHECKSUM_ERROR;
|
||||
uint8_t checksum = (uint8_t)(data[0] + data[1] + data[2] + data[3]); // считаем контрольную сумму
|
||||
if (checksum != data[4]) { // сравниваем с байтом датчика
|
||||
return DHT22_CHECKSUM_ERROR; // данные повреждены
|
||||
}
|
||||
|
||||
uint16_t raw_h = (uint16_t)((data[0] << 8) | data[1]);
|
||||
uint16_t raw_t = (uint16_t)((data[2] << 8) | data[3]);
|
||||
uint16_t raw_h = (uint16_t)((data[0] << 8) | data[1]); // собираем влажность из двух байт
|
||||
uint16_t raw_t = (uint16_t)((data[2] << 8) | data[3]); // собираем температуру из двух байт
|
||||
|
||||
*humidity_x10 = raw_h;
|
||||
if (raw_t & 0x8000u) {
|
||||
*temperature_x10 = -(int16_t)(raw_t & 0x7fffu);
|
||||
*humidity_x10 = raw_h; // DHT22 уже даёт влажность в десятых долях
|
||||
if (raw_t & 0x8000u) { // старший бит хранит знак температуры
|
||||
*temperature_x10 = -(int16_t)(raw_t & 0x7fffu); // отрицательная температура
|
||||
} else {
|
||||
*temperature_x10 = (int16_t)raw_t;
|
||||
*temperature_x10 = (int16_t)raw_t; // положительная температура
|
||||
}
|
||||
|
||||
return DHT22_OK;
|
||||
return DHT22_OK; // всё прочитано корректно
|
||||
}
|
||||
|
||||
+36
-19
@@ -1,24 +1,41 @@
|
||||
#ifndef DHT22_H
|
||||
#define DHT22_H
|
||||
#ifndef DHT22_H // защита от двойного включения
|
||||
#define DHT22_H // открываем тело заголовка
|
||||
|
||||
#include "hardware/pio.h"
|
||||
#include "pico/types.h"
|
||||
#include "hardware/pio.h" // типы и API PIO
|
||||
#include "pico/types.h" // базовые типы Pico SDK
|
||||
|
||||
typedef enum {
|
||||
DHT22_OK = 0,
|
||||
DHT22_TIMEOUT,
|
||||
DHT22_CHECKSUM_ERROR,
|
||||
DHT22_BUS_STUCK
|
||||
} dht22_status_t;
|
||||
typedef enum { // коды результата чтения
|
||||
DHT22_OK = 0, // чтение успешно
|
||||
DHT22_TIMEOUT, // датчик не ответил вовремя
|
||||
DHT22_CHECKSUM_ERROR, // контрольная сумма не сошлась
|
||||
DHT22_BUS_STUCK // линия данных зажата в нуле
|
||||
} dht22_status_t; // тип статуса DHT22
|
||||
|
||||
typedef struct {
|
||||
PIO pio;
|
||||
uint sm;
|
||||
uint pin;
|
||||
uint offset;
|
||||
} dht22_t;
|
||||
typedef struct { // состояние драйвера датчика
|
||||
PIO pio; // используемый блок PIO
|
||||
uint sm; // номер state machine
|
||||
uint pin; // GPIO линии данных
|
||||
uint offset; // смещение программы в PIO
|
||||
} dht22_t; // дескриптор DHT22
|
||||
|
||||
dht22_status_t dht22_read(dht22_t *dev, int16_t *temperature_x10, uint16_t *humidity_x10);
|
||||
void dht22_init(dht22_t *dev, PIO pio, uint sm, uint pin);
|
||||
/*
|
||||
* Инициализирует драйвер DHT22.
|
||||
* На вход принимает:
|
||||
* dev - структуру, куда сохраняется состояние драйвера;
|
||||
* pio - блок PIO, который будет выполнять программу чтения;
|
||||
* sm - номер state machine внутри выбранного PIO;
|
||||
* pin - GPIO, к которому подключена линия данных датчика.
|
||||
* Ничего не возвращает.
|
||||
*/
|
||||
void dht22_init(dht22_t *dev, PIO pio, uint sm, uint pin); // инициализирует PIO и GPIO
|
||||
/*
|
||||
* Выполняет одно чтение DHT22.
|
||||
* На вход принимает:
|
||||
* dev - ранее инициализированный дескриптор датчика;
|
||||
* temperature_x10 - указатель, куда будет записана температура в десятых долях градуса;
|
||||
* humidity_x10 - указатель, куда будет записана влажность в десятых долях процента.
|
||||
* Возвращает код результата: успех, таймаут, ошибка контрольной суммы или залипшая шина.
|
||||
*/
|
||||
dht22_status_t dht22_read(dht22_t *dev, int16_t *temperature_x10, uint16_t *humidity_x10); // читает температуру и влажность x10
|
||||
|
||||
#endif
|
||||
#endif // DHT22_H
|
||||
|
||||
+17
-17
@@ -1,19 +1,19 @@
|
||||
.program dht22
|
||||
.program dht22 // имя PIO-программы
|
||||
|
||||
; Capture 40 bits from DHT22 by sampling each high pulse around 35us after rising edge.
|
||||
.wrap_target
|
||||
wait 0 pin 0
|
||||
wait 1 pin 0
|
||||
; Захватываем 40 бит, измеряя уровень примерно через 35 мкс после фронта.
|
||||
.wrap_target // начало зацикленного участка
|
||||
wait 0 pin 0 // ждём спад импульса
|
||||
wait 1 pin 0 // ждём новый подъём импульса
|
||||
|
||||
set y, 4
|
||||
byte_loop:
|
||||
set x, 7
|
||||
bit_loop:
|
||||
wait 0 pin 0
|
||||
wait 1 pin 0
|
||||
nop [31]
|
||||
nop [2]
|
||||
in pins, 1
|
||||
jmp x-- bit_loop
|
||||
jmp y-- byte_loop
|
||||
.wrap
|
||||
set y, 4 // нужно принять 5 байт: 4..0
|
||||
byte_loop: // внешний цикл по байтам
|
||||
set x, 7 // в каждом байте 8 бит: 7..0
|
||||
bit_loop: // внутренний цикл по битам
|
||||
wait 0 pin 0 // ждём низкий уровень перед битом
|
||||
wait 1 pin 0 // ждём начало высокого импульса
|
||||
nop [31] // выдерживаем основную часть задержки
|
||||
nop [2] // добираем задержку до точки выборки
|
||||
in pins, 1 // считываем один бит с входа
|
||||
jmp x-- bit_loop // повторяем, пока байт не собран
|
||||
jmp y-- byte_loop // повторяем, пока не собраны 5 байт
|
||||
.wrap // конец зацикленного участка
|
||||
|
||||
Reference in New Issue
Block a user