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);
}
}
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);
}
}
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
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
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