Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <SPI.h>
- #include <SD.h>
- #include <avr/wdt.h>
- // Constantes système
- #define PIN_CAPTEUR A2
- #define PIN_CS_SD 4
- #define DUREE_ACQUISITION_S 7
- #define BAUD_RATE 115200
- // Constantes pour l'algorithme de compression
- #define MARQUEUR_VALEUR_COMPLETE 0xFF
- #define MARQUEUR_DELTA_TEMPS_STD 0x7F
- #define MARQUEUR_DELTA_TEMPS_VAR 0x7E
- #define DELTA_MAX 126
- #define DELTA_MIN -126
- #define INTERVALLE_TEMPS_STD 1 // Intervalle standard (ms)
- // Constantes de conversion et calibration
- /**
- * Valeur ADC représentant 0g (position neutre du capteur)
- * Cette valeur doit être calibrée pour chaque capteur ADXL335
- */
- #define ZERO_G_VALUE 512
- /**
- * Facteur de conversion ADC vers mg (1g = 1000mg)
- * Déterminé par la sensibilité du capteur (~300mV/g) et la résolution ADC
- */
- #define SCALE_FACTOR 102
- // Optimisation mémoire critique
- /**
- * Réduit à ~1KB pour respecter contraintes RAM
- * Allocation calculée: 2048 - 917 - 100 (marge) = 1031
- * Valeur choisie: 1024 (pour garantir ~1% marge)
- */
- #define BUFFER_SIZE 1024
- // Buffer d'acquisition statique réduit
- uint8_t buffer[BUFFER_SIZE];
- uint16_t indexBuffer = 0;
- uint16_t nbEchantillons = 0; // Réduit à uint16_t pour économiser 2 octets
- // Références pour la compression différentielle
- int16_t dernierAccel = 0;
- uint16_t dernierTemps = 0; // Réduit à uint16_t (restriction à 65.5s max d'acquisition)
- // Variables de contrôle du timing
- volatile bool acquisitionTerminee = false;
- volatile uint8_t compteurSecondes = 0;
- uint16_t tempsDebutAcquisition = 0; // Réduit à uint16_t
- // Interface carte SD
- File fichierSD;
- // Routine d'interruption du Watchdog
- ISR(WDT_vect) {
- if (++compteurSecondes >= DUREE_ACQUISITION_S) {
- acquisitionTerminee = true;
- wdt_disable();
- }
- }
- /**
- * Lecture ADC optimisée avec accès direct aux registres
- *
- * Cette fonction contourne la couche d'abstraction Arduino (analogRead) pour
- * accéder directement aux registres du convertisseur analogique-numérique.
- * Le prescaler ADC est maintenu à 128 pour privilégier la précision sur la vitesse,
- * conformément aux spécifications du projet.
- *
- * @param pin Numéro du canal ADC (0-7, correspondant aux broches A0-A7)
- * @return Valeur de conversion ADC 10 bits (0-1023)
- */
- inline uint16_t lectureADC(uint8_t pin) {
- ADMUX = (ADMUX & 0xF0) | (pin & 0x07);
- ADCSRA |= (1 << ADSC);
- while (ADCSRA & (1 << ADSC));
- return ADC;
- }
- /**
- * Configuration du Watchdog comme base de temps précise pour l'acquisition
- *
- * Cette fonction configure le timer Watchdog en mode interruption (sans reset)
- * pour générer des interruptions périodiques d'environ 1 seconde, utilisées
- * comme base de temps pour contrôler la durée totale d'acquisition.
- *
- * La précision temporelle est d'environ ±10%, ce qui est suffisant pour
- * respecter les spécifications du projet (7 secondes ±10%).
- */
- void configurerWatchdog() {
- cli(); // Désactiver les interruptions
- MCUSR &= ~(1 << WDRF);
- WDTCSR |= (1 << WDCE) | (1 << WDE);
- WDTCSR = (1 << WDIE) | (1 << WDP2) | (1 << WDP1); // ~1s
- sei(); // Réactiver les interruptions
- }
- /**
- * Stocke une valeur d'accélération complète avec son horodatage
- *
- * Cette fonction est utilisée pour l'initialisation et lorsque les deltas
- * ne peuvent pas être encodés efficacement (variations brusques ou intervalles
- * temporels importants). Utilise 5 octets de stockage.
- *
- * @param valeur Valeur d'accélération en mg (millièmes de g)
- * @param temps Temps relatif en ms depuis le début de l'acquisition
- */
- void stockerValeurComplete(int16_t valeur, uint16_t temps) {
- // Vérifier l'espace disponible (5 octets)
- if (indexBuffer + 5 > BUFFER_SIZE) {
- Serial.println(F("Buffer plein"));
- acquisitionTerminee = true;
- return;
- }
- // Format: [MARQUEUR][VAL_MSB][VAL_LSB][TEMPS_MSB][TEMPS_LSB]
- buffer[indexBuffer++] = MARQUEUR_VALEUR_COMPLETE;
- buffer[indexBuffer++] = (valeur >> 8) & 0xFF;
- buffer[indexBuffer++] = valeur & 0xFF;
- buffer[indexBuffer++] = (temps >> 8) & 0xFF;
- buffer[indexBuffer++] = temps & 0xFF;
- // Mettre à jour les références
- dernierAccel = valeur;
- dernierTemps = temps;
- nbEchantillons++;
- }
- /**
- * Stockage d'une valeur delta compressée
- *
- * Cette fonction implémente l'algorithme de compression différentielle adaptatif
- * qui permet de réduire l'empreinte mémoire des échantillons. Trois formats sont
- * disponibles selon les caractéristiques du signal:
- * 1. Format standard (2 octets): delta d'accélération + intervalle fixe 1ms
- * 2. Format variable (3 octets): delta d'accélération + delta temps explicite
- * 3. Échec compression: utilisation d'une valeur complète (via stockerValeurComplete)
- *
- * @param valeur Valeur d'accélération actuelle en mg
- * @param temps Horodatage relatif actuel en ms
- * @return true si compression réussie, false si valeur complète nécessaire
- */
- bool stockerDeltaValeur(int16_t valeur, uint16_t temps) {
- // Calculer les deltas
- int16_t deltaAccel = valeur - dernierAccel;
- uint16_t deltaTemps = temps - dernierTemps;
- // Vérifier si le delta est dans les limites encodables
- if (deltaAccel < DELTA_MIN || deltaAccel > DELTA_MAX) {
- return false; // Nécessite une valeur complète
- }
- // Déterminer le format optimal selon l'intervalle temporel
- uint8_t espaceRequis;
- uint8_t typeMarqueur;
- if (deltaTemps == INTERVALLE_TEMPS_STD) {
- // Format compact (delta avec intervalle implicite)
- espaceRequis = 2; // 1 marqueur + 1 delta
- typeMarqueur = MARQUEUR_DELTA_TEMPS_STD;
- } else if (deltaTemps <= 255) {
- // Format avec temps explicite
- espaceRequis = 3; // 1 marqueur + 1 delta + 1 temps
- typeMarqueur = MARQUEUR_DELTA_TEMPS_VAR;
- } else {
- return false; // Delta temps trop grand, nécessite valeur complète
- }
- // Vérifier l'espace disponible
- if (indexBuffer + espaceRequis > BUFFER_SIZE) {
- Serial.println(F("Buffer plein"));
- acquisitionTerminee = true;
- return false;
- }
- // Écriture selon le format déterminé
- buffer[indexBuffer++] = typeMarqueur;
- buffer[indexBuffer++] = deltaAccel & 0xFF; // Delta signé 8 bits
- if (typeMarqueur == MARQUEUR_DELTA_TEMPS_VAR) {
- buffer[indexBuffer++] = deltaTemps & 0xFF;
- }
- // Mettre à jour les références
- dernierAccel = valeur;
- dernierTemps = temps;
- nbEchantillons++;
- return true;
- }
- /**
- * Décompression et sauvegarde des données au format texte final
- *
- * Cette fonction parcourt le buffer de données compressées, reconstruit les
- * valeurs originales d'accélération et de temps, puis les écrit directement
- * dans le fichier MESURE.txt avec le format attendu par l'utilisateur final.
- *
- * Le processus de décompression reconstruite séquentiellement les valeurs en
- * appliquant l'algorithme inverse de compression, selon les marqueurs rencontrés.
- * Une validation de format est appliquée pour éviter les corruptions de données.
- *
- * Un fichier de métadonnées INFO.txt est également généré pour documenter
- * les statistiques d'acquisition et l'efficacité de la compression.
- */
- void sauvegarderDonneesMesure() {
- // Création du fichier de mesure au format attendu
- fichierSD = SD.open(F("MESURE.txt"), FILE_WRITE);
- if (fichierSD) {
- // En-tête standardisé
- fichierSD.println(F("Accel Z (g), Temps (ms)"));
- // Variables pour la reconstruction des données
- uint16_t i = 0;
- int16_t accel = 0;
- uint16_t temps = 0;
- char bufferFormatage[20]; // Buffer temporaire pour formatage des valeurs
- // Parcours séquentiel et décodage du buffer compressé
- while (i < indexBuffer) {
- if (buffer[i] == MARQUEUR_VALEUR_COMPLETE) {
- // Décodage de la valeur complète (16 bits)
- i++; // Avancer après le marqueur
- accel = (buffer[i] << 8) | buffer[i+1];
- i += 2;
- temps = (buffer[i] << 8) | buffer[i+1];
- i += 2;
- }
- else if (buffer[i] == MARQUEUR_DELTA_TEMPS_STD) {
- // Décodage du delta standard (variation fixe)
- i++;
- int8_t deltaAccel = buffer[i];
- i++;
- accel += deltaAccel;
- temps += INTERVALLE_TEMPS_STD;
- }
- else if (buffer[i] == MARQUEUR_DELTA_TEMPS_VAR) {
- // Décodage du delta variable (intervalle temporel explicite)
- i++;
- int8_t deltaAccel = buffer[i];
- i++;
- uint8_t deltaTemps = buffer[i];
- i++;
- accel += deltaAccel;
- temps += deltaTemps;
- }
- else {
- // Protection contre les formats non reconnus
- i++;
- continue;
- }
- // Conversion en valeur d'accélération en g (précision 2 décimales)
- float accel_g = accel / 1000.0; // Conversion mg → g
- dtostrf(accel_g, 6, 2, bufferFormatage);
- // Écriture formatée dans le fichier
- fichierSD.print(bufferFormatage);
- fichierSD.print(F(", "));
- fichierSD.println(temps);
- }
- fichierSD.close();
- Serial.println(F("Fichier MESURE.txt généré"));
- } else {
- Serial.println(F("Erreur création fichier MESURE.txt"));
- }
- // Génération optionnelle d'un fichier de métadonnées
- fichierSD = SD.open(F("INFO.txt"), FILE_WRITE);
- if (fichierSD) {
- fichierSD.println(F("STATISTIQUES ACQUISITION:"));
- fichierSD.println(F("------------------------"));
- fichierSD.print(F("Échantillons: ")); fichierSD.println(nbEchantillons);
- fichierSD.print(F("Compression: "));
- uint8_t ratioCompression = (uint8_t)((float)indexBuffer / (nbEchantillons * 4.0) * 100.0);
- fichierSD.print(ratioCompression); fichierSD.println(F("%"));
- fichierSD.print(F("Durée: ")); fichierSD.print(compteurSecondes); fichierSD.println(F(" sec"));
- fichierSD.close();
- }
- }
- void setup() {
- Serial.begin(BAUD_RATE);
- Serial.println(F("Initialisation système"));
- /**
- * Configuration ADC optimisée
- * Maintien du prescaler à 128 (valeur par défaut) pour privilégier
- * la précision sur la vitesse, conformément aux recommandations.
- * La valeur 0x07 correspond au diviseur 128 dans les registres ADCSRA.
- */
- ADCSRA = (ADCSRA & 0xF8) | 0x07;
- // Initialisation carte SD
- if (!SD.begin(PIN_CS_SD)) {
- Serial.println(F("Échec initialisation carte SD"));
- while (1); // Arrêt du système
- }
- // Suppression des fichiers existants
- if (SD.exists(F("DATA.BIN"))) SD.remove(F("DATA.BIN"));
- if (SD.exists(F("META.TXT"))) SD.remove(F("META.TXT"));
- if (SD.exists(F("ACCEL.CSV"))) SD.remove(F("ACCEL.CSV"));
- // Configuration du Watchdog
- configurerWatchdog();
- // Initialisation des variables
- indexBuffer = 0;
- nbEchantillons = 0;
- tempsDebutAcquisition = millis();
- Serial.println(F("Début acquisition de données"));
- Serial.print(F("Capacité buffer: "));
- Serial.print(BUFFER_SIZE);
- Serial.println(F(" octets"));
- }
- void loop() {
- if (!acquisitionTerminee) {
- /**
- * PHASE 1: ACQUISITION PURE
- *
- * Cette phase privilégie la vitesse d'échantillonnage en concentrant
- * toutes les ressources système sur l'acquisition et la compression.
- * Aucune opération de sauvegarde n'est effectuée pendant cette phase
- * pour éviter les latences variables associées aux accès SD.
- *
- * La fréquence d'échantillonnage théorique maximale est d'environ 8-10kHz,
- * limitée principalement par le temps de conversion ADC et les calculs
- * de compression.
- */
- // Lecture optimisée de l'accéléromètre
- uint16_t valeurADC = lectureADC(PIN_CAPTEUR - A0);
- // Conversion en accélération (mg)
- int16_t acceleration = ((int32_t)valeurADC - ZERO_G_VALUE) * SCALE_FACTOR / 100;
- // Horodatage relatif (ms)
- uint16_t tempsRelatif = millis() - tempsDebutAcquisition;
- /**
- * Sélection intelligente du mode de stockage
- * Première valeur toujours stockée en format complet (référence initiale)
- * Sinon tentative de compression, avec fallback vers format complet
- * si les deltas calculés sont hors plage ou si le temps est trop grand
- */
- if (nbEchantillons == 0 || !stockerDeltaValeur(acceleration, tempsRelatif)) {
- stockerValeurComplete(acceleration, tempsRelatif);
- }
- } else {
- /**
- * PHASE 2: SAUVEGARDE FINALE
- *
- * Cette phase se déclenche après la période d'acquisition définie (7s)
- * et s'occupe exclusivement du traitement et de la sauvegarde des données.
- *
- * Le processus inclut:
- * - Décompression des données depuis le buffer mémoire
- * - Conversion au format attendu (accélération en g, temps en ms)
- * - Génération du fichier MESURE.txt pour l'utilisateur final
- * - Enregistrement des statistiques d'acquisition
- */
- static bool sauvegardeFaite = false;
- if (!sauvegardeFaite) {
- Serial.println(F("Acquisition terminée"));
- Serial.print(F("Échantillons acquis: "));
- Serial.println(nbEchantillons);
- // Génération directe du fichier MESURE.txt
- sauvegarderDonneesMesure();
- sauvegardeFaite = true;
- Serial.println(F("Traitement terminé"));
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement