# 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>

// 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 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();

}
``````

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
``````