Problème pour faire clignoter une LED à une fréquence donnée.

Bonjour,

Débutant sur arduino, je désire faire clignoter une LED à une fréquence donnée comprise entre 1Hz et 100Hz.

Le réglage de la fréquence est fait avec 2 boutons ( un pour augmenter et l’autre pour diminuer la fréquence).

Un LCD pour afficher la fréquence et la période du signal.

Dans mon programme, la gestion des boutons et l'affichage du calcul de la période et de la fréquence fonctionnent parfaitement.
Par contre la LED ne clignote pas à la fréquence demandée, et je ne vois pas dans mon programme ou est l’erreur.
Par avance merci pour votre aide.

#include <Wire.h>   // Librairie déjà l'IDE  Arduino 
#include <LiquidCrystal_I2C.h>  //librairie à installer LCD
#define valeurMin 1
#define valeurMax 120
#define led 2

long demiperiode;
long previousMicros = 0;
int ledState = LOW;

float periode = 0;
int frequence = 0;

int Pin_plus=0;
int Pin_moins=0;

// Ecran à brancher en I2C
LiquidCrystal_I2C lcd(0x3F,16,2);  // Adresse 0x3F, 16 caractères, 2 lignes

void setup()
{
  pinMode(led, OUTPUT);
  digitalWrite(led, LOW);
  pinMode(11,INPUT);
  pinMode(12,INPUT);
  digitalWrite(11, HIGH);
  digitalWrite(12, HIGH);

 lcd.begin();                   //Initialise le LCD
 lcd.backlight();              //Eclairer l'écran
 lcd.setCursor(0,0);        //Début première ligne
 lcd.print("T:");              //Message texte période
 lcd.setCursor(10,0);      //Première ligne position 10
 lcd.print("ms");  
 lcd.setCursor(0,1);  
 lcd.print("F:");  
 lcd.setCursor(7,1);  
 lcd.print("Hz");  

 frequence = 10;             //Au départ on fixe f=10Hz
 lcd.setCursor(3,1);
 lcd.print(frequence);      //Affichage fréquence
 
 delay(50);  
}

void loop()
{
//gestion des boutons ok 
 if (digitalRead(11)==HIGH)    //début gestion des boutons
  {
    if (frequence<valeurMax) frequence++;
    lcd.setCursor(3,1);
    lcd.print("   ");
    lcd.setCursor(3,1);
    lcd.print(frequence);           //affichage fréquence
    while((digitalRead(11)==HIGH));
  }
  
  if (digitalRead(12)==HIGH)
   {
    if (frequence>valeurMin) frequence--;
    lcd.setCursor(3,1);
    lcd.print("   ");
    lcd.setCursor(3,1);
    lcd.print(frequence);           //affichage fréquence   
    while((digitalRead(12)==HIGH)); //fin gestion des boutons
   }
 
 //calculs ok
  demiperiode  =  500000/frequence;        //calcul demi période  en  micro s
  periode  = 1000/((float)frequence);  //calcul période  en  milli s
  lcd.setCursor(3,0);    //Seconde ligne LCD
  lcd.print(periode);    //Affiche la période 
  
//gestion allumage led ½ période puis repos  ½ période calculs problème
  unsigned long time = micros();
  
  if (time  -  previousMicros  >=  demiperiode)
  {
    ledState  =  !ledState;
    previousMicros  =  time;
    digitalWrite(led, ledState);
  }

}

Bonjour,

Mets ton code entre balises.

previousMicros doit être un unsigned long (mais je ne pense pas que ce soit le problème du moins au début).
Quand tu dis que la led ne clignote pas à la fréquence demandée, quel est le problème exactement?
Ca m'étonne aussi que tu vois une led clignoter à 100Hz

En faite je regarde la fréquence du signal sur un oxcillo et je n’ai pas par exemple 100Hz mais bien en dessous et une période qui varie de +- 5Hz.

Au final le but est de remplacer la LED, afin de piloter la fréquence d’acquisition d’une camera (triggering),
Il me faut donc une très bonne précision au niveau de la période et un signal stable dans le temps.

Tu fais des calculs et un affichage en permanence dans la loop.
Essaies de les faire uniquement lorsque la fréquence change comme ceci

