Je viens de finir un bout de code qui réalise dans une boucle loop :
lecture clavier 4x4 et affichage valeur dans serial moniteur.
lecture DS1820 et affichage sur LCD 128*4
Cela marche mais la lecture du clavier manque de réactivité (je dois garder la touche appuyée 1sec) à cause du sleep (1000) se trouvant dans la partie lecture DS1820.
Sachant que la séquence de lecture du DS1820 ne doit pas être interrompue, comment pourrais-je améliorer la réactivité de lecture du clavier ?
milli() est bien sûr la première optimisation à faire.
Néanmoins, à terme mon code devra à la fois (en tâches principales) :
interpréter les commandes du clavier.
lire la température de 1 ou 2 capteurs DS1820
communiquer via CAN ou RS485 vers d'autres cartes.
Donc je m'interroge sur l'organisation de mon code, car les séquences de
lecture OneWire et lecture/écriture RS485 ne doivent pas être interrompues.
En même temps, je dois garder une réactivité du clavier.
Sur mon ancien µ Motorola, je bouclais en continue sur une lecture clavier,
et je lançais régulièrement des routines de scrutation des entrées via la RTI
(toutes les xx ms).
Avec la durée de lecture DS1820 et RS485, je suis un peu perdu...
Mon code pas optimisé du tout :-[
void loop()
{
//---------------------------------------------------------------------------//
// ONEWIRE DS1820 read
byte i, sensor;
byte present = 0;
byte data[12];
for (sensor=0;sensor<MAX_DS1820_SENSORS;sensor++)
{
if ( OneWire::crc8( addr[sensor], 7) != addr[sensor][7])
{
GLCD.GotoXY(60, 40);
GLCD.Puts("CRC is not valid"); // print a text string
return;
}
if ( addr[sensor][0] != 0x10)
{
GLCD.GotoXY(60, 40);
GLCD.Puts("Device is not a DS18S20 family device."); // print a text string
return;
}
ds.reset();
ds.select(addr[sensor]);
ds.write(0x44,1); // start conversion, with parasite power on at the end
delay(1000); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.
present = ds.reset();
ds.select(addr[sensor]);
ds.write(0xBE); // Read Scratchpad
for ( i = 0; i < 9; i++)
{ // we need 9 bytes
data[i] = ds.read();
}
LowByte = data[0];
HighByte = data[1];
TReading = (HighByte << 8) + LowByte;
SignBit = TReading & 0x8000; // test most sig bit
if (SignBit) // negative
{
TReading = (TReading ^ 0xffff) + 1; // 2's comp
}
Tc_100 = (TReading*100/2);
Whole = Tc_100 / 100; // separate off the whole and fractional portions
Fract = Tc_100 % 100;
// sprintf(buf, "%d:%c%d.%d\337C",sensor,SignBit ? '-' : '+', Whole, Fract < 10 ? 0 : Fract);
sprintf(buf, "%c%d.%d\337",SignBit ? '-' : '+', Whole, Fract/10);
//---------------------------------------------------------------------------//
// DISPLAY DS1820 temp
GLCD.CursorToXY(40, 40);
GLCD.Puts("T= "); // print a text string
GLCD.Puts(buf); // print a number
GLCD.CursorToXY(94, 40);
GLCD.Puts("C");
}
//---------------------------------------------------------------------------//
// KEYPAD read
char customKey = customKeypad.getKey();
if (customKey != NO_KEY){
Serial.println(customKey);
}
}
Ce que j'ai compris :
au lieu de boucler bêtement pendant 1 sec, je surveille la valeur d'un timer.
Là ou je coince :
Tant que le timer n'est pas à "1 sec", que fait mon programme principal ? Si je reboucle sur le début, il va une nouvelle fois lancer une interrogation du capteur ds1820 alors que la précédente est en cours... Que dois-je faire ?
Ainsi si ta boucle est faite plus rapidement que la fréquence désirée pour tes mesures sur le DS1820, une boucle est refaite sans lecture de ton capteur.
@Gozaki,
A tester aussi autour de cela je suppose :
void InterruptTimer()
Reste à clarifier ce que je mets dans la boucle principale et dans l'interruption.
@Jean-François,
Très instructif cette page du siteduzero !
Encore un point que je n'arrive pas à saisir, la première partie du code avant la pause d'1 sec :
J'adresse le DS1820
Je compare la valeur du temps avec millis().
Si je n'ai pas encore 1000, je continue.
Je passe par la lecture clavier (parfait, je n'ai plus la latence de 1sec).
Mais je reviens au début du code. Il faut donc un flag qui m'empêche de redérouler le début du code.
Sinon je relance encore un adressage ds1820. Est-ce bien cela ?
boolean lecture = true;
void looop(){
if (lecture=true){
lit le DS1820;
lecture = false;
}
if (si la boucle est supérieur à 1000){
fait la fonction keypad;
lecture = true ;
}
}
Je me suis repenché sur ce bout de code, mais dès que j'applique ma
première modif, le DS1820 n'affiche plus la température.
Explications de ce que je fais :
Le sous programme est appelé régulièrement dans ma boucle loop.
Au démarrage du code, je mets le flag "lecture_en_cours" à false.
La modification de la première partie du code (activation des 3 lignes
précédées de // pose pb : plus de lecture du DS1820. Pourtant je n'ai
pas encore modifié la second partie du code (remplacement de delay
par les deux ligne du dessous.
Pourriez-vous m'aider à comprendre ce qui coince ?
Merci.
void Ds1820Capture(void)
{
unsigned long currentMillis = millis();
int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract;
char buf[20];
byte i, sensor; byte present = 0; byte data[12];
////////// 1/2 : Adressage / demande de mesure
// if (lecture_en_cours == false)
// {
for (sensor=0;sensor<MAX_DS1820_SENSORS;sensor++)
{
if ( OneWire::crc8( addr[sensor], 7) != addr[sensor][7])
{ GLCD.GotoXY(60, 40); GLCD.Puts("CRC is not valid"); return; }
if ( addr[sensor][0] != 0x10)
{ GLCD.GotoXY(60, 40); GLCD.Puts("Device is not a DS18S20 family device."); return; }
ds.reset(); ds.select(addr[sensor]); ds.write(0x44,1); // start conversion, with parasite power on at the end
lecture_en_cours = true;
// }
////////// 2/2 : Après 1 seconde d'attente, lecture scratchpad
delay(1000);
//if(currentMillis - previousMillis > interval){
// previousMillis = currentMillis;
present = ds.reset(); ds.select(addr[sensor]); ds.write(0xBE); // Read Scratchpad
for ( i = 0; i < 9; i++)
{ // we need 9 bytes
data[i] = ds.read();
}
LowByte = data[0]; HighByte = data[1];
TReading = (HighByte << 8) + LowByte;
SignBit = TReading & 0x8000; // test most sig bit
if (SignBit) // negative
{
TReading = (TReading ^ 0xffff) + 1; // 2's comp
}
Tc_100 = (TReading*100/2);
Whole = Tc_100 / 100; // separate off the whole and fractional portions
Fract = Tc_100 % 100;
// sprintf(buf, "%d:%c%d.%d\337C",sensor,SignBit ? '-' : '+', Whole, Fract < 10 ? 0 : Fract);
sprintf(buf, "%c%d.%d\337",SignBit ? '-' : '+', Whole, Fract/10);
TempNow = Tc_100;
lecture_en_cours = false;
}
}
Combien vaut interval ? On dirait en fait que lecture_en_cours ne repasse pas en false parce que la condition au-dessus n'est pas vérifié et donc lecture_en_cours ne repasse pas en false.
En fait je viens de relire ton code mais je comprends pas bien : pourquoi mettre un delay (enfin l'histoire avec les millis()) sur la lecture clavier ? N'est-ce pas plutôt sur la mesur ede température que tu veux faire cela ?
Comme cela ton code est consacré à 99% sur la lecture clavier (donc + réactif) et toute les secondes tu as une lecture de température. Tu peux même encore optimiser le code par exemple en réinitialisant previousMillis à l'appuie sur une touche clavier, ce qui laisserait le temps à l'utilisateur de tout taper sans que des mesures se mettent au milieu.
Sur les boutons poussoir, il faut tout de même prévoir une petite temporisation pour éviter un effet de "rebond", le bouton n'est pressé qu'une fois, mais est lu comme appuyé plusieurs fois....
B@tto,
Jean-François a décrit le principe; il reste à croiser les fonctions, car il est évident que la réactivité est attendue au niveau du clavier. Au niveau de mon code, la tempo est bien sur la partie lecture DS1820 pour donner priorité au clavier.