Pages: [1] 2   Go Down
Author Topic: Décalage horloge interne millis()  (Read 4850 times)
0 Members and 1 Guest are viewing this topic.
Chateau-Thierry (02)
Offline Offline
Full Member
***
Karma: 0
Posts: 167
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonsoir

Ayant réalisé un petit programme de gestion d'oscillateurs à base de servomoteurs : http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1293371084

J'effectue le changement de paramètres (vitesses, courses, ...) en fonction de l'heure.
Pour ce faire, j'ai créé une horloge interne à base de l'instruction millis().
Mais un problème de taille me pose problème. La valeur millis n'évolue pas au rythme souhaité. Normalement, un décalage de 1000 correspond à 1 seconde, et dans mon cas, cela va trop vite. J'ai donc recalé le comptage par une simple règle de trois, mais je me rends compte que le décalage est aléatoire.
parfois cela avance, parfois cela retarde.
J'ai tout d'abord pensé que cela provenait de la taille du programme et que l'horloge s'apparentait plus à un compteur de cycle où la longueur du programme faisait varier le rythme de la variable interne millis.
J'ai donc créé un tout petit programme allumant la LED avec une impulsion toutes les minutes pour vérifier ma théorie.
Effectivement la valeur est légèrement différente pour clignoter toutes les minutes, mais toujours pas dans la norme (je devrais en théorie avoir 600 pour incrémenter toutes les minutes).

Voici le bout de code :
Code:
 
// Déclaration des variables et constantes horloge
  long compteur_top=0;        // Initialisation des tops horloge
  long ancien_millis=0;       // Mémoire de l'horloge millis
  int minute = 5;            // Minutes de l'horloge
  int heure = 19;             // Heures de l'horloge (avec inscription "19h" comme heure initiale)
  
  
   // Sortie LED
  const int led_int = 13;
  int etat_led = LOW;
 
 

void setup() {

  
  // Adressage des sorties
  pinMode (led_int, OUTPUT);
 
  // Initialise la liaison série
  Serial.begin(19200);
   delay(50);
 
}



void loop() {
  
// Création d'une impulsion temporisée (top) pour déplacements oscillateurs sur la base de l'horloge interne millis()
  int top;
      if (millis() >= ancien_millis) { // Vérifie que le temps millis() est bien supérieur à l'ancienne valeur mémorisée
                                       // >> risque à l'init et au retour à zéro de l'horloge interne.
      if (millis() - ancien_millis >= 100){ top = 1;  // création d'un top toutes les 100ms
              ancien_millis = millis();               // réinitialisation ancien_millis
          compteur_top = compteur_top + 1; }          // Incrémente le compteur de tops
                      
                      else {delay(100-(millis()-ancien_millis));}
      }
        
// HORLOGE
    if (compteur_top >= 498) {minute = minute + 1; //Incrémentation des minutes  
         // (498 au lieu de 600 dans ce cas pour avoir une incrémentation toutes les minutes)
    
        compteur_top = 0;  
  etat_led = HIGH;      
    }
    else etat_led = LOW;
    
    if (minute >= 60) {heure = heure + 1; //Incrémentation des heures
        minute = 0;}
    if (heure >=24) {heure = 0;} // réinitialise l'horloge toutes les 24h
  
    
    
// LIAISON SERIE POUR TESTS

 if (top = 1){
    
      Serial.print(heure);
      Serial.print("     ");  
      Serial.print(minute);
    
      Serial.println("   ");
    
      Serial.println("   ");
  
      Serial.println("     ");
      
}

 // Remise à zéro impulsion "Top"
  top = 0;
  
 
  //    Serial.print("   ");
      Serial.println("  ");
      Serial.println("   ");
      Serial.println("   ");
      

      
          
        digitalWrite(led_int, etat_led);
      
      
}

Ma carte aurait-elle un problème, ou la valeur millis est naturellement inexploitable ?

Merci pour votre aide
Franck
Logged

Toulouse / France
Offline Offline
Full Member
***
Karma: 5
Posts: 241
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour,

ça me semble un gros offset tout de même,
Je viens de refaire le montage DS1307 avec le code suivant (trèèèès fortement issu du lien ci dessus)

Code:
//ChronoDot test [ds1307]
// Based on http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1279385586

#include <WProgram.h>
#include <Wire.h>
#include <DS1307.h> // written by  mattt on the Arduino forum and modified by D. Sjunnesson

#define INT_PIN 3  //DS1307 sqw wire

extern volatile unsigned long timer0_millis;
volatile unsigned long t, now, prev;

