#define SIGNAL_PIN 9  // Broche où le signal carré sera généré

 
volatile unsigned int ocr1a_value = 79;     // Valeur initiale d'OCR1A pour 10 kHz
volatile unsigned int presDivT1[6] = {0, 1, 8, 64, 256, 1024};   // 0=stop 1=frequence/1 2=freq/8 3=freq/64 4=freq/256 5=freq/1024
volatile unsigned int indexpresDivT1 = 1;
unsigned long new_ocr1a_value;

unsigned long counter = 0;
unsigned long previousMillis = 0;
const unsigned long interval = 1000; // Intervalle de 1 seconde


void setup() {//************************************************SETUP***************************************************************
  pinMode(SIGNAL_PIN, OUTPUT);
  Serial.begin(9600);                            // Initialiser la communication série à 9600 bps
  delay(3000);

  noInterrupts();                                 // Désactiver les interruptions
    // Configurer le timer 1
    TCCR1A = 0;                                   // Mettre le registre de contrôle A à 0
    TCCR1B = 1;//indexpresDivT1;                  // Mettre prescaler timer1 à 1
    TCNT1 = 0;                                    // Initialiser le compteur à 0

    bitSet(TCCR1B, WGM12);                        // Mode CTC (Clear Timer on Compare Match)
    bitSet(TIMSK1, OCIE1A);                       // Activer l'interruption sur compare match
    bitSet(TCCR1B, CS10);                         // Démarrer le timer avec un prescaler de 1
    OCR1A = ocr1a_value;                          // Initialiser OCR1A
  interrupts();                                   // Activer les interruptions

  Serial.println("Entrer la fréquence :");
}


ISR(TIMER1_COMPA_vect,ISR_NAKED) {//**********************************Interruption Timer1*********************************************** 
  //datasheet :13.2.2 Toggling the Pin
  //           Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn. Note that the SBI instruction 
  //           can be used to toggle one single bit in a port
  
                                  //appel 7 cycles   
      asm volatile("sbi 3,1");    //sbi=>Set bit in I/O register ,  3 => registre PINB ,   2 => PINB1=pin 9      2 cycles (sbi ici inverse l'etat pin9)  
 reti();                          //4 cycles
}
                                   //a la sortie 13 cycles =0.812us   

void loop() {//*******************************************************Loop****************************************************************
  
  counter++;                     //sans interruption  = 178500

    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {     //en 1s 16000000 cycles
             previousMillis = currentMillis;
              Serial.print("Charge de l'interruption : ");
              Serial.print(100-(8958/(16000000/counter)));
              Serial.println("%");
              counter = 0;
    }
    
    
    if (Serial.available() > 0) {                                                                     // Vérifier s'il y a une nouvelle entrée série      
    unsigned long frequency = Serial.parseInt();
    indexpresDivT1 = 1;
    
    if (frequency > 0) {
        counter=0;
        new_ocr1a_value = (16000000 / (presDivT1[indexpresDivT1] * 2 * frequency)) - 1;                // Calculer la nouvelle valeur de OCR1A
        if (new_ocr1a_value <= 65535) {                                                                // S'assurer que la valeur est dans les limites de OCR1A
         noInterrupts();
           TCCR1A = 0;                                                                                 // Mettre le registre de contrôle A à 0
           TCCR1B = 1;                                                                                 // Mettre prescaler timer1 à 1
           bitSet(TCCR1B, WGM12);                                                                       // Mode CTC (Clear Timer on Compare Match)
           bitSet(TIMSK1, OCIE1A);                                                                      // Activer l'interruption sur compare match
  
           TCNT1 = 0;                                                                                     // Initialiser le compteur à 0
           OCR1A = new_ocr1a_value;                                                                       // Mettre à jour OCR1A avec la nouvelle valeur
         interrupts();
         Serial.print("Nouvelle fréquence : ");
         Serial.print(frequency);
         Serial.print(" Hz fréquence la plus proche : ");
         Serial.print(16000000 / (presDivT1[indexpresDivT1]* 2 * (new_ocr1a_value + 1)));
         Serial.print(" Hz, OCR1A = ");
         Serial.println(new_ocr1a_value);
         } 
         else {
           Serial.println("Erreur : La fréquence est trop basse pour être gérée par le timer avec prescaler 1.");       
           for (indexpresDivT1 = 2; indexpresDivT1 < 6; indexpresDivT1++) {                                  // Vérifier les autres prescalers si nécessaire
                 new_ocr1a_value = (16000000 / (presDivT1[indexpresDivT1] * 2 * frequency)) - 1;
                 if (new_ocr1a_value <= 65535) {
                    noInterrupts();
                      TCCR1A = 0;                                  // Mettre le registre de contrôle A à 0
                      TCCR1B = indexpresDivT1;                     // Mettre le nouveau prescaler
                     bitSet(TCCR1B, WGM12);                        // Mode CTC (Clear Timer on Compare Match)
                     bitSet(TIMSK1, OCIE1A);                       // Activer l'interruption sur compare match
  
                      TCNT1 = 0;                                   // Initialiser le compteur à 0
                      OCR1A = new_ocr1a_value;                     // Mettre à jour OCR1A avec la nouvelle valeur
                      interrupts();
            
                      Serial.print("Nouvelle fréquence : ");
                      Serial.print(frequency);
                      Serial.print(" Hz fréquence la plus proche : ");
                      Serial.print(16000000 / (presDivT1[indexpresDivT1] * 2 * (new_ocr1a_value + 1)));
                      Serial.print(" Hz, OCR1A = ");
                      Serial.print(new_ocr1a_value);
                      Serial.print(", prescaler = ");
                      Serial.println(TCCR1B);
                      break;
                 }
        }
        if (indexpresDivT1 == 6) {
          Serial.println("Erreur : La fréquence est trop basse pour être gérée par le timer.");
        }
      }
    } else {
      Serial.println("Erreur : Entrée invalide.");
    }
  }
}