void loop()
{
 static int freqPrec=0;            // fréquence précédente
 //gestion des boutons ok
 if (digitalRead(11) == HIGH)  //début gestion des boutons
 {
   if (frequence < valeurMax) frequence++;
   while ((digitalRead(11) == HIGH));
 }

 if (digitalRead(12) == HIGH)
 {
   if (frequence > valeurMin) frequence--;
   while ((digitalRead(12) == HIGH)); //fin gestion des boutons
 }
 
 if (frequence!=freqPrec)
 {
   lcd.setCursor(3, 1);
   lcd.print("   ");
   lcd.setCursor(3, 1);
   lcd.print(frequence);           //affichage fréquence

   //calculs ok
   demiperiode  =  500000 / frequence;      //calcul demi période  en  micro s
   periode  = 1000 / ((float)frequence); //calcul période  en  milli s
   lcd.setCursor(3, 0);   //Seconde ligne LCD
   lcd.print(periode);    //Affiche la période
   
   freqPrec=frequence;
 }

 //gestion allumage led ½ période puis repos  ½ période calculs problème
 unsigned long time = micros();
 
 if (time  -  previousMicros  >=  demiperiode)
 {
   ledState  =  !ledState;
   previousMicros  =  time;
   digitalWrite(led, ledState);
 }
}

Bonjour,

Je ne sais si c'est la cause du problème, mais le temps d'exécution de ta boucle est variable.
Selon que tu appuies ou pas sur un bouton, le temps d'exécution est plus ou moins long.
Dès lors, la précision de la temporisation en souffre.

De plus, est-il nécessaire de mettre à jour le LCD à chaque boucle ?
Tant que la fréquence ne change pas, il ne faut rien faire et si la fréquence change, il ne faut mettre à jour le LCD qu'une seule fois, non ?

Enfin, il serait certainement plus pratique d'utiliser les compteurs/décompteurs du processeur pour obtenir une fréquence plus stable. (Voir Datasheet du µP) Après tout, ils sont aussi prévus pour cela :wink:

Bonnes recherches !

Coyotte

Damned !
Battu sur le fil par Kamil ! :wink:

Je pense que le point de Kamill est valide, soit vous prenez l'option de Kamill, soit vous mettez les calculs de frequence et période ainsi que l'affichage associé dans une fonction inline et vous l'appelez uniquement dans le code des boutons quand la valeur change (ça évite un test sur la comparaison des fréquences)

je déclarerai unsigned long time; comme global plutôt que dans la boucle.

J'utiliserai millis() plutôt que micros() vu la fréquence max à 100Hz.

J'utiliserai les PORT plutôt que digitalWrite() qui prend un temps fou... Vous utilisez la pin 2, donc le 3ème bit sur le PORTD et la valeur courante dans le 3ème bit de PIND

(PIND & B00000100); //  valeur courante de la pin 2
PORTD &= B11111011; // met à LOW pin 2
PORTD |= B00000100; // met à HIGH pin 2

donc pour alterner

if ((PIND & B00000100)) PORTD &= B11111011; else PORTD |= B00000100;

Voici un bout de code d'exemple qui fait clignoter la pin 13 (donc la LED embarquée que vous avez directement sur votre carte UNO, pas besoin de montage)

const unsigned long demiperiode = 500; // 1Hz
unsigned long lastmillis = 0;

void setup() {
  pinMode(13, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (millis() - lastmillis > demiperiode) {
    if ((PINB & B00100000)) PORTB &= B11011111; else PORTB |= B00100000;
    lastmillis = millis();
  }
}

Petite note en passant - vous déclarez comme cela

[color=red]long[/color] demiperiode;
float periode = 0;
[color=red]int[/color] frequence = 0;

ça risque de vous jouer des tours dans les approximations. j'utiliserai des unsigned long au lieu du long et int et par acquis de conscience je mettrais 500000UL et 1000.0 dans les calculs

  demiperiode  =  500000/frequence;        //calcul demi période  en  micro s
  periode  = 1000/((float)frequence);  //calcul période  en  milli s

Merci pour votre aide et vos conseils !