Bonjour
Après le Mini scheduler, je vous propose une version nettement plus aboutie :
- gestion intégrée du watchdog
- possibilité d'avoir des tâches de fond
- possibilité de surveillance de la charge CPU et de la quantité de ram disponible
- activation / désactivation de tâches, voire de l'ordonnanceur lui-même
- ...
Le tout en restant sur une architecture logicielle simple et assez légère.
Bref je vous encourage vraiment à tester la bestiole, d'autant que c'est très facile : branchez une arduino au PC (aucun câblage requis), ouvrez le terminal série à 115200 bauds et testez les onze exemples fournis.
Chacun d'eux illustre une des fonctionnalités de cette bibliothèque.
Télécharger la bibliothèque ordonnanceur.h
Voici le header
//Ordonnanceur de tâches pour arduino
//Bricoleau 2016
//V1.0
#ifndef ordonnanceur_h
#define ordonnanceur_h
#include <Arduino.h>
//Définition du type de fontions associées aux tâches
typedef void (*fonctionVoid)();//correspond à toute fonction du style "void ma_fonction()"
//Une tâche est définie par :
//- une fonction à exécuter
//- une période entre deux exécutions (en millisecondes)
class tache
{
public :
//Constructeur
tache(fonctionVoid fonction, uint32_t periode_ms);
//Méthodes principales
void changerFonction(fonctionVoid nouvelle_fonction);
void changerPeriode(uint32_t nouvelle_periode_ms);
void recaler(); //Voir notes explicatives plus bas
//Méthodes secondaires
void executer();
uint32_t periode() const {return this->_periode;}
uint32_t millis_prochaine_exec() const {return this->_millis_prochaine_exec;}
private :
fonctionVoid _fonction;
uint32_t _periode;
uint32_t _millis_prochaine_exec;
};
//L'ordonnanceur intègre la gestion du watchdog.
//Le watchdog est un dispositif hardware
//qui provoque un reset de l'arduino si une tâche a une durée anormale.
const uint8_t WATCHDOG_INACTIF = 0;
const uint8_t WATCHDOG_1_SECONDE = 1;
const uint8_t WATCHDOG_2_SECONDES = 2;
const uint8_t WATCHDOG_4_SECONDES = 3;
const uint8_t WATCHDOG_8_SECONDES = 4;
class ordonnanceur_c
{
public :
//Constructeur
ordonnanceur_c();
//Méthode principale, à appeler en fin de setup(), dont on ne ressort jamais sauf arrêt de l'ordonnanceur
void lancer(const uint8_t watchdog = WATCHDOG_INACTIF);
//Méthodes secondaires, appelables depuis une tâche
void stopper();
void reboot();
bool estActif() const {return this->_statut > 127;}
void modifierWatchdog(const uint8_t watchdog);
void desactiverWatchdog() {this->modifierWatchdog(WATCHDOG_INACTIF);}
const uint8_t watchdog() const {return this->_statut & 7;}
bool watchdogInactif() const {return this->watchdog() == WATCHDOG_INACTIF;}
bool watchdogActif() const {return this->watchdog() != WATCHDOG_INACTIF;}
uint16_t ramDisponible() const {return this->_ramDisponible;} //Ram disponible hors exécution des tâches
uint8_t chargeCPU1s() const {return this->_chargeCPU1s;} //Pourcentage d'occupation CPU sur 1 seconde
uint8_t chargeCPU5s() const {return this->_chargeCPU5s;} //Pourcentage d'occupation CPU sur 5 secondes
private :
uint8_t _statut, _chargeCPU1s, _chargeCPU5s;
uint16_t _ramDisponible;
uint32_t _tempo1s[2], _tempo5s[2];
void gererWatchdog();
void actualiserRamDisponible();
void actualiserChargeCPU(uint32_t);
};
extern ordonnanceur_c ordonnanceur;
#endif
Ainsi que sa note explicative
/****************************************************************************************
//Notes :
//
//Ceci est un ordonnanceur coopératif basique : les tâches ne s'interrompent pas entre elles.
//
//La fonction associée à une tâche doit s'exécuter rapidement.
// ==> Ne jamais utiliser l'instruction delay() !
// Si une pause est nécessaire, terminer la fonction et gérer la suite du traitement lors de l'appel suivant.
// Utiliser des variables statiques pour conserver l'état des données entre les appels.
// Il est aussi possible de modifier la fonction associée à la tâche et/ou sa période, selon le contexte.
// Voir les exemples fournis avec la bibliothèque.
//
//Utiliser des variables globales pour passer des données depuis une tâche vers une autre.
// La communication entre tâches est asynchrone.
//
//Au démarrage, le premier appel à chaque tâche est effectué dès que possible.
// Une fonction de type setup() peut être associée à la tâche pour sa première exécution,
// puis être remplacée par une fonction de type loop().
//
//L'utilisation du watchdog permet de contourner les cas de bug conduisant à un blocage de l'arduino.
// Elle est recommandée dans les programmes qui utilisent <Wire.h> ou <Ethernet.h>.
//
//Une tâche peut avoir une période à 0.
// C'est alors une tâche de fond, exécutée aussi souvent que possible.
// Exemple type : surveillance des entrées numériques de l'arduino (bouton poussoir, ...).
// Une tâche de fond doit avoir la durée d'exécution la plus courte possible.
//
//Pour désactiver une tâche, lui associer la fonction NULL.
//
//La méthode tache.executer() est en principe réservée à l'ordonnanceur.
// Mais elle peut aussi être appelée depuis une autre tâche.
// Cette possibilité est utile lorsqu'il y a nécessité de fluidifier l'enchaînement entre les tâches,
// par exemple entre une tâche qui lit un capteur et une tache qui exploite la valeur lue.
//
//L'ordonnanceur essaie de rattraper tout retard, afin de maintenir une période régulière.
// ==> Le délai entre deux exécutions peut donc être inférieur à la période fixée.
// Par exemple avec une période de 1000 ms : si la première exécution est à millis()=15,
// la suivante reste planifiée à millis() = 1000.
// Si besoin, recaler() permet de forcer la prochaine execution à maintenant+période.
// Nb : recaler() est automatique si les tâches durent trop longtemps et que l'ordonnanceur est saturé.
//
/****************************************************************************************/
Modèle d'implémentation dans le programme principal arduino :
#include "ordonnanceur.h"
... // définir au moins une tâche
void setup()
{
...
ordonnanceur.lancer();
}
void loop() {} //Ne sert plus à rien
ordonnanceur.zip (14.6 KB)