////////////////////////////////////////////////////////////////////
class CStateMachineRotary //déclaration de la classe
{
public: //membres accessibles depuis l'extérieur de la classe, il s'agit de l'interface d'interaction de la classe
CStateMachineRotary(int brocheAinit, int brocheBinit); //Constructeur avec paramètres pour régler les 2 broches Arduino utilisées
void clock(); //méthode pour cadencer la machine à état (faire 1 coup d'horloge)
int getPosition()//méthode accesseur pour accéder à l'attribut privé position
{ return position;} //on parle de méthode inlinée car l'implémentation est faite dans la déclaration de la classe
private: //membres privés pour réaliser l'encapsulation: ces attributs sont inacessibles directement depuis l'extérieur de la classe
byte etat; //numéro de l'état actif
byte entreeA; //valeur lue sur l'entrée A
byte entreeB; //valeur lue sur l'entrée B
int brocheA; //numéro de broche Arduino utilisée pour l'entrée A
int brocheB; //numéro de broche Arduino utilisée pour l'entrée B
virtual void frontDetecte(){}; //methode abstraite, sera implémentée dans la classe fille
virtual void actionSurTousLesEtats(){}; //methode abstraite, sera implémentée dans la classe fille
protected: //ces membres peuvent être accédés dans les classes filles
int position; //position angulaire mesurée
}; //ne pas oublier le ;
////////////////////////////////////////////////////////////////////
class CStateMachineRotaryWithSpeed: public CStateMachineRotary
{
public:
CStateMachineRotaryWithSpeed(int brocheAinit, int brocheBinit);
float getSpeed(); //méthode accesseur pour accéder à l'attribut privé speed
private:
float speed; //vitesse mesurée
unsigned long lastPulseTime; //horodatage du dernier front
void frontDetecte(); //implémentation pour effectuer des traitements lorsqu'un front est detecté
};
////////////////////////////////////////////////////////////////////
//Implémentation du constructeur de la classe fille, exécutée après avoir exécuté le constructeur de la classe mère
CStateMachineRotaryWithSpeed::CStateMachineRotaryWithSpeed(int brocheAinit, int brocheBinit): CStateMachineRotary(brocheAinit, brocheBinit){
lastPulseTime=micros(); //initialisation de la date initiale pour l'horodatage des fronts
speed=0; //initialise vitesse nulle au démarrage. Attention, en simu, l'encodeur génère des fronts parasites
}
////////////////////////////////////////////////////////////////////
//implémentation de la méthode frontDetecte() qui n'était pas implémentée dans la classe mère
void CStateMachineRotaryWithSpeed::frontDetecte()
{
unsigned long newPulseTime =micros();
speed = 1000000.0/(newPulseTime-lastPulseTime);
lastPulseTime = newPulseTime;
}
//implémentation de la mesure de vitesse
float CStateMachineRotaryWithSpeed::getSpeed(){
unsigned long newTime=micros();
//TODO donner un signe à la vitesse en fonction du sens de rotation
if((newTime-lastPulseTime)>4000000)
speed=0; //vitesse=0 si mise à jour de la vitesse depuis plus de 4 secondes TODO: faire dépendre ce délai de la vitesse en cours...
return speed;
}
////////////////////////////////////////////////////////////////////
//Implémentation de la méthode constructeur
CStateMachineRotary::CStateMachineRotary(int brocheAinit, int brocheBinit){
etat = 0; //numéro de l'état actif
brocheA = A4; //numéro de broche Arduino utilisée pour l'entrée A
brocheB = A5; //numéro de broche Arduino utilisée pour l'entrée B
position = 0; //position angulaire mesurée
pinMode(brocheA, INPUT_PULLUP);
pinMode(brocheB, INPUT_PULLUP);
}
//Implémentation de la méthode clock
void CStateMachineRotary::clock(){
//actions sur transition
entreeA = digitalRead(brocheA); //valeur lue sur l'entrée A
entreeB = digitalRead(brocheB); //valeur lue sur l'entrée B
if ((etat==0) && (entreeA==1)) // passe de état0 à état1 en incrémentent position de +1
position++;
if ((etat==1) && (entreeA==0)) // passe de état1 à état0 en décrémentent position de -1
position--;
//évolution de l'état
switch (etat){
case 0: if (entreeA==1)
etat=1;
else if (entreeB==1)
etat=3;
break;
case 1: if (entreeB==1)
etat=2;
else if (entreeA==0)
etat=0;
break;
case 2: if (entreeA==0)
etat=3;
else if (entreeB==0)
etat=1;
break;
case 3:
default:
if (entreeB==0)
etat=0;
else if (entreeA==1)
etat=2;
break;
}
}
CStateMachineRotary encoder1(A4,A5);
CStateMachineRotaryWithSpeed encoder2(A0,A1);
void setup() {
Serial.begin(115200);
}
void loop() {
//lecture et mémorisation des entrées
encoder1.clock();
encoder2.clock();
//affichage de la valeur mesurée 10 fois par seconde
unsigned int periodiciteTache1=100;
static unsigned long timerTache1 = millis();
if (millis() - timerTache1 >= periodiciteTache1) {
timerTache1 += periodiciteTache1;
Serial.print(encoder1.getPosition());
Serial.print(" ");
Serial.println(encoder2.getPosition());
Serial.print(" ");
Serial.println(encoder2.getSpeed());
}
}