Retard/Avance Cadencement boucle 10ms arduino

Bonjour à tous,

Je travaille sur un petit exercice qui me paraissait des plus simplistes mais je n'arrive pas à résoudre mon problème. Je cherche à cadencer une boucle à 100 Hz soit 10 ms.

unsigned long previousTime=0;           // end time of the last period in microsecond
unsigned long currentTime=0;
unsigned long executionTime=0;
unsigned long deltaTime=0;
const long period=10000;              // time period for pulse counting in microsecond


void setup()   {                
  Serial.begin(115200);
  Serial.println("Start");
  
}

//------------------------------------------------------------------------------------------------//
void loop() {
  currentTime = micros();
  deltaTime = currentTime-(previousTime-executionTime); 
  
  if (deltaTime >= period){ 
       Serial.print("\t currentTime=\t");
       Serial.println(currentTime);
       previousTime = micros();
       executionTime = previousTime-currentTime;   
  }

}

J'ai un retard aléatoire de 4 micro secondes

Start
     currentTime=   10004
     currentTime=   20008
     currentTime=   30008
     currentTime=   40012
     currentTime=   50016
     currentTime=   60020
     currentTime=   70024
     currentTime=   80028
     currentTime=   90032
     currentTime=   100032
     currentTime=   110032
     currentTime=   120032
     currentTime=   130036
     currentTime=   140036
     currentTime=   150036
     currentTime=   160036
     currentTime=   170036
     currentTime=   180036
     currentTime=   190036
     currentTime=   200036
     currentTime=   210036
     currentTime=   220036
     currentTime=   230040
     currentTime=   240040
     currentTime=   250040
     currentTime=   260040
     currentTime=   270040
     currentTime=   280040
     currentTime=   290040
     currentTime=   300040
     currentTime=   310044

Naïvement je pensais que le soucis se situait sur la ligne:

executionTime = previousTime-currentTime;

que j'ai transformé,

executionTime = micros()-currentTime;

Maintenant il y a une avance,

Start
     currentTime=   10004
     currentTime=   20000
     currentTime=   30000
     currentTime=   39996
     currentTime=   49992
     currentTime=   59988
     currentTime=   69988
     currentTime=   79984
     currentTime=   89980
     currentTime=   99976
     currentTime=   109976
     currentTime=   119972
     currentTime=   129972
     currentTime=   139972
     currentTime=   149968
     currentTime=   159964
     currentTime=   169956
     currentTime=   179956
     currentTime=   189952
     currentTime=   199948
     currentTime=   209952
     currentTime=   219948

Je n'arrive pas à obtenir une période fixe de 10ms, j'aimerai bien de l'aide svp....

Bonne soirée, Pm

unsigned long lastMillis = 0;

....

// dans la loop()

if (millis()-lastMillis >= 10) {
   // ... 10 ms sont passées
   // faites ce qu'il faut faire
   lastMillis +=10; / en faisant comme cela on "gomme" le temps d'exécution
}

Génial merci beaucoup!

Bonne soirée, Pm

de rien :-)

Bonjour,

