#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "stm32c0xx_hal.h"
#include <stdio.h>
// Définition des pins pour les LEDs et capteurs
#define LED1_PIN GPIO_PIN_5
#define LED2_PIN GPIO_PIN_6
#define LED_RED_PIN GPIO_PIN_7
#define LED_PORT GPIOA
#define SENSOR1_PIN GPIO_PIN_0 // A0
#define SENSOR2_PIN GPIO_PIN_1 // A1
#define POT_PIN GPIO_PIN_3 // Broche modifiée pour le potentiomètre (A3)
// Déclarations des variables ADC
ADC_HandleTypeDef hadc1;
UART_HandleTypeDef huart1; // Déclaration pour l'UART
// Déclaration des sémaphores et mutex
SemaphoreHandle_t uartMutex;
SemaphoreHandle_t emergencySemaphore;
// Déclaration des queues de messages pour les zones d'irrigation
QueueHandle_t zone1Queue;
QueueHandle_t zone2Queue;
// Variables pour l'humidité et le seuil
uint32_t humidityThreshold = 500; // Seuil d'humidité par défaut
uint32_t valveDuration = 10000; // Durée d'activation des vannes (en millisecondes)
// 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 envoyer des messages UART
void UART_Send(const char *message) {
if (xSemaphoreTake(uartMutex, portMAX_DELAY) == pdTRUE) {
printf("%s", message); // Envoi via UART
xSemaphoreGive(uartMutex);
}
}
// 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 les LEDs
GPIO_InitStruct.Pin = LED1_PIN | LED2_PIN | LED_RED_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 les capteurs d'humidité (A0, A1) et le potentiomètre (A3)
GPIO_InitStruct.Pin = SENSOR1_PIN | SENSOR2_PIN | POT_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
// Initialiser le bouton poussoir (A11)
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP; // Résistance pull-up interne
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// Initialisation de l'ADC
void MX_ADC_Init(void) {
__HAL_RCC_ADC_CLK_ENABLE(); // Activer l'horloge ADC
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);
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
sConfig.Rank = ADC_REGULAR_RANK_1;
// Configurer les capteurs (A0, A1, A3) - canal 3 pour A3
sConfig.Channel = ADC_CHANNEL_0; // Capteur 1 (A0)
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
sConfig.Channel = ADC_CHANNEL_1; // Capteur 2 (A1)
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
sConfig.Channel = ADC_CHANNEL_3; // Potentiomètre (A3)
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
// Initialisation de l'UART
void MX_USART1_UART_Init(void) {
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK) {
Error_Handler(); // Gestion d'erreur si l'initialisation échoue
}
}
// Redirection de printf() vers UART
int fputc(int ch, FILE *f) {
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
// Tâche pour surveiller l'humidité
void HumidityMonitoringTask(void *pvParameters) {
uint32_t sensor1Value = 0, sensor2Value = 0;
for (;;) {
// Démarrer la conversion ADC pour SENSOR1 et SENSOR2
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
sensor1Value = HAL_ADC_GetValue(&hadc1);
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
sensor2Value = HAL_ADC_GetValue(&hadc1);
// Ajout d'un message de débogage pour afficher les valeurs des capteurs
char msg[50];
snprintf(msg, sizeof(msg), "Sensor 1: %lu, Sensor 2: %lu\r\n", sensor1Value, sensor2Value);
UART_Send(msg); // Affiche les valeurs des capteurs
// Vérifier si l'humidité est en dessous du seuil
if (sensor1Value < humidityThreshold) {
zone1.moistureLevel = sensor1Value;
xQueueSendToBack(zone1Queue, &zone1, 0); // Envoi dans la queue pour activer l'irrigation
UART_Send("Humidity low in zone 1, activating irrigation.\r\n");
}
if (sensor2Value < humidityThreshold) {
zone2.moistureLevel = sensor2Value;
xQueueSendToBack(zone2Queue, &zone2, 0); // Envoi dans la queue pour activer l'irrigation
UART_Send("Humidity low in zone 2, activating irrigation.\r\n");
}
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;
char msg[50]; // Buffer pour le message à afficher
for (;;) {
// Lire la valeur du potentiomètre
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
potValue = HAL_ADC_GetValue(&hadc1);
// Mettre à jour le seuil d'humidité en fonction de la valeur du potentiomètre
humidityThreshold = potValue;
// Créer un message pour afficher la nouvelle valeur du seuil d'humidité
snprintf(msg, sizeof(msg), "Threshold updated to: %lu\r\n", humidityThreshold);
UART_Send(msg); // Afficher la nouvelle valeur du seuil
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) {
static uint8_t emergencyFlag = 0; // Variable pour suivre l'état d'urgence
for (;;) {
uint32_t buttonState = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11);
if (buttonState == GPIO_PIN_RESET && !emergencyFlag) {
emergencyFlag = 1;
UART_Send("Emergency stop activated. Closing all valves.\r\n");
HAL_GPIO_WritePin(LED_PORT, LED_RED_PIN, GPIO_PIN_SET); // Allumer LED rouge
// Fermer toutes les vannes
HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_PORT, LED2_PIN, GPIO_PIN_RESET);
} else if (buttonState == GPIO_PIN_SET && emergencyFlag) {
emergencyFlag = 0;
UART_Send("Emergency stop deactivated.\r\n");
HAL_GPIO_WritePin(LED_PORT, LED_RED_PIN, GPIO_PIN_RESET); // Éteindre LED rouge
}
vTaskDelay(pdMS_TO_TICKS(100)); // Vérifier toutes les 100ms
}
}
// Tâche pour activer les vannes
void ValveActivationTask(void *pvParameters) {
IrrigationZone zone;
for (;;) {
// Lire les messages de la queue et activer les vannes
if (xQueueReceive(zone1Queue, &zone, portMAX_DELAY)) {
HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_SET); // Allumer LED1 pour la zone 1
UART_Send("Valve 1 opened.\r\n");
vTaskDelay(pdMS_TO_TICKS(valveDuration)); // Attendre la durée de l'activation
HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_RESET); // Éteindre LED1
UART_Send("Valve 1 closed.\r\n");
}
if (xQueueReceive(zone2Queue, &zone, portMAX_DELAY)) {
HAL_GPIO_WritePin(LED_PORT, LED2_PIN, GPIO_PIN_SET); // Allumer LED2 pour la zone 2
UART_Send("Valve 2 opened.\r\n");
vTaskDelay(pdMS_TO_TICKS(valveDuration)); // Attendre la durée de l'activation
HAL_GPIO_WritePin(LED_PORT, LED2_PIN, GPIO_PIN_RESET); // Éteindre LED2
UART_Send("Valve 2 closed.\r\n");
}
}
}
int main(void) {
HAL_Init();
MX_GPIO_Init(); // Initialisation des GPIOs
MX_ADC_Init(); // Initialisation de l'ADC
MX_USART1_UART_Init(); // Initialisation de l'UART pour la communication série
// Créer les sémaphores et queues
uartMutex = xSemaphoreCreateMutex();
emergencySemaphore = xSemaphoreCreateBinary();
zone1Queue = xQueueCreate(10, sizeof(IrrigationZone));
zone2Queue = xQueueCreate(10, sizeof(IrrigationZone));
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);
xTaskCreate(ValveActivationTask, "Valve Activation", 256, NULL, 1, 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() {}