Stabilní a bezchybný přenos telemetrických dat je absolutní prioritou každého měřícího systému. Během vývoje softwaru pro obsluhu komunikačního modulu HC-12, připojeného přes rozhraní UART, jsem stál před rozhodnutím, jaký mechanismus pro zpracování příchozích zpráv zvolit. Porovnával jsem metodu neustálého dotazování (Polling) s pokročilou architekturou řízenou událostmi (Event-Driven), která využívá datové fronty.

Ve svém řešení jsem nakonec použil architekturu řízenou událostmi, ačkoliv by se začátečníkům mohlo zdát logičtější a programátorsky snazší použít metodu Polling. Při aplikaci Pollingu se procesor v nekonečné smyčce neustále dotazuje komunikačního portu: „Máš nová data?“. Tento přístup je z inženýrského hlediska extrémně neefektivní. Spotřebovává značné množství elektrické energie a zcela zbytečně blokuje výpočetní výkon procesoru, který by mohl být využit pro zpracování dat ze senzorů. Navíc při vysoké rychlosti přenosu hrozí, že procesor nestihne data přečíst včas.

Z toho důvodu jsem na implementoval sofistikovaný systém událostních front (QueueHandle_t). Můj komunikační Task pro obsluhu HC-12 v podstatě „spí“ a nevyužívá absolutně žádný strojový čas procesoru. Ve chvíli, kdy modul zachytí rádiový signál, vygeneruje se hardwarové přerušení. Následně systém automaticky vytvoří událost (například UART_DATA), vloží ji do fronty a Task bleskově probudí k jejímu zpracování. Tento přístup mi poskytl naprostou garanci, že nepřijdu o jediný bajt dat ani při extrémním komunikačním vytížení. Kód s ukázkou použití fronty může pak vypadat například takto:

#include "driver/uart.h"
#include "freertos/queue.h"
#define HC12_UART_PORT UART_NUM_1
#define TXD_PIN (17)
#define RXD_PIN (18)
#define RX_BUF_SIZE (1024)
// Fronta pro předávání událostí UARTu - mozek naší komunikace
static QueueHandle_t uart_queue;
void init_hc12_communication() {
uart_config_t uart_config = {
.baud_rate = 9600,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
// Instalace ovladače: definujeme velikost bufferu a odkaz na frontu událostí
uart_driver_install(HC12_UART_PORT, RX_BUF_SIZE * 2, 0, 20, &uart_queue, 0);
uart_param_config(HC12_UART_PORT, &uart_config);
uart_set_pin(HC12_UART_PORT, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
}
void hc12_event_task(void *pvParameters) {
uart_event_t event;
uint8_t* dtmp = (uint8_t*) malloc(RX_BUF_SIZE);
for(;;) {
// Klíčový moment: Task čeká na událost z fronty (neplýtvá CPU výkonem)
if(xQueueReceive(uart_queue, (void *)&event, (TickType_t)portMAX_DELAY)) {
if(event.type == UART_DATA) {
// Čteme data z bufferu až ve chvíli, kdy víme, že tam skutečně jsou
int len = uart_read_bytes(HC12_UART_PORT, dtmp, event.size, portMAX_DELAY);
// Zde probíhá samotné zpracování přijatých telemetrických dat
printf("Přijato přes HC-12: %.*s\n", len, dtmp);
}
}
}
}
/* Poznámka pro zájemce o testování: Pro zprovoznění tohoto mechanismu
je nutné v hlavní funkci app_main() nejprve zavolat init_hc12_communication()
a následně vytvořit task pomocí xTaskCreate(hc12_event_task, ...).
Tuto implementaci si již vyzkoušejte sami v rámci svého hlavního souboru. :D
*/

Slovníček pojmů:

  • Polling (Dotazování): Způsob programování, kdy systém neustále plýtvá časem tím, že dokola aktivně kontroluje stav určitého hardwaru.
  • Event-Driven (Řízené událostmi): Architektura, kde program pasivně čeká, dokud mu sám hardware prostřednictvím přerušení neoznámí, že vyžaduje pozornost.
  • Fronta (Queue): Bezpečná softwarová struktura, přes kterou si různé části programu organizovaně předávají data, aby nedošlo k jejich ztrátě či přepsání.
  • UART: Sériový komunikační standard, přes který spolu čipy komunikují asynchronně pomocí dvou datových vodičů (TX pro odesílání, RX pro příjem).
  • Přetečení paměti (Overflow): Kritický chybový stav, který nastává, když příchozí data plní paměťový prostor (buffer) rychleji, než je procesor stíhá číst.

Kategorie