DS1820 et Keypad

Bonsoir,

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 ?

Merci.

Met ton code pour voir...

ne peux tu pas utiliser une fonction faite avec milli() plutôt que sleep()(?) ?

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);
    }    
}

)

Commence déjà par virer ce delay(1000) et remplace le par une une fonction avec millis().

Help :stuck_out_tongue:

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 ?

tu mets une interruption toutes les secondes...

Gozaki

www.laboelectronique.be

Maitriser le temps

Tu remplaces SDL_GetTicks par millis() :wink:

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 ?

PS : j'espère avoir été clair :o

Fait un truc du genre :

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 ;
}
}

Ou un truc approchant... ;D

Ah, ça y est, c'est monté au cerveau :o
Je suis en déplacement prof., je m'y remets ce week-end.

Merci beaucoup pour les explications !

Bonsoir,

Pourriez-vous m'éclairer sur ceci ?

 sprintf(buf, "%c%d.%d\337",SignBit ? '-' : '+', Whole, Fract/10);

L'affichage indique 21.5 °. J'aimerais sauvegarder la valeur numérique en
mémoire car je dois ensuite comparer avec une température de consigne.

Pourriez-vous m'expliquer comment faire ? Je suis un peu perdu avec le
chiffre après la virgule...

Désolé si cela parait trivial :-[

D'après ton code ça devrait être Tc_100 la variable correspondante :wink:

Oups ! Vu merci :o

Bonsoir et bon réveillon à tous :wink:

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;
          }
}

Up !
Merci.

Il me semble que le problème vient de l'état de ton boolean lecture_en_cours et de ces lignes :

//if(currentMillis - previousMillis > interval){
// previousMillis = currentMillis;

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.

J'ai testé avec interval = 1000.
Est-ce OK comme valeur ? (pour faire 1 seconde).

long interval = 1000;

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 ?

Le schéma de ton code devrait être plutôt :

void loop(){
currentMillis=millis();
if (if(currentMillis - previousMillis > interval){
previousMillis = currentMillis;  
lecture_température;
}
lecture_clavier;
}

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.