5. 3.4 Build : producer-consumer pattern
Pattern complet — capteur → queue → affichage avec mutex :
// src/main.c
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_log.h"
typedef struct {
float temperature;
float humidity;
uint32_t timestamp_ms;
} sensor_data_t;
static QueueHandle_t xQueueSensorData;
static SemaphoreHandle_t xMutexDisplay;
// Producteur — simule la lecture DHT22 toutes les 2s
static void task_producer(void *pv) {
TickType_t xLastWake = xTaskGetTickCount();
sensor_data_t data;
while (1) {
data.temperature = 22.5f + (rand() % 10) * 0.1f; // simulé
data.humidity = 45.0f + (rand() % 20) * 0.1f;
data.timestamp_ms = xTaskGetTickCount();
if (xQueueSend(xQueueSensorData, &data, pdMS_TO_TICKS(10)) != pdTRUE) {
ESP_LOGW("PRODUCER", "Queue full — data dropped");
}
vTaskDelayUntil(&xLastWake, pdMS_TO_TICKS(2000));
}
vTaskDelete(NULL);
}
// Consommateur — attend les données, protège l'affichage avec mutex
static void task_consumer(void *pv) {
sensor_data_t data;
while (1) {
if (xQueueReceive(xQueueSensorData, &data, pdMS_TO_TICKS(5000)) == pdTRUE) {
if (xSemaphoreTake(xMutexDisplay, pdMS_TO_TICKS(50)) == pdTRUE) {
ESP_LOGI("DISPLAY", "Temp: %.1f C Hum: %.1f %% @%" PRIu32 "ms",
data.temperature, data.humidity, data.timestamp_ms);
xSemaphoreGive(xMutexDisplay);
}
} else {
ESP_LOGW("CONSUMER", "No data in 5s — is the sensor task alive?");
}
}
vTaskDelete(NULL);
}
void app_main(void) {
xQueueSensorData = xQueueCreate(5, sizeof(sensor_data_t));
xMutexDisplay = xSemaphoreCreateMutex();
xTaskCreate(task_producer, "producer", 4096, NULL, 4, NULL);
xTaskCreate(task_consumer, "consumer", 4096, NULL, 2, NULL);
}
Exercice : Ajouter une tâche task_logger (priorité 1) qui conserve un buffer circulaire de 20 entrées sensor_data_t et affiche l'historique sur xSemaphoreGive(xSemPrintHistory) (sémaphore binaire déclenché par un bouton GPIO).
Soumettez l'implémentation avec une capture série montrant l'historique affiché au moins une fois.