Il y a aussi FlexiTimer2, qui permet de déclencher une interruption (et d'exécuter une fonction à ce moment-là) à un intervalle de temps donné.

Merci pour l’info je vais regarder aussi cette fonction. Quelle est l’avantage ou l’inconvénient par rapport à la première méthode?

J’ai un petit soucis dans l’exécution de mon code et je ne sais pas trop comment procéder.
En fait l’objectif global de l’exercice est de réaliser un compteur moto indiquant la vitesse du véhicule, la distance parcourue et la vitesse de rotation de la roue. Par la suite, j’aimerai ajouter une sauvegarde des données sur une SD avec une frequence de 100Hz. C’est pourquoi j’ai choisit de séparer la boucle en 2 tâches à des fréquences différentes:

  • rafraichissement des données capteur effet hall toutes les 10ms
  • affichage sur l’écran toutes les 100ms (trop lent et illisible pour le faire toutes les 10ms)

Le soucis c’est lorsque je lance mon code:

// Program to compute rotational wheel speed, vehicle velocity and travel distance from the measure of a hall effect sensor
// The program used a fixed period to count the number of rising edge and compute the wheel speed in rpm

// Libraries:
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// Display SSD1906 settings:
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13

Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

// Variables:
volatile byte rpmCounter=0;             // pulse counter
unsigned int  counter=0;                // total number of counting pulses since begining only for debugging 
unsigned int  rpm=0;                    // rotational wheel speed in rpm
unsigned long previousTimeSensor=0;     // end time of the last sensor period in micros
unsigned long previousTimeScreen=0;     // end time of the last screen period in micros
unsigned long currentTime=0;            // actual time in micros
unsigned long deltaTimeSensor=0;
const long periodSensor=10000;          // time period for pulse counting in micros
const long periodScreen=100000;        // time period for refresch the screen in micros
const int ppr=40;                       // pulse per revolution
const float radiusRearWheell=0.2758;    // radius of the wheel in m
const float pi = 3.14159;               // pi constant
float Speed=0;                          // vehicle speed in km/h
float distance=0;                       // travel distance in m

//------------------------------------------------------------------------------------------------//
//------------------------------------------------------------------------------------------------//
void disp(float SpeedToDisp, int rpmToDisp, float DistanceToDisp, int counterToDisp)   // display function for SSD1906
{
  // vehicle speed displaying:
  display.setTextSize(1);  
  display.setCursor(0,3);        
  display.println("Speed");     
  display.setCursor(46,0); 
  display.setTextSize(2);          
  display.println(SpeedToDisp);
  display.setCursor(95,3);
  display.setTextSize(1);        
  display.println(" km/h"); 
  
  // wheel rpm displaying:
  display.setTextSize(1);  
  display.setCursor(0,18);        
  display.println("RPM");     
  display.setCursor(46,15); 
  display.setTextSize(2);          
  display.println(rpmToDisp);
  display.setCursor(95,18);
  display.setTextSize(1);        
  display.println(" rpm"); 

  // travel distance displaying:
  display.setTextSize(1);  
  display.setCursor(0,33);        
  display.println("Dist."); 
  display.setCursor(46,30); 
  display.setTextSize(2);          
  display.println(DistanceToDisp);
  display.setCursor(95,33);
  display.setTextSize(1);        
  display.println(" m");

  // global pulse counter displaying:
  display.setTextSize(1);  
  display.setCursor(0,48);        
  display.println("Counter"); 
  display.setCursor(46,45); 
  display.setTextSize(2);          
  display.println(counterToDisp);
 
  display.display();
  display.clearDisplay();
  
 }
  
//------------------------------------------------------------------------------------------------//
void rpmCountFun() // function for attachInterrupt
 {
      rpmCounter++ ;   // Update rpm counter
      counter++;       // Update global counter just for debugging
 }

//------------------------------------------------------------------------------------------------//
void updateSensor() // function for attachInterrupt
{
   deltaTimeSensor = currentTime - previousTimeSensor;
   if (deltaTimeSensor >= periodSensor){ 
    detachInterrupt(0);                                             // disable interrupt when calculating
    rpm = rpmCounter*6000000/(ppr*deltaTimeSensor );                // convert frecuency to RPM be carefull period is in micros and need to be multiplied by 6000000 to be converted in min
    Speed = 3.6*radiusRearWheell*rpm*2*pi/ 60;                      // speed calculation v=3.6*r*w with w in rad/s
    distance = distance + rpmCounter*2*pi*radiusRearWheell/ppr;     // distance calculation
    rpmCounter = 0;                                                 // restart the RPM counter
   
    Serial.print("\t currentTime=\t");
    Serial.print(currentTime);
    Serial.print("\t RPM =\t"); 
    Serial.print(rpm);
    Serial.print("\t speed=\t"); 
    Serial.print(Speed); 
    Serial.print("\t distance=\t");
    Serial.print(distance);
    Serial.print("\t global counter=\t");
    Serial.println(counter); 
    
    previousTimeSensor += periodSensor;       // uptade previousTimeSensor
    attachInterrupt(0, rpmCountFun, RISING);  //enable interrupt
   }
   
}

//------------------------------------------------------------------------------------------------//
void updateScreen() // function for attachInterrupt
{
  if (currentTime - previousTimeScreen >= periodScreen){ 
        disp(Speed, rpm, distance, counter );           // display results on the screen
        previousTimeScreen += periodScreen;             // uptade previousTimeScreen
  }
  
}

//------------------------------------------------------------------------------------------------//
void setup()   {                
    Serial.begin(115200);
    
    //init SSD1906 display:
    display.clearDisplay();
    display.begin(SSD1306_SWITCHCAPVCC);
    display.clearDisplay();
    display.setTextColor(WHITE);

    attachInterrupt(0, rpmCountFun, RISING);
    
    Serial.println("Start");

}

//------------------------------------------------------------------------------------------------//
void loop() {
  currentTime = micros();
  updateSensor();
  updateScreen();
 
}

l’initialisation de l’écran ( display.begin(SSD1306_SWITCHCAPVCC) ) dans la fonction setup() est un peu longue et du coup ma première mesure est à 12 ms.

Start
	 currentTime=	12616	 RPM =	0	 speed=	0.00	 distance=	0.00	 global counter=	0
	 currentTime=	20004	 RPM =	0	 speed=	0.00	 distance=	0.00	 global counter=	0
	 currentTime=	30004	 RPM =	0	 speed=	0.00	 distance=	0.00	 global counter=	0
	 currentTime=	40000	 RPM =	0	 speed=	0.00	 distance=	0.00	 global counter=	0
	 currentTime=	50000	 RPM =	0	 speed=	0.00	 distance=	0.00	 global counter=	0
	 currentTime=	60000	 RPM =	0	 speed=	0.00	 distance=	0.00	 global counter=	0
	 currentTime=	70000	 RPM =	0	 speed=	0.00	 distance=	0.00	 global counter=	0
	 currentTime=	80004	 RPM =	0	 speed=	0.00	 distance=	0.00	 global counter=	0

En commentant la ligne d’initialisation de l’écran, le timing est parfait mais je n’ai plus rien d’affiché…

Avez vous une idée?

Merci d’avance et bonne soirée,
Pm

FlexiTimer2 utilise un timer hardware pour déclencher une interruption. comme vous avez déjà des interruptions ce n'est pas forcément judicieux d'en rajouter à mon avis et gérer du 100Hz c'est accessible juste dans la boucle du moment où vous ne faites pas d'opérations trop lourde (les LCD sont souvent assez lents --> optimisez et ne affichez pas sans cesse la légende par exemple. affichez seulement les valeur sans écraser la légende que vous n'écrirez qu'une seule fois)

Sinon counter devrait être volatile et par acquis de conscience tous vos calculs avec des grands entiers devraient être notés comme tel genre 100000[color=red]ul[/color] ou 6000000[color=red]ul[/color] (pour unsigned long) par exemple

Vos Serial print de debug si vous saturez le buffer deviennent bloquants et peuvent aussi vous emmener des soucis, vous devriez limiter le texte affiché en debg au strict minimum, pas besoin de

     currentTime=   12616    RPM =  0    speed= 0.00     distance=  0.00     global counter=    0

par exemple faites juste

12616    0  0.00   0.00     0