Hello,
I'm developping a project and encounter an issue with a block of code I tested.
I have a character table whith 20 items (0-19)
I select the item with the encoder and must display his content.
It's OK if I only display on the monitor, but when I add the output to the LCD it seems to lock. The display is OK (tested at the beginning of the sketch)
Is it possible it's due by the fact I use interrupts to read the encoder.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define pinArduinoRaccordementSignalSW 2 // La pin D2 recevra la ligne SW du module KY-040
#define pinArduinoRaccordementSignalCLK 3 // La pin D3 recevra la ligne CLK du module KY-040
#define pinArduinoRaccordementSignalDT 4 // La pin D4 la ligne DT du module KY-040
LiquidCrystal_I2C lcd(0x27,20,4);
void setup ()
{
lcd.init();
lcd.backlight();
attachInterrupt(digitalPinToInterrupt(pinArduinoRaccordementSignalCLK), changementDetecteSurLigneCLK, FALLING); // FALLING => détecte tout front descendant
attachInterrupt(digitalPinToInterrupt(pinArduinoRaccordementSignalSW), changementDetecteSurLigneSW, CHANGE); // CHANGE => détecte tout changement d'état
lcd.setCursor(0, 3);
lcd.print("test lcd"); =====> AFFICHAGE OK
void changementDetecteSurLigneCLK() {
// Lecture de la ligne DT, issue du KY-040, et arrivant sur l'arduino
int etatActuelDeLaLigneDT = digitalRead(pinArduinoRaccordementSignalDT);
int etatActuelDeLaLigneCLK = LOW;
if (etatActuelDeLaLigneCLK != etatActuelDeLaLigneDT) {
compteur++;
Serial.print(F("Sens = horaire | Valeur du compteur = "));
}
else {
compteur--;
Serial.print(F("Sens = antihoraire | Valeur du compteur = "));
}
if (compteur > (MAX_Process -1)) {
compteur = 0;
}
if (compteur < 0 ) {
compteur = MAX_Process-1;
}
POUR MON APPLICATION DOIT ETRE entre 0 et 19
Serial.println(compteur);
Serial.println(description[compteur]); ======> ELEMENT D'UN TABLEAU
OK JUSQUE LA, SI JE METS EN COMMENTAIRE LES LIGNES SUIVANTE
lcd.setCursor(0,0);=======================================\
lcd.print(description[index]);============================/ N'AFFICHE RIEN ET BLOQUE LE PROCESS
}
/*
* minuterie exposition tubes uv pour procédés photographique
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define pinArduinoRaccordementSignalSW 2 // La pin D2 de l'Arduino recevra la ligne SW du module KY-040
#define pinArduinoRaccordementSignalCLK 3 // La pin D3 de l'Arduino recevra la ligne CLK du module KY-040
#define pinArduinoRaccordementSignalDT 4 // La pin D4 de l'Arduino recevra la ligne D
#define MAX_Process 20 // nombre de procédés différents
int Program_index = 0 ;
char description [20][35] = {"Cyanotype", "Van Dijck Brown",
"Gomme bichromatée", "Puretch trame", "Puretch image","Tok solar trame",
"Tok solar image","Film ..... trame", "Film ...... image",
"Plaque verte trame", "Plaque verte image","12","13","14","15","16","17","18","19","20"
}; // nom du procédé
int exposition6 [20] = {101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119}; //exposition led 625nm en secondes
int exposition8 [20] = {21,22,3,14,125,16,37,18,109,10,21,32,43,74,65,26,77,48,29}; //exposition led 815nm en secondes
// Variables
int etatPrecedentLigneSW; // Cette variable nous permettra de stocker le dernier état de la ligne SW, afin de le comparer à l'actuel
int compteur = 0; // Cette variable nous permettra de compter combien de crans ont été parcourus, sur l'encodeur
// (sachant que nous compterons dans le sens horaire, et décompterons dans le sens antihoraire)
LiquidCrystal_I2C lcd(0x27,20,4);
void setup ()
{
lcd.init();
lcd.backlight();
pinMode(pinArduinoRaccordementSignalSW, INPUT);
pinMode(pinArduinoRaccordementSignalDT, INPUT);
pinMode(pinArduinoRaccordementSignalCLK, INPUT);
Serial.begin(9600); // test à supprimer
Serial.println(F("==========================================================================")); //test à supprimer
Serial.println(F(" interruptions Arduino INT0 et INT1, avec affichage du nombre de")); //test à supprimer
Serial.println(F(" crans parcourus sur l'encodeur, ainsi que le sens de rotation)")); //test à supprimer
Serial.println(F("=========================================================================")); //test à supprimer
Serial.println(F("=========================================================================")); //test à supprimer
Serial.println(F("=========================================================================")); //test à supprimer
Serial.println(""); //test à supprimer
delay(200);
// Mémorisation de la valeur initiale de la ligne SW, au démarrage du programme
etatPrecedentLigneSW = digitalRead(pinArduinoRaccordementSignalSW);
// Affichage de la valeur initiale du compteur, sur le moniteur série
Serial.print(F("Valeur initiale du compteur = ")); //test à supprimer
Serial.println(compteur); //test à supprimer
attachInterrupt(digitalPinToInterrupt(pinArduinoRaccordementSignalCLK), changementDetecteSurLigneCLK, FALLING); // FALLING => détecte tout front descendant
attachInterrupt(digitalPinToInterrupt(pinArduinoRaccordementSignalSW), changementDetecteSurLigneSW, CHANGE); // CHANGE => détecte tout changement d'état
lcd.setCursor(0, 3);
lcd.print("test lcd");
}
void loop() {
// put your main code here, to run repeatedly:
// POUR PREMIERS TESTS
}
void eff_ligne (int ligne)
{
lcd.setCursor(0,ligne-1);
lcd.print( " ");
}
void affiche_lcd(int index) {
LiquidCrystal_I2C lcd(0x27,20,4);
lcd.init();
lcd.backlight();
eff_ligne(1);
eff_ligne(2);
eff_ligne(3);
lcd.setCursor(0,0);
lcd.print(description[index]);
}
void changementDetecteSurLigneCLK() {
// Lecture de la ligne DT, issue du KY-040, et arrivant sur l'arduino
int etatActuelDeLaLigneDT = digitalRead(pinArduinoRaccordementSignalDT);
int etatActuelDeLaLigneCLK = LOW;
// Nota : ici, la ligne CLK est forcément au niveau bas (0V), du fait qu'on entre dans cette routine
// que sur front descendant de CLK (donc passage de 1 à 0)
// On compare ensuite l'état des lignes CLK et DT
// ----------------------------------------------
// Nota : - si CLK est différent de DT, alors cela signifie que nous avons tourné l'encodeur dans le sens horaire
// - si CLK est égal à DT, alors cela signifie que nous avons tourné l'encodeur dans le sens antihoraire
if(etatActuelDeLaLigneCLK != etatActuelDeLaLigneDT) {
// CLK différent de DT => cela veut dire que nous tournons dans le sens horaire
// Alors on incrémente le compteur
compteur++;
// Et on affiche ces infos sur le moniteur série
Serial.print(F("Sens = horaire | Valeur du compteur = "));
// Serial.println(compteur);
}
else {
// CLK est identique à DT => cela veut dire que nous tournons dans le sens antihoraire
// Alors on décrémente le compteur
compteur--;
// Et on affiche ces infos sur le moniteur série
Serial.print(F("Sens = antihoraire | Valeur du compteur = "));
}
if (compteur > (MAX_Process -1)) {
compteur = 0;
}
if (compteur < 0 ) {
compteur = MAX_Process-1;
}
Serial.println(compteur);
Serial.println(description[compteur]);
// affiche_lcd(compteur);
}
// ====================================================
// Routine d'interruption : changementDetecteSurLigneSW
// ====================================================
void changementDetecteSurLigneSW() {
// On lit le nouvel état de la ligne SW
int etatActuelDeLaLigneSW = digitalRead(pinArduinoRaccordementSignalSW);
// On mémorise le nouvel état de la ligne SW, puisqu'il vient de changer (sans quoi nous ne serions pas dans cette routine d'interruption)
etatPrecedentLigneSW = etatActuelDeLaLigneSW;
// Puis on affiche le nouvel état de SW sur le moniteur série de l'IDE Arduino
if(etatActuelDeLaLigneSW == LOW)
Serial.println(F("Bouton SW appuyé"));
else
Serial.println(F("Bouton SW relâché"));
}
// Nota : en pratique, sans "filtre anti-rebond", vous noterez qu'il y a parfois pas mal de comptes/décomptes non souhaités, en l'état
P.S.: I tried different version moving the lcd.print in a function, but it's the same.
void affiche_lcd(int index) {
/// no need LiquidCrystal_I2C lcd(0x27,20,4);
/// done in setup once lcd.init();
The other problem seems to have something to do with using the LCD within the ISR maybe.
// I added a global variable
volatile signed char kludgeIndex = -1;
// ... and put these service lines in your loop
void loop() {
if (kludgeIndex >= 0) {
affiche_lcd(kludgeIndex);
kludgeIndex = -1;
}
}
//... then where you called affiche_lcd() just set the kludgeIndex so it would be handled later in the loop:
Serial.println(compteur);
Serial.println(description[compteur]);
kludgeIndex = compteur;
It is genearlly advised not to do too much work in the ISR. Printing was once problematic. Usually we recommend the ISR do nothing but set flags to be noticed and acted upon in the main code.
Of course its different for a rotary encoder ISR. Buty it should just increment or decrement some counter we all look at to decide what or whether do. anything.
The other solution, which is unorthodox, is to enable the interrupts inside the ISR, as long as you keep it short enough :
/*
minuterie exposition tubes uv pour procédés photographique
*/
// #include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define pinArduinoRaccordementSignalSW 2 // La pin D2 de l'Arduino recevra la ligne SW du module KY-040
#define pinArduinoRaccordementSignalCLK 3 // La pin D3 de l'Arduino recevra la ligne CLK du module KY-040
#define pinArduinoRaccordementSignalDT 4 // La pin D4 de l'Arduino recevra la ligne D
#define MAX_Process 20 // nombre de procédés différents
int Program_index = 0 ;
char description [20][35] = {"Cyanotype", "Van Dijck Brown",
"Gomme bichromatée", "Puretch trame", "Puretch image", "Tok solar trame",
"Tok solar image", "Film ..... trame", "Film ...... image",
"Plaque verte trame", "Plaque verte image", "12", "13", "14", "15", "16", "17", "18", "19", "20"
}; // nom du procédé
int exposition6 [20] = {101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119}; //exposition led 625nm en secondes
int exposition8 [20] = {21, 22, 3, 14, 125, 16, 37, 18, 109, 10, 21, 32, 43, 74, 65, 26, 77, 48, 29}; //exposition led 815nm en secondes
// Variables
int etatPrecedentLigneSW; // Cette variable nous permettra de stocker le dernier état de la ligne SW, afin de le comparer à l'actuel
int compteur = 0; // Cette variable nous permettra de compter combien de crans ont été parcourus, sur l'encodeur
// (sachant que nous compterons dans le sens horaire, et décompterons dans le sens antihoraire)
LiquidCrystal_I2C lcd(0x27, 20, 4);
void setup ()
{
lcd.init();
lcd.backlight();
pinMode(pinArduinoRaccordementSignalSW, INPUT);
pinMode(pinArduinoRaccordementSignalDT, INPUT);
pinMode(pinArduinoRaccordementSignalCLK, INPUT);
Serial.begin(115200); // test à supprimer
Serial.println(F("==========================================================================")); //test à supprimer
Serial.println(F(" interruptions Arduino INT0 et INT1, avec affichage du nombre de")); //test à supprimer
Serial.println(F(" crans parcourus sur l'encodeur, ainsi que le sens de rotation)")); //test à supprimer
Serial.println(F("=========================================================================")); //test à supprimer
Serial.println(F("=========================================================================")); //test à supprimer
Serial.println(F("=========================================================================")); //test à supprimer
Serial.println(""); //test à supprimer
delay(200);
// Mémorisation de la valeur initiale de la ligne SW, au démarrage du programme
etatPrecedentLigneSW = digitalRead(pinArduinoRaccordementSignalSW);
// Affichage de la valeur initiale du compteur, sur le moniteur série
Serial.print(F("Valeur initiale du compteur = ")); //test à supprimer
Serial.println(compteur); //test à supprimer
attachInterrupt(digitalPinToInterrupt(pinArduinoRaccordementSignalCLK), changementDetecteSurLigneCLK, FALLING); // FALLING => détecte tout front descendant
attachInterrupt(digitalPinToInterrupt(pinArduinoRaccordementSignalSW), changementDetecteSurLigneSW, CHANGE); // CHANGE => détecte tout changement d'état
lcd.setCursor(0, 3);
lcd.print("test lcd");
}
void loop() {
// put your main code here, to run repeatedly:
// POUR PREMIERS TESTS
}
void eff_ligne (int ligne)
{
lcd.setCursor(0, ligne - 1);
lcd.print( " ");
}
void affiche_lcd(int index) {
eff_ligne(1);
eff_ligne(2);
eff_ligne(3);
lcd.setCursor(0, 0);
lcd.print(description[index]);
}
void changementDetecteSurLigneCLK() {
// Lecture de la ligne DT, issue du KY-040, et arrivant sur l'arduino
int etatActuelDeLaLigneDT = digitalRead(pinArduinoRaccordementSignalDT);
int etatActuelDeLaLigneCLK = LOW;
// Nota : ici, la ligne CLK est forcément au niveau bas (0V), du fait qu'on entre dans cette routine
// que sur front descendant de CLK (donc passage de 1 à 0)
// On compare ensuite l'état des lignes CLK et DT
// ----------------------------------------------
// Nota : - si CLK est différent de DT, alors cela signifie que nous avons tourné l'encodeur dans le sens horaire
// - si CLK est égal à DT, alors cela signifie que nous avons tourné l'encodeur dans le sens antihoraire
if (etatActuelDeLaLigneCLK != etatActuelDeLaLigneDT) {
// CLK différent de DT => cela veut dire que nous tournons dans le sens horaire
// Alors on incrémente le compteur
compteur++;
if (compteur > (MAX_Process - 1)) {
compteur = 0;
}
// Et on affiche ces infos sur le moniteur série
interrupts();
Serial.print(F("Sens = horaire | Valeur du compteur = "));
}
else {
// CLK est identique à DT => cela veut dire que nous tournons dans le sens antihoraire
// Alors on décrémente le compteur
compteur--;
if (compteur < 0 ) {
compteur = MAX_Process - 1;
}
// Et on affiche ces infos sur le moniteur série
interrupts();
Serial.print(F("Sens = antihoraire | Valeur du compteur = "));
}
Serial.println(compteur);
Serial.println(description[compteur]);
affiche_lcd(compteur);
}
// ====================================================
// Routine d'interruption : changementDetecteSurLigneSW
// ====================================================
void changementDetecteSurLigneSW() {
// On lit le nouvel état de la ligne SW
int etatActuelDeLaLigneSW = digitalRead(pinArduinoRaccordementSignalSW);
// On mémorise le nouvel état de la ligne SW, puisqu'il vient de changer (sans quoi nous ne serions pas dans cette routine d'interruption)
etatPrecedentLigneSW = etatActuelDeLaLigneSW;
// Puis on affiche le nouvel état de SW sur le moniteur série de l'IDE Arduino
interrupts();
if (etatActuelDeLaLigneSW == LOW)
Serial.println(F("Bouton SW appuyé"));
else
Serial.println(F("Bouton SW relâché"));
}
// Nota : en pratique, sans "filtre anti-rebond", vous noterez qu'il y a parfois pas mal de comptes/décomptes non souhaités, en l'état
Yes! The problem is exactly that interrupts are off in the ISR. I realized that when I was brushing my cat's teeth.
The solution of turning them on briefly is unorthodox, and although it appears to work is def not the recommended manner to deal with a this kind of thing.
The "set flags in the interrupt" and "do stuff because flags in the main loop" is a good pattern to follow for ISRs.
Some ISRs are naturally where the work should be done. In general, printing and by extension publishing to an LCD is prolly stuff anyone should figure out a better way to handle. Again in general those ISRs are coded to take a minimal amount of time.
Note that using interrupts and flags may mean you need to keep your loop running free. I had a blank loop to play with, my service lines were being execute thousands of ties a second usually doing nothing.
There are ways to make this work, but often it is a recipe for disaster.
Another big issue with re-enabling interrupts in an ISR is reentrancy.
Normally and ISR is not re-entered, but if you re-enable interrupts in the ISR there is the possibility that the same interrupt occurs and the ISR is re-entered.
This can cause all kinds of issues that can be difficult to resolve.
About the LCD, no you can't ever print to the LCD in an ISR since it uses the WIRE library and the WIRE library needs interrupts to function. If interrupts are disabled when you try to send something over the i2c interface, the code in WIRE will hang.
I also would suggest not printing out the serial port from the ISR either.
While it "works" it can cause interrupts to be masked for along period.
This is because HardwareSerial detects when interrupts are blocked and starts polling the h/w vs buffering it for interrupts to drain.
Depending on the baud rate and the length of the message this can keep the processor in the ISR for quite some time, which means that interrupts are masked for quite some time.
After all modifications, I see a problem (not noticed before ). I have to push 2 times on the switch to start.
Here is the complete sketch:
/*
* minuterie exposition tubes uv pour procédés photographique
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define pinArduinoRaccordementSignalSW 2 // La pin D2 de l'Arduino recevra la ligne SW du module KY-040
#define pinArduinoRaccordementSignalCLK 3 // La pin D3 de l'Arduino recevra la ligne CLK du module KY-040
#define pinArduinoRaccordementSignalDT 4 // La pin D4 de l'Arduino recevra la ligne D
#define uvc61 5 // relais pour les leds UV 650 nm
#define uvc62 6
#define uvc63 7
#define uvc64 8
#define uvc81 9 // relais pour les leds UV 810 nm
#define uvc82 10
#define uvc83 11
#define uvc84 12
#define MAX_Process 20 // nombre de procédés différents
char description [20][35] = {
"Cyanotype", "Van Dijck Brown", "Gomme bichromatee", "Puretch trame",
"Puretch image","Tok solar trame","Tok solar image", "Film ..... trame",
"Film ...... image", "Plaque verte trame", "Plaque verte image", "essai_6 5 sec",
"essai_6 10 sec","essai_6 20 sec","essai_6 40 sec", "essai_6 80 sec",
"essai_8 5 sec","essai_8 10 sec","essai_8 20 sec","essai_8 40 sec"
}; // nom du procédé
int exposition6 [20] = {
101,102,103,104,
105,106,107,108,
109,110,15,5,
10,20,40,80,
0,0,0,0
}; //exposition led 625nm en secondes
int exposition8 [20] = {
21,22,3,14,
125,16,37,18,
109,10,8,0,
0,0,0,0,
5,10,20,40
}; //exposition led 815nm en secondes
int Program_index = 0 ;
bool changeindex = 0;
int Expose=0;
int etatPrecedentLigneSW; // Cette variable nous permettra de stocker le dernier état de la ligne SW, afin de le comparer à l'actuel
int compteur = 0; // Cette variable nous permettra de compter combien de crans ont été parcourus, sur l'encodeur
int Exp6 = 0; //temps exposition 650 nm
int Exp8 = 0; //temps exposition 810 nm
bool Stop6 = 0; //fin exposition 650 nm
bool Stop8 = 0; //fin exposition 810 nm // (sachant que nous compterons dans le sens horaire, et décompterons dans le sens antihoraire)
LiquidCrystal_I2C lcd(0x27,20,4);
void setup ()
{
lcd.init();
lcd.backlight();
pinMode(pinArduinoRaccordementSignalSW, INPUT);
pinMode(pinArduinoRaccordementSignalDT, INPUT);
pinMode(pinArduinoRaccordementSignalCLK, INPUT);
pinMode(uvc61, OUTPUT);
pinMode(uvc62, OUTPUT);
pinMode(uvc63, OUTPUT);
pinMode(uvc64, OUTPUT);
pinMode(uvc81, OUTPUT);
pinMode(uvc82, OUTPUT);
pinMode(uvc83, OUTPUT);
pinMode(uvc84, OUTPUT);
digitalWrite(uvc61,LOW);
digitalWrite(uvc62,LOW);
digitalWrite(uvc63,LOW);
digitalWrite(uvc64,LOW);
digitalWrite(uvc81,LOW);
digitalWrite(uvc82,LOW);
digitalWrite(uvc83,LOW);
digitalWrite(uvc84,LOW);
delay (250);
Serial.begin(9600);
// Mémorisation de la valeur initiale de la ligne SW, au démarrage du programme
etatPrecedentLigneSW = digitalRead(pinArduinoRaccordementSignalSW);
attachInterrupt(digitalPinToInterrupt(pinArduinoRaccordementSignalCLK), changementDetecteSurLigneCLK, FALLING); // FALLING => détecte tout front descendant
attachInterrupt(digitalPinToInterrupt(pinArduinoRaccordementSignalSW), changementDetecteSurLigneSW, CHANGE); // CHANGE => détecte tout changement d'état
lcd.setCursor(0,0);
lcd.print(" BOX EXPOSITION UV");
affiche_lcd(0);
}
void loop()
{
if (changeindex == 1)
{
affiche_lcd(compteur);
changeindex = 0;
}
if (Expose == 1)
{
if (Exp6 > 0)
{
Allume650();
Exp6 --;
}
else
Eteint650();
if (Exp8 > 0)
{
Allume810();
Exp8 --;
}
else
Eteint810();
Serial.print(F("Exp6 "));
Serial.print(Exp6);
Serial.print(F(" Exp8 "));
Serial.println(Exp8);
delay(100);
}
if (Exp6 == 0 && Exp8 == 0)
{
Eteint650();
Eteint810();
Expose=0;
}
}
void eff_ligne (int ligne)
{
lcd.setCursor(0,ligne-1);
lcd.print( " ");
}
void affiche_lcd(int index) {
eff_ligne(2);
eff_ligne(3);
eff_ligne(4);
lcd.setCursor(0,1);
lcd.print(description[index]);
lcd.setCursor (0,2);
lcd.print(exposition6[index]);
lcd.setCursor (0,3);
lcd.print(exposition8[index]);
}
void changementDetecteSurLigneCLK() {
// Lecture de la ligne DT, issue du KY-040, et arrivant sur l'arduino
int etatActuelDeLaLigneDT = digitalRead(pinArduinoRaccordementSignalDT);
int etatActuelDeLaLigneCLK = LOW;
// Nota : ici, la ligne CLK est forcément au niveau bas (0V), du fait qu'on entre dans cette routine
// que sur front descendant de CLK (donc passage de 1 à 0)
// On compare ensuite l'état des lignes CLK et DT
// ----------------------------------------------
// Nota : - si CLK est différent de DT, alors cela signifie que nous avons tourné l'encodeur dans le sens horaire
// - si CLK est égal à DT, alors cela signifie que nous avons tourné l'encodeur dans le sens antihoraire
if(etatActuelDeLaLigneCLK != etatActuelDeLaLigneDT) {
// CLK différent de DT => cela veut dire que nous tournons dans le sens horaire
// Alors on incrémente le compteur
compteur++;
}
else {
// CLK est identique à DT => cela veut dire que nous tournons dans le sens antihoraire
// Alors on décrémente le compteur
compteur--;
}
if (compteur > (MAX_Process -1)) {
compteur = 0;
}
if (compteur < 0 ) {
compteur = MAX_Process-1;
}
changeindex=true;
}
// ====================================================
// Routine d'interruption : changementDetecteSurLigneSW
// ====================================================
void changementDetecteSurLigneSW() {
// On lit le nouvel état de la ligne SW
int etatActuelDeLaLigneSW = digitalRead(pinArduinoRaccordementSignalSW);
// On mémorise le nouvel état de la ligne SW, puisqu'il vient de changer (sans quoi nous ne serions pas dans cette routine d'interruption)
etatPrecedentLigneSW = etatActuelDeLaLigneSW;
// Puis on affiche le nouvel état de SW sur le moniteur série de l'IDE Arduino
if(etatActuelDeLaLigneSW == LOW)
Expose = 1;
Exp6 = exposition6[compteur];
Exp8 = exposition8[compteur];
}
// Nota : en pratique, sans "filtre anti-rebond", vous noterez qu'il y a parfois pas mal de comptes/décomptes non souhaités, en l'état
void Allume650()
{
digitalWrite(uvc61,HIGH);
digitalWrite(uvc62,HIGH);
digitalWrite(uvc63,HIGH);
digitalWrite(uvc64,HIGH);
}
void Eteint650()
{
digitalWrite(uvc61,LOW);
digitalWrite(uvc62,LOW);
digitalWrite(uvc63,LOW);
digitalWrite(uvc64,LOW);
}
void Allume810()
{
digitalWrite(uvc81,HIGH);
digitalWrite(uvc82,HIGH);
digitalWrite(uvc83,HIGH);
digitalWrite(uvc84,HIGH);
}
void Eteint810()
{
digitalWrite(uvc81,LOW);
digitalWrite(uvc82,LOW);
digitalWrite(uvc83,LOW);
digitalWrite(uvc84,LOW);
}
delay in loop must be 1000 (1sec), but for test, I lower it to 100, so I don't have to wait to much
Why do you trigger an interrupt on CHANGE for pinArduinoRaccordementSignalSW ? FALLING (if pulled-up) seems more appropriate. etatPrecedentLigneSW is not used...
The indentation makes you think all three instructions will be executed only when etatActuelDeLaLigneSW == LOW but if you ask your IDE to format the code (ctrl+T with Arduino IDE 2), you'll notice the mistake even though the ISR works well...
But the culprit could be pinArduinoRaccordementSignalSW which is not pulled-up (internally at least).
Here are the modifications I made:
/*
minuterie exposition tubes uv pour procédés photographique
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define pinArduinoRaccordementSignalSW 2 // La pin D2 de l'Arduino recevra la ligne SW du module KY-040
#define pinArduinoRaccordementSignalCLK 3 // La pin D3 de l'Arduino recevra la ligne CLK du module KY-040
#define pinArduinoRaccordementSignalDT 4 // La pin D4 de l'Arduino recevra la ligne D
#define uvc61 5 // relais pour les leds UV 650 nm
#define uvc62 6
#define uvc63 7
#define uvc64 8
#define uvc81 9 // relais pour les leds UV 810 nm
#define uvc82 10
#define uvc83 11
#define uvc84 12
#define MAX_Process 20 // nombre de procédés différents
char description [20][35] = {
"Cyanotype", "Van Dijck Brown", "Gomme bichromatee", "Puretch trame",
"Puretch image", "Tok solar trame", "Tok solar image", "Film ..... trame",
"Film ...... image", "Plaque verte trame", "Plaque verte image", "essai_6 5 sec",
"essai_6 10 sec", "essai_6 20 sec", "essai_6 40 sec", "essai_6 80 sec",
"essai_8 5 sec", "essai_8 10 sec", "essai_8 20 sec", "essai_8 40 sec"
}; // nom du procédé
int exposition6 [20] = {
101, 102, 103, 104,
105, 106, 107, 108,
109, 110, 15, 5,
10, 20, 40, 80,
0, 0, 0, 0
}; //exposition led 625nm en secondes
int exposition8 [20] = {
21, 22, 3, 14,
125, 16, 37, 18,
109, 10, 8, 0,
0, 0, 0, 0,
5, 10, 20, 40
}; //exposition led 815nm en secondes
int Program_index = 0 ;
bool changeindex = 0;
int Expose = 0;
// int etatPrecedentLigneSW; // Cette variable nous permettra de stocker le dernier état de la ligne SW, afin de le comparer à l'actuel
int typeDexposition = 0; // Cette variable nous permettra de compter combien de crans ont été parcourus, sur l'encodeur
int Exp6 = 0; //temps exposition 650 nm
int Exp8 = 0; //temps exposition 810 nm
bool Stop6 = 0; //fin exposition 650 nm
bool Stop8 = 0; //fin exposition 810 nm // (sachant que nous compterons dans le sens horaire, et décompterons dans le sens antihoraire)
LiquidCrystal_I2C lcd(0x27, 20, 4);
void setup ()
{
Serial.begin(115200);
lcd.init();
lcd.backlight();
pinMode(pinArduinoRaccordementSignalSW, INPUT_PULLUP);
pinMode(pinArduinoRaccordementSignalDT, INPUT);
pinMode(pinArduinoRaccordementSignalCLK, INPUT);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(uvc61, OUTPUT);
pinMode(uvc62, OUTPUT);
pinMode(uvc63, OUTPUT);
pinMode(uvc64, OUTPUT);
pinMode(uvc81, OUTPUT);
pinMode(uvc82, OUTPUT);
pinMode(uvc83, OUTPUT);
pinMode(uvc84, OUTPUT);
digitalWrite(uvc61, LOW);
digitalWrite(uvc62, LOW);
digitalWrite(uvc63, LOW);
digitalWrite(uvc64, LOW);
digitalWrite(uvc81, LOW);
digitalWrite(uvc82, LOW);
digitalWrite(uvc83, LOW);
digitalWrite(uvc84, LOW);
delay (250);
// Mémorisation de la valeur initiale de la ligne SW, au démarrage du programme
// etatPrecedentLigneSW = digitalRead(pinArduinoRaccordementSignalSW);
attachInterrupt(digitalPinToInterrupt(pinArduinoRaccordementSignalCLK), changementDetecteSurLigneCLK, FALLING); // FALLING => détecte tout front descendant
attachInterrupt(digitalPinToInterrupt(pinArduinoRaccordementSignalSW), changementDetecteSurLigneSW, FALLING); // CHANGE => détecte tout changement d'état
lcd.setCursor(0, 0);
lcd.print(" BOX EXPOSITION UV");
affiche_lcd(0);
}
void loop()
{
if (changeindex == 1)
{
affiche_lcd(typeDexposition);
changeindex = 0;
}
if (Expose == 1)
{
if (Exp6 > 0)
{
Allume650();
Exp6 --;
}
else
Eteint650();
if (Exp8 > 0)
{
Allume810();
Exp8 --;
}
else
Eteint810();
Serial.print(F("Exp6 "));
Serial.print(Exp6);
Serial.print(F(" Exp8 "));
Serial.println(Exp8);
delay(100);
}
if (Exp6 == 0 && Exp8 == 0)
{
// Eteint650();
// Eteint810();
Expose = 0;
digitalWrite(LED_BUILTIN, LOW);
}
}
void eff_ligne (int ligne)
{
lcd.setCursor(0, ligne - 1);
lcd.print( " ");
}
void affiche_lcd(int index) {
eff_ligne(2);
eff_ligne(3);
eff_ligne(4);
lcd.setCursor(0, 1);
lcd.print(description[index]);
lcd.setCursor (0, 2);
lcd.print(exposition6[index]);
lcd.setCursor (0, 3);
lcd.print(exposition8[index]);
}
void changementDetecteSurLigneCLK() {
// Lecture de la ligne DT, issue du KY-040, et arrivant sur l'arduino
int etatActuelDeLaLigneDT = digitalRead(pinArduinoRaccordementSignalDT);
int etatActuelDeLaLigneCLK = LOW;
// Nota : ici, la ligne CLK est forcément au niveau bas (0V), du fait qu'on entre dans cette routine
// que sur front descendant de CLK (donc passage de 1 à 0)
// On compare ensuite l'état des lignes CLK et DT
// ----------------------------------------------
// Nota : - si CLK est différent de DT, alors cela signifie que nous avons tourné l'encodeur dans le sens horaire
// - si CLK est égal à DT, alors cela signifie que nous avons tourné l'encodeur dans le sens antihoraire
if (etatActuelDeLaLigneCLK != etatActuelDeLaLigneDT) {
// CLK différent de DT => cela veut dire que nous tournons dans le sens horaire
// Alors on incrémente le typeDexposition
typeDexposition++;
if (typeDexposition > (MAX_Process - 1)) {
typeDexposition = 0;
}
}
else {
// CLK est identique à DT => cela veut dire que nous tournons dans le sens antihoraire
// Alors on décrémente le typeDexposition
typeDexposition--;
if (typeDexposition < 0 ) {
typeDexposition = MAX_Process - 1;
}
}
changeindex = true;
}
// ====================================================
// Routine d'interruption : changementDetecteSurLigneSW
// ====================================================
void changementDetecteSurLigneSW() {
// On lit le nouvel état de la ligne SW
// int etatActuelDeLaLigneSW = digitalRead(pinArduinoRaccordementSignalSW);
// On mémorise le nouvel état de la ligne SW, puisqu'il vient de changer (sans quoi nous ne serions pas dans cette routine d'interruption)
// etatPrecedentLigneSW = etatActuelDeLaLigneSW;
// Puis on affiche le nouvel état de SW sur le moniteur série de l'IDE Arduino
// if (etatActuelDeLaLigneSW == LOW)
Expose = 1;
Exp6 = exposition6[typeDexposition];
Exp8 = exposition8[typeDexposition];
digitalWrite(LED_BUILTIN, HIGH);
}
// Nota : en pratique, sans "filtre anti-rebond", vous noterez qu'il y a parfois pas mal de comptes/décomptes non souhaités, en l'état
void Allume650()
{
digitalWrite(uvc61, HIGH);
digitalWrite(uvc62, HIGH);
digitalWrite(uvc63, HIGH);
digitalWrite(uvc64, HIGH);
}
void Eteint650()
{
digitalWrite(uvc61, LOW);
digitalWrite(uvc62, LOW);
digitalWrite(uvc63, LOW);
digitalWrite(uvc64, LOW);
}
void Allume810()
{
digitalWrite(uvc81, HIGH);
digitalWrite(uvc82, HIGH);
digitalWrite(uvc83, HIGH);
digitalWrite(uvc84, HIGH);
}
void Eteint810()
{
digitalWrite(uvc81, LOW);
digitalWrite(uvc82, LOW);
digitalWrite(uvc83, LOW);
digitalWrite(uvc84, LOW);
}