void setup() {
  //init wire & serial
  Wire.begin();
  Serial.begin(9600);
  Wire.beginTransmission(104); // transmit to device #104, the ds 1307
  Wire.send(0x07);  //select control register
  Wire.send(0x10);  //set sqw at specified Hz of  0=1Hz
  Wire.endTransmission();

  //init interrupt
  pinMode(INT_PIN, INPUT);
  attachInterrupt(0, OneHzInterrupt, FALLING);  //0 = digital pin 3
}


void loop() {
 Serial.println(t);
  delay(1000);
}


void OneHzInterrupt(void) {
now = timer0_millis;
  t = now - prev;
  prev = now;
}

et j'ai ce genre de résultat :


Code:
1000
1000
999
1001
1000
1000
1000
1000
1000
999
1001
999
1001
1000
1000
1000
1000
1000
999
1001
1000
1000
1000
1000
1000
999
1001
1000
1000
1000
1000
1000
1000
1000
1000
1000
1000
1000
1000
1000
1000
1001
999
1000
1000
1000
1000
1000
1001
999
1000
1000
1000
1000
1000
1001
999
1001
999
1000
1000
1000
1001
999
1001
999
1000
1000
1000
1001
999

Donc c'est de l'ordre de moins de 1ms par seconde de dérive, ce n'est pas du même ordre que ce que tu constates, doit y avoir un souci dans le code, n'étant pas vraiment une star du code, je ne sais pas dire ou est l'erreur dans le tien

Par contre, il existe la librairie Time pour simplifier l'usage de l'heure dans les sketches, réglable par le terminal série par exemple
http://www.arduino.cc/playground/Code/Time

Ceci dit, concernant de la gestion horaire, je pense que tu devrais regarder tu coté des horloges RTC (Real Time Clock)

Les plus célèbres sont basées sur le DS1307 ou le Chronodot (DS1321 pour plus de précision)
Elles sont autonomes (batterie lithium) donc ne craignant aucunement la coupure secteur.

Leur utilisation est bien documentée, elles utilisent le bus I2c (entrées Analogiques 4 & 5) et c'est quand même bien plus simple de jouer avec le temps dans ce cas.

Bon courage,

Lionel


- Distributeur officiel Arduino - Conception de shields pour les bricoleurs
Logged

- Distributeur officiel Arduino - France

Geneva
Offline Offline
Faraday Member
**
Karma: 30
Posts: 3231
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ce que je ne comprend pas c'est la raison pour laquelle tu utilises millis() avec un delay si millis() n'est pas à la valeur que tu attends :

Code:
else {delay(100-(millis()-ancien_millis));}

Essaye simplement de supprimer ce delay() :

Code:
else {;;} // ou sans les ;;

Ton offset viens peut-être de là.


Ensuite, incrémente tes top ainsi :

Code:
compteur_top ++; }    

« Last Edit: January 18, 2011, 06:13:32 am by jfs » Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Chateau-Thierry (02)
Offline Offline
Full Member
***
Karma: 0
Posts: 167
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour

Merci à tous les deux pour votre aide !  smiley

