Rebonjour à tous,
mon projet de PN a progressé, mais je bute sur un comportement apparemment aléatoire.
Pour mémoire, je pilote un servo qui manœuvre des barrières de PN. La commande du servo fait appel à la bibliothèque SlowMotionServo de Jean-Luc qui fonctionne bien.
Un inter double (1RT, représenté par deux inter inter1 et inter2 sur deux entrées avec pull-up interne activée) pilote le mouvement des barrières. L'un des modes déclenche une séquence (bibliothèque ScheduleTable) avec : déclenchement sonnerie, 5 sec plus tard mouvement de fermeture des barrières qui dure 10 s, puis extinction sonnerie.
La sonnerie est un module externe autonome, le déclenchement et l'extinction se font par mise à la masse impulsionnelle d'une entrée (la même). J'ai installé un optocoupleur pour activer ce "contact".
Mon problème : le déclenchement de la sonnerie par le programme est aléatoire, ou en tout cas réagit à quelque chose que je ne comprends pas.
Après l'init de l'Arduino, la première commande active bien la sonnerie. Puis la sonnerie ne se déclenche plus. La commande issue de l'arduino est correcte (visualisé par une diode, on voit bien les deux impulsions de 0,5sec à chaque cycle). De même, un mise à la masse physique de l'entrée du module sonore active bien la sonnerie.
Je suspecte des problèmes de timing entre le rythme du microcontroleur du module sonore (dont je ne connais rien) et le cycle issu de l'arduino.
Quelqu'un a-t-il déjà rencontré ce genre de problème ? Toute suggestion d'analyse est bonne, merci d'avance.
/* Programme de pilotage du modulino PN37
* créé par D. Donnat - février 2016
*/
#include <ScheduleTable.h>
#include <Bounce2.h>
#include <Servo.h>
#include <SlowMotionServo.h>
// Création des objets
ScheduleTable ouvreSonne(5,18000); // Création de la table
Bounce inter1; // inter pour programme fermeture barrières avec sonnerie ; LOW pour inter activé, pullup interne au + 5V, fil gris
Bounce inter2; // inter pour programme fermeture barrières sans sonnerie ; LOW pour inter activé, pullup interne au + 5V, fil rouge
Bounce eclair; // instancie un objet bounce pour le bouton poussoir d'éclairage
SMSSmooth servoPN;
// déclaration des constantes
const byte pinServo=9; // affecte l'E/S 9 au pilotage du servo
const byte pinInter1=13; // affecte l'E/S 13 à l'inter en position 1
const byte pinInter2=12; // affecte l'E/S 12 à l'inter en position 2
const byte pinSonne=8; // affecte l'E/S 8 au pilotage de la sonnerie via optocoupleur
const byte pinLed0=3; // affecte l'E/S 3 à la led 0 lampadaire en façade
const byte pinLed1=5; // affecte l'E/S 5 à la led 1 grande salle
const byte pinLed2=6; // affecte l'E/S 6 à la led 2 petite chambre
const byte pinLed3=11; // affecte l'E/S 11 à la led 3e étage
const byte pinEclair=7; // affecte l'E/S 7 au bp cyclage éclairage
// déclaration des variables
float target = 0.0; // La cible du servo : target = 0.0 pour barrières fermées.
byte actionPN=0; // variable d'état pour le switchcase de pilotage des barrières
byte prevActionPN=0; // l'état précédent de actionPN
byte sonne=LOW; // variable utilisée pour l'impulsion de commande de la sonnerie.
// byte flagInit = 0; // flag pour sortir de la boucle d'initialisation. flagInit = 1 pour sortir ; à voir plus tard
byte memoireEclair = HIGH; // état du bouton d'éclairage au cycle précédent
byte cycleEclair; // compteur de cycle d'éclairage, de 0 à 4 ; 0 = éteint, cycles d'éclairage de 1 à 4
byte pwmLed0=255; // pour règler l'éclairement Led0 - provisoire 100 % (255)
byte pwmLed1=255; // pour règler l'éclairement Led1 - provisoire 100 % (255)
byte pwmLed2=255; // pour règler l'éclairement Led2 - provisoire 100 % (255)
byte pwmLed3=255; // pour règler l'éclairement Led3 - provisoire 100 % (255)
void pulseOn()
{
sonne=HIGH;
}
void pulseOff()
{
sonne=LOW;
}
void basculeTarget()
{
target = 1.0 - target;
}
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
servoPN.setInitialPosition(target);
servoPN.setMinMax(850, 1475);
servoPN.setPin(pinServo); /* the servo is connected to pin pinServo */
pinMode(pinInter1, INPUT_PULLUP); // déclare pinInter1 en entrée et active la résistance de pullup interne
pinMode(pinInter2, INPUT_PULLUP); // déclare pinInter2 en entrée et active la résistance de pullup interne
pinMode(pinEclair, INPUT_PULLUP); // déclare pinEclair en entrée et active la résistance de pullup interne
inter1.attach(pinInter1);
inter1.interval(10);
inter2.attach(pinInter2);
inter2.interval(10);
eclair.attach(pinEclair);
eclair.interval(10);
pinMode(pinSonne, OUTPUT); // déclare pinSonne comme sortie;
pinMode(pinLed0, OUTPUT); // déclare pinLed0 comme sortie
pinMode(pinLed1, OUTPUT); // déclare pinLed1 comme sortie
pinMode(pinLed2, OUTPUT); // déclare pinLed2 comme sortie
pinMode(pinLed3, OUTPUT); // déclare pinLed3 comme sortie
analogWrite(pinLed0, 0); // on éteint toutes les leds
analogWrite(pinLed1, 0);
analogWrite(pinLed2, 0);
analogWrite(pinLed3, 0);
// Table des événements de ouvreSonne: impulsions de 500 ms à t=500 et t = 16500, et assigne la valeur 0.0 à target à t = 5000
ouvreSonne.at(500,pulseOn);
ouvreSonne.at(1000,pulseOff);
ouvreSonne.at(5500,basculeTarget);
ouvreSonne.at(16500,pulseOn);
ouvreSonne.at(17000,pulseOff);
}
void loop() {
// put your main code here, to run repeatedly:
// les objets Bounce doivent exécuter leur code interne à chaque loop :
inter1.update();
inter2.update();
eclair.update();
// Lire la valeur des inter filtrés :
int value1 = inter1.read();
int value2 = inter2.read();
int value3 = eclair.read();
ScheduleTable::update();
SlowMotionServo::update();
// ici on calcule actionPN en fonction de inter1 et inter2
if ((value1==HIGH) && (value2==LOW))
{
actionPN=2;
}
else if ((value1==LOW) && (value2==HIGH))
{
actionPN=1;
}
else {
actionPN=0;
}
Serial.print("inter 1 : ");
Serial.print(value1);
Serial.print(" inter2 : ");
Serial.print(value2);
Serial.print(" actionPN : ");
Serial.print(actionPN);
Serial.print(" prevActionPN : ");
Serial.print(prevActionPN);
Serial.print(" Target avant : ");
Serial.print(target);
// Code pour gérer le mouvement des barrières
switch (actionPN) // début du switch case de pilotage des barrières
{
case 0: // on ouvre les barrières
if (actionPN != prevActionPN) {target = 1.0; prevActionPN=actionPN;}
break;
case 1: // on ferme les barrières avec sonnerie
if (actionPN != prevActionPN) ouvreSonne.start(1);
digitalWrite(pinSonne,sonne); // allumage d'une led qui visualise l'impulsion de déclenchement de la sonnerie
prevActionPN=actionPN;
break;
case 2: // on ferme les barrières sans sonnerie
if (actionPN != prevActionPN) {target = 0.0; prevActionPN=actionPN;}
break;
} // fin du switch case de pilotage des barrières
Serial.print(" target après : ");
Serial.print(target);
Serial.print(" Sonne : ");
Serial.println(sonne);
if (servoPN.isStopped()) {
servoPN.goTo(target);
}
// Code pour gérer les séquences d'éclairage
if ((value3 != memoireEclair) && (value3 == LOW)) cycleEclair++;
memoireEclair = value3;
if (cycleEclair > 7) cycleEclair = 0;
switch (cycleEclair) { // début du switch sur cycleEclair
case 0: // on n'allume rien
analogWrite(pinLed0, 0);
analogWrite(pinLed1, 0);
analogWrite(pinLed2, 0);
analogWrite(pinLed3, 0);
break;
case 1: // on allume Led0
analogWrite(pinLed0, pwmLed0);
break;
case 2: // on garde Led0 et on allume Led1
//analogWrite(pinLed0, 0);
analogWrite(pinLed1, pwmLed1);
break;
case 3: // on garde Led0, Led1 et on allume Led2 en plus
// analogWrite(pinLed1, 0);
analogWrite(pinLed2, pwmLed2);
break;
case 4: // on garde Led0, on éteint Led1 et on garde Led2
analogWrite(pinLed1, 0);
break;
case 5: // on gerde Led0 et Led2, on allume Led3 en plus
analogWrite(pinLed3, pwmLed3);
break;
case 6: // on garde Led0 et Led3, on éteint Led2
analogWrite(pinLed2, 0);
break;
case 7: // on garde Led1, on éteint Led3
analogWrite(pinLed3, 0);
break;
} // fin du switch sur cycleEclair
}