diff --git a/CMakeLists.txt b/CMakeLists.txt index 32478ae..d24a8c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,7 @@ target_link_libraries(display_engine PUBLIC hardware_spi hardware_dma hardware_timer + hardware_pio pico_multicore ) @@ -46,7 +47,7 @@ target_link_libraries(display_engine PUBLIC target_compile_definitions(display_engine PUBLIC # EN: Select the display controller backend: ST7789 or ILI9341. # RU: Выберите бэкенд контроллера дисплея: ST7789 или ILI9341. - DISPLAY_TYPE=DISPLAY_TYPE_ST7789 + DISPLAY_TYPE=DISPLAY_TYPE_ILI9341 # EN: Select the SPI peripheral connected to the display: spi0 or spi1. # RU: Выберите SPI-периферию, к которой подключён дисплей: spi0 или spi1. DISPLAY_SPI_PORT=spi1 @@ -58,6 +59,10 @@ target_compile_definitions(display_engine PUBLIC DISPLAY_PIN_BL=10 # BL / LED / LEDK ) -add_executable(my_app src/main.c) +add_executable(my_app + src/main.c + src/dht22.c +) target_link_libraries(my_app PRIVATE display_engine) -pico_add_extra_outputs(my_app) \ No newline at end of file +pico_generate_pio_header(my_app ${CMAKE_CURRENT_LIST_DIR}/src/dht22.pio) +pico_add_extra_outputs(my_app) diff --git a/src/dht22.c b/src/dht22.c new file mode 100644 index 0000000..149f05d --- /dev/null +++ b/src/dht22.c @@ -0,0 +1,90 @@ +#include "dht22.h" + +#include "dht22.pio.h" +#include "hardware/clocks.h" +#include "hardware/gpio.h" +#include "pico/stdlib.h" + +#define DHT22_START_LOW_US 1200u +#define DHT22_PREPARE_US 30u +#define DHT22_WORD_TIMEOUT_US 2000u + +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; + } + } + *out = pio_sm_get(pio, sm); + return true; +} + +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); + + pio_gpio_init(pio, pin); + + 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_init(pio, sm, dev->offset, &c); + pio_sm_set_enabled(pio, sm, false); + + gpio_init(pin); + gpio_pull_up(pin); + gpio_set_dir(pin, GPIO_IN); +} + +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; + } + + gpio_set_dir(dev->pin, GPIO_OUT); + 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); + + 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); + + 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; + } + data[i] = (uint8_t)word; + } + + pio_sm_set_enabled(dev->pio, dev->sm, false); + + 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]); + + *humidity_x10 = raw_h; + if (raw_t & 0x8000u) { + *temperature_x10 = -(int16_t)(raw_t & 0x7fffu); + } else { + *temperature_x10 = (int16_t)raw_t; + } + + return DHT22_OK; +} diff --git a/src/dht22.h b/src/dht22.h new file mode 100644 index 0000000..3089b29 --- /dev/null +++ b/src/dht22.h @@ -0,0 +1,24 @@ +#ifndef DHT22_H +#define DHT22_H + +#include "hardware/pio.h" +#include "pico/types.h" + +typedef enum { + DHT22_OK = 0, + DHT22_TIMEOUT, + DHT22_CHECKSUM_ERROR, + DHT22_BUS_STUCK +} dht22_status_t; + +typedef struct { + PIO pio; + uint sm; + uint pin; + uint offset; +} dht22_t; + +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); + +#endif diff --git a/src/dht22.pio b/src/dht22.pio new file mode 100644 index 0000000..73b1662 --- /dev/null +++ b/src/dht22.pio @@ -0,0 +1,19 @@ +.program dht22 + +; 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 + + 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 diff --git a/src/main.c b/src/main.c index 84e7d28..68e7393 100644 --- a/src/main.c +++ b/src/main.c @@ -2,46 +2,54 @@ #include "display/display.h" #include "display/render/context.h" #include "Font/font_data.h" +#include "dht22.h" #include +#define WIDTH 320 +#define HEIGHT 240 +#define DHT22_PIN 13 +#define DHT22_POLL_INTERVAL_US 2000000ULL + int main(void) { stdio_init_all(); display_config_t cfg = { - .width = 320, - .height = 240, + .width = WIDTH, + .height = HEIGHT, .buffer_count = 1, .mode = DISPLAY_MODE_SAFE }; display_init(&cfg); render_ctx_t rc; - uint32_t frame = 0; + wchar_t temp_text[24] = L"T: --.- C"; + wchar_t hum_text[24] = L"H: --.- %"; + int16_t dht_temp_x10 = 0; + uint16_t dht_hum_x10 = 0; + uint64_t next_dht_poll_us = time_us_64(); + + dht22_t dht; + dht22_init(&dht, pio0, 0, DHT22_PIN); while (1) { - uint16_t *buf = display_begin_paint_blocking(); - render_begin(&rc, buf, 320, 240); - switch ((frame / 30u) % 4u) { - case 0: - render_clear(&rc, RGB16(255, 0, 0)); - break; - case 1: - render_clear(&rc, RGB16(0, 255, 0)); - break; - case 2: - render_clear(&rc, RGB16(0, 0, 255)); - break; - default: - render_clear(&rc, RGB16(255, 255, 255)); - break; + uint64_t now_us = time_us_64(); + if (now_us >= next_dht_poll_us) { + if (dht22_read(&dht, &dht_temp_x10, &dht_hum_x10) == DHT22_OK) { + uint16_t t_abs_x10 = (dht_temp_x10 < 0) ? (uint16_t)(-dht_temp_x10) : (uint16_t)dht_temp_x10; + wchar_t sign = (dht_temp_x10 < 0) ? L'-' : L'+'; + (void)swprintf(temp_text, sizeof(temp_text) / sizeof(temp_text[0]), L"T: %lc%u.%u C", sign, (unsigned)(t_abs_x10 / 10u), (unsigned)(t_abs_x10 % 10u)); + (void)swprintf(hum_text, sizeof(hum_text) / sizeof(hum_text[0]), L"H: %u.%u %%", (unsigned)(dht_hum_x10 / 10u), (unsigned)(dht_hum_x10 % 10u)); + } + next_dht_poll_us = now_us + DHT22_POLL_INTERVAL_US; } - wchar_t frame_text[32]; - (void)swprintf(frame_text, sizeof(frame_text) / sizeof(frame_text[0]), L"frame: %lu", (unsigned long)frame); - draw_string(&rc, 100, 110, frame_text, RGB565(255, 255, 255)); + uint16_t *buf = display_begin_paint_blocking(); + render_begin(&rc, buf, WIDTH, HEIGHT); + render_clear(&rc, RGB16(0, 0, 0)); + draw_string(&rc, 16, 72, temp_text, RGB16(255, 255, 255)); + draw_string(&rc, 16, 96, hum_text, RGB16(255, 255, 255)); display_end_paint(); - frame++; - sleep_ms(1000/50); + sleep_ms(50); } }