Lionel
J'avais vu cette option "librairie time", mais je n'ai pas compris comment la télécharger (si vous pouviez m'aider, je suis preneur  smiley )

Pour l'utilisation d'une horloge externe RTC, je pensais pouvoir m'en passer au regard du besoin de précision relativement faible dont j'ai besoin. Mais là, c'est énorme !

Jean François
Tout le développement que j'avais réalisé était sans le else (delay). Et le décalage était présent.
Comme j'ai supposé que l'horloge se décalait à cause du temps de scrutation, je m'étais dit qu'une pause ne ferait pas de mal au processeur. Et ai donc rajouté cette instruction qui repose le proc. en attendant le temps nécessaire à l'obtention du top 100ms. Cela n'a rien changé dans le décalage, mais permet de scruter moins souvent  smiley-wink.
Là n'est donc pas le problème

Oui, pour l'incrémentation, je vais modifier par "compteur_top ++; "



Si vous entrez la totalité du code donné en tête de post, je constate ce décalage. Constatez vous le même ?

Franck
Logged

Geneva
Offline Offline
Faraday Member
**
Karma: 30
Posts: 3231
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

J'ai effectivement un décalage d'une ou deux secondes au bout de quinze minutes.
Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Toulouse / France
Offline Offline
Full Member
***
Karma: 5
Posts: 241
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
J'avais vu cette option "librairie time", mais je n'ai pas compris comment la télécharger (si vous pouviez m'aider, je suis preneur   )

La librairie se trouve en suivant ce lien

http://www.arduino.cc/playground/uploads/Code/Time.zip

En fonction de ton OS il faut l'installer a l'endroit qui convient

Lionel
Logged

- Distributeur officiel Arduino - France

Geneva
Offline Offline
Faraday Member
**
Karma: 30
Posts: 3231
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

J'ai une hypothèse.
la précision est de 1 milliseconde, la résolution est de 4 millisecondes.

Comme on test un chiffre plus grand ou égal à l'écart de temps que l'on veut mesurer, au meilleur des cas on tombe sur le plus petit écart possible, au pire des cas on tombe sur un chiffre plus grand, donc une dérive est obligatoire.

Lors de chaque test if t tu tombes dans la fourchettes de résolution, dans le pire des cas tu as une seconde d'offset au bout de 4 minutes.
Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Geneva
Offline Offline
Faraday Member
**
Karma: 30
Posts: 3231
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

J'ai sué un petit moment sur ton problème....

Je t'ai fait un petit bout de code avec commentaires, essaye le.
Après 30 minute de test, je n'ai pas de dérive flagrante.

Quote

// Déclaration des variables et constantes horloge

unsigned long refTemps=0;              // reference prise dans le flux du temps
                                  // on lance une ancre dans le flux du temps et on compte les noeuds qui défilent sur la corde
unsigned long diff=0;                // difference entre le temps voulu et le temps reel

int jour=18;                // Jour de l'horloge
int heure = 23;             // Heures de l'horloge
int minute = 32;            // Minutes de l'horloge
int seconde = 0;            // Secondes de l'horloge


void setup() {

  // Initialise la liaison série
  Serial.begin(19200);

}


void loop() {

  diff=millis()-refTemps-1000;      // on calcule les millisecondes qui seront perdues dans la comparaison de la boucle "if"
  if(millis()-refTemps>=1000){      // on compare a 1000 (1 seconde) le temps actuel moins la longueur de l'ancre jetee dans le flux du temps

    refTemps=millis();              // on jette a nouveau une ancre dans le flux du temps
    seconde++;                      // on additionne 1 seconde
    
    refTemps -= diff;                 // on enleve les millisecondes de retard a la position de l'ancre, ainsi l'echeance de la seconde arrive plus tot
    
    if(seconde>=60){                // lorsque les secondes arrivent a 60
      minute++;                     // on additionne 1 minute
      seconde=0;                    // et on remet les seconde a zero
      if(minute>=60){               // lorsque les minutes arrivent a 60
        heure++;                    // on additionne 1 heure
        minute=0;                   // et on remet .... etc, etc
        if(heure>=24){
          jour++;
          heure=0;

        }
      }
    }
  }

  // on envoie dans le moniteur serie le jour, l'heure, les minutes et les secondes....
  Serial.print(jour);
  Serial.print("     ");  
  Serial.print(heure);
  Serial.print("     ");  
  Serial.print(minute);
  Serial.print("     ");  
  Serial.println(seconde);

delay(100);

}



Tiens moi au courant  smiley-wink
« Last Edit: January 19, 2011, 02:35:30 am by jfs » Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Chateau-Thierry (02)
Offline Offline
Full Member
***
Karma: 0
Posts: 167
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ouhaouuuu !  :o :o  :-X

Je vois qu'il y en a qui occupent leurs soirées  ;D

Merci Jean François
Bien vu la cause très probable du décalage. Je testerais l'intégration de cette astuce ce WE.

Lionel,
J'ai un portable dernière (presque) génération sous win7. Le soft Arduino installé est la version Française, sans remise à jour.
Je ferais également l'installation ce WE. Mais je n'ai pas tout compris dans la manière de procéder. Où dois-je dézipper ? Suffit-il d'écrire les instructions sans chargement préalable ? y'aurais pas un tuto qui traine des fois ?

Franck
Logged

Toulouse / France
Offline Offline
Full Member
***
Karma: 5
Posts: 241
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour,

Pour installer une nouvelle librairie, il faut faire comme suggéré sur la page suivante :
http://www.mon-club-elec.fr/pmwiki_reference_arduino/pmwiki.php?n=Main.Librairies

Quote
(...)Pour utiliser les librairies "hors référence" fournies par la communauté, il faut télécharger un fichier zip, le décompresser et copier le répertoire obtenu dans le répertoire /arduino-00xx/libraries/. La nouvelle librairie ainsi installée sera insérée dans un programme à l'aide de l'instruction #include.

Ou alors, il y a aussi la possibilités de place la librairie dans ton répertoire sketchbook, il faut la dézipper dans un dossier /libraries/ que tu auras crée dans ton répertoire sketchbook


Ensuite, il faut quitter l'appli et la relancer pour que les nouvelles librairies soient prises en compte lors de la compilation.

Souvent, les librairies intègrent des sketches d'exemple qui seront accessibles (une fois la lib installée) par le menu File/examples du GUI arduino.

Et je ne savais même pas qu'il y avait une version fr de l'arduino, par curiosité tu l'as trouvée ou ?

Par ailleurs, je te conseille plutôt de travailler avec la version à jour du GUI (22 à ce jour) les évolutions du GUI corrigent bien des bugs.

Lionel





- Distributeur officiel Arduino - Conception de shields qui s'empilent
« Last Edit: January 19, 2011, 10:07:39 am by snootlab » Logged

- Distributeur officiel Arduino - France

Chateau-Thierry (02)
Offline Offline
Full Member
***
Karma: 0
Posts: 167
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Merci Lionel.

Je tenterais l'opération (et celle de Jean François) ce WE

Pour le soft en Français, b'en t'étais pas loin :
http://www.mon-club-elec.fr/pmwiki_reference_arduino/pmwiki.php?n=Main.TelechargerArduinoFrancais
(version 018)

Voilà
« Last Edit: January 19, 2011, 10:02:58 am by Bubule » Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 62
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour,

En ce qui concerne les libraries ajoutées, j'avais fait comme conseillé sur le site Arduino mais à la 1ere mise à jour du logiciel Arduino comme j'ai créée un nouveau répertoire pour la nouvelle version et que je n'avais pas copié le dossier "libraries", je ne pouvais plus compiler mes projets. J'ai cherché un moment avant de comprendre pourquoi ça ne marchait plus.  >smiley-sad
Maintenant j'ai  un dossier "librairies" dans le dossier sketchbook et j'y installe les librairies et plus de problème pour les mises à jour Arduino.

Serge
Logged

Geneva
Offline Offline
Faraday Member
**
Karma: 30
Posts: 3231
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Sur dix heures d'essais, j'ai une dérive de 2 secondes.



J'ai une autre solution un peu plus simple, qui devrait fonctionner sans dérive :

Quote
// Déclaration des variables et constantes horloge

unsigned long refTemps;              // echeance placee dans le futur

int jour=19;                // Jour de l'horloge
int heure = 18;             // Heures de l'horloge
int minute = 6;            // Minutes de l'horloge
int seconde = 30;            // Secondes de l'horloge


void setup() {

  // Initialise la liaison série
  Serial.begin(19200);

}


void loop() {

  if (millis()>= refTemps){          // si millis est egal ou plus grand que l'echeance

    refTemps+=1000;                   //la derniere echeance + 1 seconde
    seconde++;                      // on additionne 1 seconde

    if(seconde>=60){                // lorsque les secondes arrivent a 60
      minute++;                     // on additionne 1 minute
      seconde=0;                    // et on remet les seconde a zero
      if(minute>=60){               // lorsque les minutes arrivent a 60
        heure++;                    // on additionne 1 heure
        minute=0;                   // et on remet .... etc, etc
        if(heure>=24){
          jour++;
          heure=0;

        }
      }
    }
  }

  // on envoie dans le moniteur serie le jour, l'heure, les minutes et les secondes....
  Serial.print(jour);
  Serial.print("     ");  
  Serial.print(heure);
  Serial.print("     ");  
  Serial.print(minute);
  Serial.print("     ");  
  Serial.println(seconde);
  delay(100);
}



La précision de l'affichage de la seconde doit être dans le 1/100 de seconde, mais dans la globalité on est précis, car l'erreur ne se cumule pas et on réajuste environ toutes les secondes sur une référence qui est exacte.
« Last Edit: January 19, 2011, 02:36:16 pm by jfs » Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Geneva
Offline Offline
Faraday Member
**
Karma: 30
Posts: 3231
Yoplait... le pt'it suisse
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Après quatre heures d'essai(pour le dernier code), ça marche.... dans une moyenne.

Pendant une minute on retarde et la minute suivante on avance (de l'ordre de la 1/2 seconde) et ainsi de suite, donc en moyenne c'est "précis".  smiley-wink



Edit: Après 13 heures de test j'ai une avance de 3 secondes due à la précision du quartz et du Mcu.
« Last Edit: January 20, 2011, 01:05:29 am by jfs » Logged

MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Chateau-Thierry (02)
Offline Offline
Full Member
***
Karma: 0
Posts: 167
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonjour

3" sur 13 heures... Et moi qui pensais que la précision Suisse était indiscutable ;D ;D

Cela devrait me suffire. Car j'ai commandé un capteur photo-résistif. Je recalerais l'horloge au moment de la détection de l'allumage des HQI (éclairage du bac).

Cependant, je me demande comment cela se passera au débordement des variables "refTemps" et millis() puisqu'à aucun moment refTemps n'est réinitialisée.

Edit :
Si débordement de RefTemps avant millis : RefTemps < millis() = Pas de soucis
Si débordement de millis avant refTemps : RefTemps > millis = reste à traiter le cas car l'incrémentation ne se fait plus.

Code:
if millis() < 1000 {refTemps = 0} ;

En tous cas merci à tous. Je vous tiendrais au courant de l'évolution

Franck
« Last Edit: January 20, 2011, 07:54:27 am by Bubule » Logged

Pages: [1] 2   Go Up
Jump to: