#include "pms5003.h" #include "hardware/uart.h" #include "pico/stdlib.h" #include #include #include #include /** Lib for Plantower PMS5003 Particulate Matter (PM) Sensor Detects PM1, PM2.5, PM10 particulates Sourcces: - https://shop.pimoroni.com/products/pms5003-particulate-matter-sensor-with-cable - https://github.com/pimoroni/pms5003-python/blob/main/pms5003/__init__.py - https://github.com/vogelrh/pms5003c/tree/master - https://github.com/raspberrypi/pico-examples/blob/master/uart/hello_uart/hello_uart.c */ #define MAX_READINGS 100 static bool read = false; static uint16_t reading_i = 0; static pms5003_reading readings[MAX_READINGS]; static uint8_t rx_buf[32] = {0}; static uint8_t rx_i = 0; static pms5003_reading extract_pm_values_from_rx_buf() { uint8_t pm1_low = rx_buf[9]; uint8_t pm1_high = rx_buf[10]; uint16_t pm1 = ((uint16_t)pm1_high << 8) | pm1_low; uint8_t pm2_5_low = rx_buf[11]; uint8_t pm2_5_high = rx_buf[12]; uint16_t pm2_5 = ((uint16_t)pm2_5_high << 8) | pm2_5_low; uint8_t pm10_low = rx_buf[13]; uint8_t pm10_high = rx_buf[14]; uint16_t pm10 = ((uint16_t)pm10_high << 8) | pm10_low; pms5003_reading reading = { .pm1 = (float)pm1, .pm2_5 = (float)pm2_5, .pm10 = (float)pm10}; return reading; } static void on_uart_rx() { // TODO: make the uart1 dynamic while (read && reading_i < MAX_READINGS && uart_is_readable(uart1)) { uint8_t ch = uart_getc(uart1); // start of a message if (ch == 0x42) { printf("pms5003 reading received\n"); rx_i = 0; } rx_buf[rx_i] = ch; rx_i++; // end of message if (rx_i == 31) { readings[reading_i] = extract_pm_values_from_rx_buf(); reading_i++; } // guard if (rx_i > 32) { rx_i = 0; } } } static unsigned char pms5003_command_prefix[] = {0x42, 0x4D}; void pms5003_init(pms5003_config *new_config, uart_inst_t *uart, uint8_t tx_pin, uint8_t rx_pin, uint8_t enable_pin, uint8_t reset_pin) { gpio_set_function(tx_pin, UART_FUNCSEL_NUM(uart, tx_pin)); gpio_set_function(rx_pin, UART_FUNCSEL_NUM(uart, rx_pin)); uart_init(uart, 9600); uart_set_format(uart, 8, 1, UART_PARITY_NONE); irq_set_exclusive_handler(UART1_IRQ, on_uart_rx); irq_set_enabled(UART1_IRQ, true); uart_set_irq_enables(uart, true, false); // high level or suspending is normal working status, while low level is // sleeping mode. gpio_init(enable_pin); gpio_set_dir(enable_pin, GPIO_OUT); gpio_put(enable_pin, 0); // TODO: add hourly reset? // low resets // gpio_init(reset_pin); // gpio_set_dir(reset_pin, GPIO_OUT); // gpio_set_pulls(enable_pin, true, false); // pull up // gpio_put(enable_pin, 1); new_config->uart = uart; new_config->enable_pin = enable_pin; new_config->reset_pin = reset_pin; } static pms5003_reading compute_avarage_reading() { extern uint16_t reading_i; extern pms5003_reading readings[MAX_READINGS]; float pm1_sum = 0; float pm2_5_sum = 0; float pm10_sum = 0; for (int i = 0; i < reading_i; i++) { pm1_sum += readings[i].pm1; pm2_5_sum += readings[i].pm2_5; pm10_sum += readings[i].pm10; } pms5003_reading average_reading = {.pm1 = pm1_sum / reading_i, .pm2_5 = pm2_5_sum / reading_i, .pm10 = pm10_sum / reading_i}; return average_reading; } void pms5003_warmup(pms5003_config *config) { gpio_put(config->enable_pin, 1); } void pms5003_start_reading(pms5003_config *config) { reading_i = 0; read = true; } pms5003_reading pms5003_finish_reading(pms5003_config *config) { printf("readings_i: %d\n", reading_i); read = false; gpio_put(config->enable_pin, 0); pms5003_reading average_reading = compute_avarage_reading(); reading_i = 0; return average_reading; }