#include <Adafruit_GFX.h> // Bibliothèque pour le graphisme Adafruit
#include <Adafruit_ILI9341.h> // Bibliothèque pour l'écran tactile Adafruit
#include <SPI.h> // Bibliothèque pour la communication SPI
#include <IRremote.h> // Bibliothèque pour la réception des signaux infrarouges
#include <math.h> // Bibliothèque pour les fonctions mathématiques
#include <freertos/FreeRTOS.h> // Bibliothèque FreeRTOS pour la gestion des tâches
#include <freertos/task.h> // Bibliothèque FreeRTOS pour la gestion des tâches
#define TFT_DC 2 // Broche de contrôle de l'écran TFT
#define TFT_CS 15 // Broche de sélection de l'écran TFT
#define TFT_WIDTH 320 // Largeur de l'écran TFT
#define TFT_HEIGHT 240 // Hauteur de l'écran TFT
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); // Instance de l'écran TFT
IRrecv irReceiver(22); // Instance du récepteur infrarouge
volatile bool signalRequested = false; // Indique si un signal est demandé
volatile int requestedSignalNumber = 0; // Numéro du signal demandé
volatile int speed = 0; // Vitesse de l'affichage du signal
TaskHandle_t affichageTaskHandle[4]; // Tableau des poignées de tâches d'affichage
float signalValues[TFT_WIDTH]; // Tableau pour stocker les valeurs du signal
struct TaskParameters {
int signalNumber;
int speed;
};
// Fonction pour calculer les valeurs du signal
void calculateSignalValues(float (*calculateSignal)(int)) {
for (int x = 0; x < TFT_WIDTH; x++) {
signalValues[x] = calculateSignal(x);
}
}
void eraseSegment(uint16_t drawColor, int segment, int numSegments, float verticalOffset) {
int segmentWidth = TFT_WIDTH / numSegments;
int startX = segment * segmentWidth;
int endX = (segment + 1) * segmentWidth;
// Efface le segment précédent
if (segment > 0) {
startX--; // Décale légèrement le début pour éviter les discontinuités
}
for (int x = startX; x < endX; x++) {
float y = signalValues[x] + verticalOffset;
float y_next = signalValues[x + 1] + verticalOffset;
tft.drawLine(x, round(y), x + 1, round(y_next), ILI9341_BLACK);
delay(7);
}
}
void drawSegment(uint16_t drawColor, int segment, int numSegments, float verticalOffset, int speed) {
int segmentWidth = TFT_WIDTH / numSegments;
int startX = segment * segmentWidth;
int endX = (segment + 1) * segmentWidth;
if (segment > 0) {
startX--; // Décale légèrement le début pour éviter les discontinuités
}
for (int x = startX; x < endX; x++) {
float y = signalValues[x] + verticalOffset;
float y_next = signalValues[x + 1] + verticalOffset;
tft.drawLine(x, round(y), x + 1, round(y_next), drawColor);
//delay(10 + speed);
}
}
void drawSignalSegments(uint16_t drawColor, int numSegments) {
// Vérifie que numSegments est supérieur à zéro pour éviter la division par zéro
if (numSegments > 0) {
float maxAmplitude = 0;
float minAmplitude = 0;
for (int x = 0; x < TFT_WIDTH; x++) {
maxAmplitude = max(maxAmplitude, signalValues[x]);
minAmplitude = min(minAmplitude, signalValues[x]);
}
// Calcul de l'offset vertical pour centrer la courbe
float averageAmplitude = (maxAmplitude - minAmplitude) / 2;
float verticalOffset = TFT_HEIGHT / 2 - averageAmplitude;
// Effacer l'écran avant de dessiner les segments
// tft.fillScreen(ILI9341_BLACK);
for (int segment = 1; segment < numSegments; segment++) {
eraseSegment(drawColor, segment, numSegments, verticalOffset);
drawSegment(drawColor, segment, numSegments, verticalOffset, speed);
delay(10);
}
} else {
// Gérer le cas où numSegments est égal à zéro (peut-être afficher un message d'erreur ou une action appropriée)
Serial.println("Erreur : numSegments est égal à zéro !");
}
}
// Tâche d'affichage
// Tâche d'affichage
void affichageTask(void *pvParameters) {
TaskParameters *parameters = (TaskParameters *)pvParameters;
int signalNumber = parameters->signalNumber;
int speed = parameters->speed;
int numSegments = 0; // Initialize numSegments
// Sélection du nombre de segments en fonction du signal
switch (signalNumber) {
case 48:
numSegments = 16;
calculateSignalValues(calculateCombinedSignal1);
break;
case 24:
numSegments = 14;
calculateSignalValues(calculateCombinedSignal2);
break;
case 122:
numSegments = 8;
calculateSignalValues(calculateCombinedSignal3);
break;
case 16:
numSegments = 6;
calculateSignalValues(calculateCombinedSignal4);
break;
default:
break;
}
for (int segment = 0; segment < numSegments; segment++) {
drawSignalSegments(ILI9341_GREEN, numSegments);}
}
// Initialisation
void setup() {
Serial.begin(9600); // Initialisation de la communication série
tft.begin(); // Initialisation de l'écran TFT
tft.setRotation(3); // Rotation de l'écran TFT
Serial.print("Signals!");
tft.fillScreen(ILI9341_BLACK); // Remplissage de l'écran en noir
tft.setTextColor(ILI9341_WHITE); // Couleur du texte en blanc
tft.setTextSize(2); // Taille du texte
irReceiver.enableIRIn(); // Activation du récepteur infrarouge
}
// Fonction principale
void loop() {
if (irReceiver.decode()) {
unsigned long irValue = irReceiver.decodedIRData.command;
Serial.println(irValue); // Imprimer la valeur IR reçue
irReceiver.resume(); // Réactivation de la réception des signaux infrarouges
// Mettre à jour la vitesse lors de la détection des boutons "+" et "-"
switch (irValue) {
case 152:
if (speed < 10) {
speed++;
}
break;
case 2:
if (speed > -3) {
speed--;
}
break;
default:
// Arrêter la tâche d'affichage précédente si elle existe
stopDisplayTask(requestedSignalNumber);
speed = 0;
// Enregistrer le nouveau signal demandé et indiquer qu'un signal est demandé
requestedSignalNumber = irValue;
signalRequested = true;
break;
}
}
if (signalRequested) {
signalRequested = false;
if (affichageTaskHandle[requestedSignalNumber - 1] == NULL) {
// Démarrer une nouvelle tâche d'affichage
TaskParameters taskParams;
taskParams.signalNumber = requestedSignalNumber;
taskParams.speed = speed;
xTaskCreate(affichageTask, "AffichageTask", 4096, &taskParams, 1, &affichageTaskHandle[requestedSignalNumber - 1]);
} else {
// Si la tâche est déjà en cours, la suspendre
vTaskSuspend(affichageTaskHandle[requestedSignalNumber - 1]);
// Puis, démarrer une nouvelle tâche d'affichage
TaskParameters taskParams;
taskParams.signalNumber = requestedSignalNumber;
taskParams.speed = speed;
xTaskCreate(affichageTask, "AffichageTask", 4096, &taskParams, 1, &affichageTaskHandle[requestedSignalNumber - 1]);
}
}
// Ajouter un petit délai pour permettre aux tâches de s'exécuter
}
// Fonction pour arrêter la tâche d'affichage
void stopDisplayTask(int signalNumber) {
if (affichageTaskHandle[signalNumber - 1] != NULL) {
vTaskSuspend(affichageTaskHandle[signalNumber - 1]);
affichageTaskHandle[signalNumber - 1] = NULL;
}
}
float calculateCombinedSignal1(int x) {
float s = 0;
int offset = 1;
while (offset <= 1000) {
float onde_P = -(0.9) * exp(-pow((x - 17 - offset), 2) / 144);
float onde_Q = (2.2) * exp(-pow((x - 41 - offset), 2) / 5);
float onde_R = -(8) * exp(-pow((x - 50 - offset), 2) / 47);
float onde_S = (4) * exp(-pow((x - 57 - offset), 2) / 9);
float onde_T = -(1.8) * exp(-pow((x - 90 - offset), 2) / 170);
s += (onde_P + onde_Q + onde_R + onde_S + onde_T);
offset += 145;
}
return s * 9 + 70;
}
float calculateCombinedSignal2(int x) {
float s = 0;
for (int offset = 1; offset <= 1000; offset += 35) {
float y1 = -9 * exp(-pow((x - 10 - offset), 2) / 49);
float y3 = 14 * exp(-pow((x - 19 - offset), 2) / 25);
s += (y1 + y3);
}
return s * 0.6 * 7 + 40;
}
float calculateCombinedSignal3(int x) {
float s = 0;
for (int offset = 1; offset <= 1000; offset += 110) {
float y1 = 2.6 * exp(-pow((x - 10 - offset), 2) / 2500);
s += (y1);
}
return s * 0.6 * 8;
}
float calculateCombinedSignal4(int x) {
float s = 0;
for (int n = 1; n <= 400; n += 18) {
float y3 = -(15) * exp(-pow((x - (5 + n)), 2) / 16);
float y4 = 1.8 * exp(-pow((x - (8 + n)), 2) / 25);
s += y3 + y4;
}
return s * 5 + 70;
}