#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "stm32c0xx_hal.h"
#include <stdio.h>
// Définition des pins pour les LEDs
#define LED1_PIN GPIO_PIN_5
#define LED2_PIN GPIO_PIN_6
#define LED_RED_PIN GPIO_PIN_7
#define LED_PORT GPIOA
// Définition des broches pour les capteurs d'humidité
#define SENSOR1_PIN GPIO_PIN_0 // A0
#define SENSOR2_PIN GPIO_PIN_1 // A1
#define POT_PIN GPIO_PIN_2 // A2
// Déclarations des variables ADC
ADC_HandleTypeDef hadc1;
// Déclaration des sémaphores et mutex
SemaphoreHandle_t uartMutex;
SemaphoreHandle_t emergencySemaphore;
// Déclaration des files de messages pour les zones d'irrigation
QueueHandle_t zone1Queue;
QueueHandle_t zone2Queue;
// Variables pour les seuils d'humidité et les zones d'irrigation
uint32_t humidityThreshold = 14; // Seuil d'humidité par défaut
// Structure pour les données d'irrigation
typedef struct {
uint32_t zoneId;
uint32_t moistureLevel;
} IrrigationZone;
IrrigationZone zone1 = {1, 0};
IrrigationZone zone2 = {2, 0};
// Fonction pour simuler l'envoi de messages UART
void UART_Send(const char *message) {
printf("%s", message); // Utilisation de printf pour envoyer via UART (Wokwi fait la redirection automatiquement)
}
// Fonction d'initialisation des GPIOs pour les LEDs et capteurs
void MX_GPIO_Init(void) {
__HAL_RCC_GPIOA_CLK_ENABLE(); // Activer l'horloge GPIOA
GPIO_InitTypeDef GPIO_InitStruct = {0};
// Initialiser LED1 (Pin 5)
GPIO_InitStruct.Pin = LED1_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
// Initialiser LED2 (Pin 6)
GPIO_InitStruct.Pin = LED2_PIN;
HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
// Initialiser LED Rouge (Pin 7)
GPIO_InitStruct.Pin = LED_RED_PIN;
HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
// Initialiser capteur d'humidité (A0, A1)
GPIO_InitStruct.Pin = SENSOR1_PIN | SENSOR2_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
}
// Fonction pour initialiser les ADC
void MX_ADC_Init(void) {
__HAL_RCC_ADC_CLK_ENABLE(); // Activer l'horloge ADC
// Initialiser l'ADC1
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
HAL_ADC_Init(&hadc1);
// Configurer les canaux ADC pour SENSOR1 (A0) et SENSOR2 (A1)
ADC_ChannelConfTypeDef sConfig = {0};
// Configurer le canal pour le capteur 1 (A0)
sConfig.Channel = ADC_CHANNEL_0; // A0 sur ADC1
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
// Configurer le canal pour le capteur 2 (A1)
sConfig.Channel = ADC_CHANNEL_1; // A1 sur ADC1
sConfig.Rank = ADC_REGULAR_RANK_2;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
// Configurer le canal pour le potentiomètre (A2)
sConfig.Channel = ADC_CHANNEL_2; // A2 sur ADC1
sConfig.Rank = ADC_REGULAR_RANK_3;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
// Tâche pour surveiller les capteurs d'humidité
void HumidityMonitoringTask(void *pvParameters) {
uint32_t sensor1Value = 0, sensor2Value = 0;
for (;;) {
// Lire les valeurs des capteurs d'humidité
HAL_ADC_Start(&hadc1); // Démarrer la conversion pour les capteurs
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
// Lire les valeurs des capteurs
sensor1Value = HAL_ADC_GetValue(&hadc1); // Valeur du capteur 1 (A0)
sensor2Value = HAL_ADC_GetValue(&hadc1); // Valeur du capteur 2 (A1)
// Vérifier si les capteurs sont en dessous du seuil d'humidité
if (sensor1Value < humidityThreshold) {
UART_Send("Humidity low in zone 1, activating irrigation.\r\n");
zone1.moistureLevel = sensor1Value;
xQueueSendToBack(zone1Queue, (void *)&zone1, 0);
}
if (sensor2Value < humidityThreshold) {
UART_Send("Humidity low in zone 2, activating irrigation.\r\n");
zone2.moistureLevel = sensor2Value;
xQueueSendToBack(zone2Queue, (void *)&zone2, 0);
}
vTaskDelay(pdMS_TO_TICKS(5000)); // Attendre 5 secondes avant de lire à nouveau
}
}
// Tâche pour ajuster le seuil d'humidité via potentiomètre
void ThresholdAdjustmentTask(void *pvParameters) {
uint32_t potValue = 0;
for (;;) {
// Lire la valeur du potentiomètre
HAL_ADC_Start(&hadc1); // Démarrer la conversion pour le potentiomètre
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
potValue = HAL_ADC_GetValue(&hadc1); // Lire la valeur du potentiomètre
// Mettre à jour le seuil d'humidité en fonction de la valeur du potentiomètre
humidityThreshold = potValue;
vTaskDelay(pdMS_TO_TICKS(1000)); // Attendre 1 seconde avant de lire à nouveau
}
}
// Tâche pour gérer l'arrêt d'urgence
void EmergencyStopTask(void *pvParameters) {
for (;;) {
// Vérifier si le bouton poussoir est pressé
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET) {
UART_Send("Emergency stop activated. Closing all valves.\r\n");
// Activer la LED rouge pour l'état d'urgence
HAL_GPIO_WritePin(LED_PORT, LED_RED_PIN, GPIO_PIN_SET);
// Fermer toutes les vannes (désactiver les LEDs)
HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_PORT, LED2_PIN, GPIO_PIN_RESET);
// Attendre que l'état d'urgence soit réinitialisé
xSemaphoreGive(emergencySemaphore); // Libérer le sémaphore pour autoriser la reprise
vTaskDelay(pdMS_TO_TICKS(500)); // Attente pour traiter l'état d'urgence
}
vTaskDelay(pdMS_TO_TICKS(100)); // Vérifier l'état du bouton toutes les 100ms
}
}
int main(void) {
HAL_Init();
MX_GPIO_Init(); // Initialisation des GPIOs
MX_ADC_Init(); // Initialisation de l'ADC
// Créer les sémaphores et les queues
uartMutex = xSemaphoreCreateMutex();
emergencySemaphore = xSemaphoreCreateBinary();
zone1Queue = xQueueCreate(10, sizeof(IrrigationZone)); // Créer la queue pour la zone 1
zone2Queue = xQueueCreate(10, sizeof(IrrigationZone)); // Créer la queue pour la zone 2
if (uartMutex != NULL && emergencySemaphore != NULL && zone1Queue != NULL && zone2Queue != NULL) {
// Créer les tâches
xTaskCreate(HumidityMonitoringTask, "Humidity Monitoring", 256, NULL, 1, NULL);
xTaskCreate(ThresholdAdjustmentTask, "Threshold Adjustment", 256, NULL, 1, NULL);
xTaskCreate(EmergencyStopTask, "Emergency Stop", 256, NULL, 2, NULL);
// Démarrer le scheduler FreeRTOS
vTaskStartScheduler();
}
// Si le système arrive ici, cela signifie que la mémoire est insuffisante
while (1) {
}
}
void loop() {
// Nothing here, tasks run independently
}