Gestion d'une température négative avec sonde DS18B2

Suite du sujet Affichage 7 segments Arduino et CD4511

Le problème exposé dans ce sujet a été résolu.

Et me revoilà… Je pensais le sujet résolu après avoir réussi à afficher dizaines, unités, point décimal et une décimale plus le signe (——) en cas de valeur négative. Au moment du dernier test avec la sonde mise dans le congélateur, je me suis aperçu qu’à part le signe (——), aucune valeur ne s’affichait. J’ai fait quelques recherches sur le forum et au delà et une fois encore je touche mes limites. C’est encore probablement une question de float et de int. Merci à qui voudra bien m’éclairer.

Merci Drulac de cette remarque pertinente. J’ai pensé à tort que ce sujet étant la suite de deux sujets précédemment résolus, il n’était pas nécessaire d’encombrer le forum avec des choses déjà dites. J’ai comme projet d’assembler un montage permettant d’afficher sur des afficheurs 7 segments à cathodes communes (3 digits en lien avec un décodeur CD4511 et 1 digit pour afficher le signe (——) si nécessaire) la valeur obtenue d’une sonde DS18B2. Comme indiqué plus haut, le tout fonctionne bien sauf quand la T° est < 0. Ci-joint mon code que je n’ai pas complètement nettoyé. Merci de ton aide Cordialement

// Croquis permettant d'afficher la température mesurée par une sonde DS18B20
// sur un afficheur 7S-4D 5643AS à cathodes communes
// en multiplexage avec un décodeur CD4511

// code devant afficher dizaines, unités et une décimale ainsi que le signe (—— )
// ce code est inspiré de plusieurs autres codes trouvés sur le net, notamment sur le site zestedesavoir.com

// la lecture des datasheet de tous les composants a été essentielle

// Téléchargement des bibliothèques correspondant à la sonde de température
// https://www.raspberryme.com/guide-du-capteur-de-temperature-ds18b20-avec-arduino/

#include <OneWire.h>
#include <DallasTemperature.h>

// ************* Initialisation des broches de l'Arduino ************

// Initialisation des broches du décodeur CD4511
const int bit_A = 2;
const int bit_B = 3;
const int bit_C = 4;
const int bit_D = 5;

// Initialisation de la broche de l'afficheur pour valeur négative
const int signe = 6;

// Initialisation des broches connectant les transistors aux cathodes de chaque afficheur
const int alim_decimale = 7; // un chiffre après la virgule
const int alim_unite = 8;   // les unites
const int alim_dizaine = 9; // les dizaines
const int alim_signe = 10; // le signe (—— ) si nécessaire

// Initialisation de la broche du capteur DS18B20
#define ONE_WIRE_BUS 12 

// initialisation de la broche du point décimal DP
int PTdecimal = 13 ; 

// Initialisation des bibliothèques
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// initialisation d'une variable temporaire de type "float" pour isoler la décimale plus tard
float temporaire ;

// ************** DÉBUT DE LA FONCTION SETUP **********************
void setup() {
  // Initialiser la communication série
  Serial.begin(9600);

  // Initialiser le capteur DS18B20
  sensors.begin();

  // Initialiser toutes les broches en sorties
  pinMode(bit_A, OUTPUT);
  pinMode(bit_B, OUTPUT);
  pinMode(bit_C, OUTPUT);
  pinMode(bit_D, OUTPUT);
  pinMode(signe, OUTPUT) ;
  pinMode(alim_dizaine, OUTPUT);
  pinMode(alim_unite, OUTPUT);
  pinMode(alim_decimale, OUTPUT);
  pinMode(PTdecimal, OUTPUT);

  // Mise à l'état bas de toutes les broches
  digitalWrite(bit_A, LOW);
  digitalWrite(bit_B, LOW);
  digitalWrite(bit_C, LOW);
  digitalWrite(bit_D, LOW);
  digitalWrite(signe, LOW);
  digitalWrite(alim_signe, LOW);
  digitalWrite(alim_dizaine, LOW);
  digitalWrite(alim_unite, LOW);
  digitalWrite(alim_decimale, LOW);
  digitalWrite(PTdecimal, LOW);
}

// ************** FIN DE LA FONCTION SETUP ************


// ************** DÉBUT DE LA FONCTION LOOP **********************
void loop()
{
  // Lecture de la température du capteur
  sensors.requestTemperatures();
  float temperature = sensors.getTempCByIndex(0); // float donc "virgule flottante"
  if (isnan(temperature)) { // vérification qu'il s'agit bien d'un nombre
    Serial.println("les données reçues du capteur DS18B20 ne forment pas un nombre");
    return;
  }
// Chargement de la valeur température dans une variable temporaire
  temporaire = temperature ;
// Conversion la température en entier
  int temp = (int)temperature;

// Affichage dans le moniteur série pour contrôle
  Serial.print ("température : ") ;
  Serial.print (temperature) ;
  Serial.println( ) ;

  Serial.print ("variable temporaire : ") ;
  Serial.print (temporaire) ;
  Serial.println( ) ;

// Lecture d'une condition particulière pour déterminet si la température est négative
  if (temp < 0 )
  {
    // Si c'est le cas, on allume le transistor du digit du signe négatif
    digitalWrite(alim_signe, HIGH);
    // on allume le segment "g" horizontal central
    digitalWrite(signe, HIGH);
    delay(5);
  }
  else {
    // on éteint le transistor allumé
    digitalWrite(alim_signe, LOW);
  }

  // Appel de la fonction affichage avec envoi du nombre à afficher
  afficher_nombre(temp);

}
// ************* FIN DE LA FONCTION LOOP ************

// ************* SOUS FONCTIONS UTILISÉES DANS LE PROGRAMME **************

// fonction permettant d'afficher un nombre sur plusieurs afficheurs
void afficher_nombre(char nombre)
{
  // initialisation de variables suplémentaires
  long temps; // variable utilisée pour savoir le temps écoulé...
  char signe = 0, unite = 0, dizaine = 0, decimale = 0 ; // variable pour chaque afficheur

  if (nombre > 9) // si le nombre reçu dépasse 9
  {
    dizaine = nombre / 10; // on récupère les dizaines

    unite = nombre - (dizaine * 10); // on récupère les unités

    // on récupère la première décimale à partir de la variable float créée en amont,
    // après avoir transformé sa valeur en un entier pour pouvoir appliquer le modulo
    decimale = (int) (temporaire * 10) % 10  ;
  }

  temps = millis(); // on récupère le temps courant

  // valeur fixant le temps de rafraichissement de la lecture de la sonde
  while ((millis() - temps) < 5000)
  {
    // on allume d'abord le digit des dizaines pendant 10 ms
    digitalWrite(alim_dizaine, HIGH);
    // on appelle la fonction qui permet d'afficher le chiffre des dizaines
    afficher(dizaine);
    // les autres transistors sont bloqués et leurs afficheurs éteints
    digitalWrite(alim_unite, LOW);
    digitalWrite(alim_decimale, LOW);

    // la valeur du delay permet de gérer le temps d'affichage
    // et donc d'éviter le clignotement si cette valeur est trop élevée
    delay(5);

    // idem pour les unités avec ajout du point décimal

    // on coupe l'alimentation du transistor des dizaines
    digitalWrite(alim_dizaine, LOW);
    // on allume ensuite le digit des unités pendant 10 ms
    digitalWrite(alim_unite, HIGH);
    // on appelle la fonction qui permet d'afficher le chiffre des unités
    afficher(unite);
    // on allume le point digital
    digitalWrite(PTdecimal, HIGH);
    // les autres transistors sont bloqués et leurs afficheurs éteints
    digitalWrite(alim_dizaine, LOW);
    digitalWrite(alim_decimale, LOW);
    delay(5);

    // idem pour les décimales

    // on coupe l'alimentation du transistor des unités
    digitalWrite(alim_unite, LOW);
    // et l'allumage du point décimal sur le deuxième digit
    digitalWrite(PTdecimal, LOW);
    // on allume ensuite le digit des unités pendant 10 ms
    digitalWrite(alim_decimale, HIGH);
    // on appel la fonction qui permet d'afficher le chiffre de la 1ère décimale
    afficher(decimale);
    // les autres transistors sont bloqués et leurs afficheurs éteints
    digitalWrite(alim_dizaine, LOW);
    digitalWrite(alim_unite, LOW);
    delay(5);
  }
}

// Fonction traduisant le chiffre décimal en une représentation binaire pour contrôler le décodeur BCD
  // et afficher ce chiffre sur l'afficheur 7 segments sélectionné.
  
void afficher(char chiffre)
{
  digitalWrite(bit_A, LOW);
  digitalWrite(bit_B, LOW);
  digitalWrite(bit_C, LOW);
  digitalWrite(bit_D, LOW);

  // Traduction 
  if (chiffre >= 8)
  {
    digitalWrite(bit_D, HIGH);
    chiffre = chiffre - 8;
  }
  if (chiffre >= 4)
  {
    digitalWrite(bit_C, HIGH);
    chiffre = chiffre - 4;
  }
  if (chiffre >= 2)
  {
    digitalWrite(bit_B, HIGH);
    chiffre = chiffre - 2;
  }
  if (chiffre >= 1)
  {
    digitalWrite(bit_A, HIGH);
    chiffre = chiffre - 1;
  }
}
+0 -0

Bonjour,

Pour que le code s’affiche correctement, il faut mettre ``` avant et après (et non pas `[code]). J’ai fait la modification sur ton message.

+0 -0

Salut,

Je pense que ton problème d’affichage ne se produit pas qu’en négatif mais dès que tu passes en dessous de 10°C. L’erreur vient du if ligne 134 : tu ne fais rien si la condition est fausse, ce qui laisse tes variables unite, dizaine et decimale à 0, et donc rien ne s’affiche. De plus, pour la ligne 138, tu peux simplement récupérer les unités grâce au modulo : unite = nombre % 10; ;)

Ça c’est le premier problème, mais il y en a un autre : la fonction afficher_nombre() ne doit recevoir en paramètre que la valeur absolue du nombre, car tu gères déjà le signe avant l’appel.

+1 -0

Merci PG06. Bien compris pour la question du >9 après le if. Je pense qu’il faut mettre 99 à la place. Le code dont je me suis inspiré était prévu pour un afficheur à 1 seul digit. OK pour le modulo. C’est plus simple. Je galère encore mais j’espère avancer. Quant à la fonction afficher_nombre() est-ce que ça peut se régler avec la fonction abs ? désolé je n’ai pas trouvé comment surligner en gris.

Salut,

comme toujours avec les codes microcontrolleurs, sans le schéma de montage, ça ne veut pas dire grand chose.

j’ai pas mal à dire sur le code, j’y reviendrai probavlement demain, avec un vrai clavier et un peu plus de temps. Mais rien qui explique que rien ne s’affiche … quand tu dis "aucune valeur ne s’affiche" tu veux bien dire que les afficheurs sont éteint ou tu veux dire que ça affiche tout le temps "00.0" ? parce que si c’est le cas ça fera partie de mes remarques.

Edit : grillé avec mon clavier mobile x)

+0 -0

Merci Romantik. Excuse mon imprécision. C’est effectivement "00.0" qui s’affiche lorsque la sonde est dans le congélateur. Le signe (——) s’affiche bien mais ne s’efface pas quand la température remonte. Je vais faire un schéma de mon montage et le poster dans un prochain message.

C’est bien la fonction abs() pour la valeur absolue.

Par contre 99 ne va pas régler ton problème. Tu dois laisser 9 comme tu as fait (enfin je n’ai pas vu ton montage mais je suppose que c’est bon puisque ça fonctionne pour les valeurs positives) mais ça doit servir uniquement pour gérer les dizaines. Les unités et décimales doivent être calculées en dehors du if, à chaque appel de la fonction.

+0 -0

D’après ce que je comprend, ta sonde ne retourne jamais de fraction décimale.

Sinon, il faudrait faire ceci:

    int temperature = (int) (sensors.getTempCByIndex(0) * 10);
    if(temperature < 0) {
        // afficher le "-"
        temperature = - temperature;     // Pareil à abs() dans ce cas.
    }

Et tenir compte du fait que ton nombre est plus grand, on aurait:

    decimal = temperature % 10;
    unite = temperature / 10 % 10;
    dizaine = temperature / 100 % 10;

Je laisse le soin à @romantik de t’expliquer le reste.

C’est lui l’expert en électronique.

C’est lui l’expert en électronique.

PierrotLeFou

Merci pour le compliment, même si je pense que c’est plutôt Eskimon l’expert embarqué sur zds. ^^'
En tout cas j’ai suivi les autres sujets liés donc je suis peut-être plus à l’aise et disponible.


@Romsie:

Comme l’a souligné PG06, le soucis pour lequel tu affiche 00.0 est ta condition if qui décompose ton nombre.

Maintenant quelques commentaires sur le code :

const int alim_signe = 10; // le signe (—— ) si nécessaire

Je ne le vois pas sur ton schéma de montage, et je pense effectivement que tu n’en n’a pas besoin, tu peux le piloter directement de ton aduino, les pilotages des alimentations afficheurs sont là parce qu’ils se partagent le même décodeur, or celui du signe n’en a pas besoin.

Par conséquent, ça ne sert pas non plus de le piloter

  // Lecture d'une condition particulière pour déterminet si la température est négative
  if (temp < 0 )
  {
    // Si c'est le cas, on allume le transistor du digit du signe négatif
    digitalWrite(alim_signe, HIGH);
    // on allume le segment "g" horizontal central
    digitalWrite(signe, HIGH);
    delay(5);
  }
  else {
    // on éteint le transistor allumé
    digitalWrite(alim_signe, LOW);
  }

dans ton else, tu n’éteint pas le signe, ce qui explique pourquoi une fois allumé il ne s’éteint plus jamais.
Aussi, je trouve que ce bout de code devrait appartenir à afficher_nombre plutôt que de traiter la valeur absolue.
De plus, l’appel à delay(5) me parait simplement te faire perdre du temps. Les autres occurences sont justifiées car les afficheurs vont être éteint ensuite et on veut s’assurer que la LED aie eu le temps de produire la lumière et que l’observateur aie le temps de voir le chiffre s’afficher. Mais sur celle-ci, l’afficheur ne va pas être coupé, donc pas besoin de ce temps de pause.


// initialisation de la broche du point décimal DP
int PTdecimal = 13 ;

à priori tu n’as pas l’air de vouloir changer de précision dans l’affichage, alors pourquoi le rendre pilotable ? Tu pourrais l’afficher en permanence en le liant au +5V


// initialisation d'une variable temporaire de type "float" pour isoler la décimale plus tard
float temporaire ;

Si ce n’est qu’une variable temporaire à un calcul, tu peux le déclarer au plus proche du calcul et éviter d’en faire une variable globale (qui est plutôt une mauvaise pratique). De manière générale, toujours déclarer les variables au plus proche de leurs utilisations.
De plus, je pense que tu n’en as pas besoin et que c’est une solution à un problème que tu as mal compris, mais j’y reviens dans un point plus bas.


// Conversion la température en entier
  int temp = (int)temperature;

lorsque tu cast un flottant en entier, tu le tronques. C’est pour ça qu’auparavent tu perdais purement et simplement tes décimales. De plus, je ne comprends pas pourquoi tu as besoin de le convertir plutôt que de changer afficher_nombre pour qu’il prenne un float en entrée.


  // Affichage dans le moniteur série pour contrôle
  Serial.print ("température : ") ;
  Serial.print (temperature) ;
  Serial.println( ) ;

  Serial.print ("variable temporaire : ") ;
  Serial.print (temporaire) ;
  Serial.println( ) ;

Ce sont des affichages de debug, ce sont des informations utiles pour trouver un problème, ce sont donc des informations que tu peux nous donner quand tu demandes de l’aide.


  if (nombre > 9) // si le nombre reçu dépasse 9
  {
    dizaine = nombre / 10; // on récupère les dizaines

    unite = nombre - (dizaine * 10); // on récupère les unités

    // on récupère la première décimale à partir de la variable float créée en amont,
    // après avoir transformé sa valeur en un entier pour pouvoir appliquer le modulo
    decimale = (int) (temporaire * 10) % 10  ;
  }

Comme déjà relevé, ta condition du if. Tu ne traites la décomposition que si le nombre est supérieur à 9, or ce n’est pas ce que tu veux et tu semble l’avoir compris. Le rôle que tu peux donner à une telle condition pour moi est double : soit il va permettre de gérer des nombres non-affichable (valeur supérieure à 99.9), soit il va permettre de gérer le format d’affichage (éviter d’afficher '07.0' mais plutôt '7' ou '7.0' etc…) donc quel format d’affichage est-ce que tu veux ?

La méthode que tu as appliqué sur la décimale, tu peux l’appliquer pour extraire n’importe quel chiffre. Tu fais en sorte de mettre le chiffre qui t’interesse dans les unités en multipliant par la puissance de 10 appropriée, puis tu tronques en castant en int, et enfin tu extrait l’unité par un modulo 10. Donc tu peux avoir le code.

dizaine = static_cast<int>(nombre/10)%10;  // on cherche le chiffre 10^1 donc on multiplie par 10^-1
unite = static_cast<int>(nombre)%10;       // on cherche le chiffre 10^0 donc on multiplie par 10^0
decimale = static_cast<int>(nombre*10)%10; // on cherche le chiffre 10^-1 donc on multiplie par 10^1

Aussi, en les tronquant ainsi, tu va avoir la décimale immédiatement inférieure. Est-ce que ça te convient ou est-ce que tu cherches un arrondi ? Une température de 17.48 doit afficher 17.5 ou 17.4 ? Et quid de 17.45 ? (Attention sur l’arrondi à 17.96 qui va donner 18.0 et donc modifier aussi l’unité)


  // valeur fixant le temps de rafraichissement de la lecture de la sonde
  while ((millis() - temps) < 5000)

Je suppose que cette boucle est là pour ne pas changer en permanence de valeur au point que ce soit illisible. C’est une bonne idée mais pour moi ce n’est pas le rôle de la fonction d’affichage. Sur ton application ça ne va peut-être pas poser problème, mais ça me semble être une erreur de conception qui pourrait te bloquer dans des évolutions, car il rend ton affichage bloquant (et pour 5 secondes !).
Pour moi, ce que tu cherches à faire c’est de prélever ta mesure toute les 5 secondes, soit de l’échantillonage. C’est donc une condition qu’on devrait trouver plutôt au prélevement de la mesure sur la sonde (actuellement dans la fonction loop). Ainsi tu pourrais faire l’appel au prélèvement que si 5 secondes se sont écoulées et continuer d’afficher à chaque tour de boucle. De plus, avec une telle structure, tu pourras appliquer des calculs pour adoucir ta mesure si la lib ne le fait pas déjà, comme une moyenne ou une médiane glissante sur X mesures.


void afficher(char chiffre)
{
  digitalWrite(bit_A, LOW);
  digitalWrite(bit_B, LOW);
  digitalWrite(bit_C, LOW);
  digitalWrite(bit_D, LOW);

  // Traduction 
  if (chiffre >= 8)
  {
    digitalWrite(bit_D, HIGH);
    chiffre = chiffre - 8;
  }
  if (chiffre >= 4)
  {
    digitalWrite(bit_C, HIGH);
    chiffre = chiffre - 4;
  }
  if (chiffre >= 2)
  {
    digitalWrite(bit_B, HIGH);
    chiffre = chiffre - 2;
  }
  if (chiffre >= 1)
  {
    digitalWrite(bit_A, HIGH);
    chiffre = chiffre - 1;
  }
}

C’est juste, et je sais que c’est le code du tuto, mais je vais proposer une autre version que je trouve plus lisible, plus concise et plus optimisée. Je pense que le tuto l’a évité pour s’épargner le concept de masque, et l’explication des éléments de langages que sont les opérateurs binaires, l’opérateur ternaire et les notations litérales alternatives (parce que c’est plus le rôle d’un tuto de langage que de tuto embarqué). Je pose ça là et on pourra en parler, mais essaie déjà de comprendre le reste du code avant.

void afficher(char chiffre)
{
  digitalWrite(bit_A, (chiffre&0b0001)?HIGH:LOW);
  digitalWrite(bit_B, (chiffre&0b0010)?HIGH:LOW);
  digitalWrite(bit_C, (chiffre&0b0100)?HIGH:LOW);
  digitalWrite(bit_D, (chiffre&0b1000)?HIGH:LOW);
}
+2 -0

Quel boulot ! Merci d’avoir pris le temps de détailler. Je vais lire tout ça avec attention. Comme tu l’auras compris je suis un peu novice en la matière. Je n’ai fait jusqu’à présent que des petits programmes bien simples et plusieurs notions de base me manquent. J’apprends au fur et à mesure, tant que mes vieux neurones veulent bien suivre…

J’ai préparé mes réponses et commentaires que je copie tels quels. Je ne sais pas si c’est la façon de procéder sur le forum. Merci de m’éclairer.

Maintenant, je vais modifier le code et le montage en conséquence et revenir avec le résultat.

1 - Pilotage du point décimal Supprimer les lignes de code concernées

Modifier le circuit en reliant directement la résistance au 5 volts

const int alim_signe = 10; // le signe (—— ) si nécessaire

Je ne le vois pas sur ton schéma de montage, et je pense effectivement que tu n’en n’a pas besoin, tu peux le piloter directement de ton aduino, les pilotages des alimentations afficheurs sont là parce qu’ils se partagent le même décodeur, or celui du signe n’en a pas besoin. Par conséquent, ça ne sert pas non plus de le piloter

// initialisation de la broche du point décimal DP int PTdecimal = 13 ;

à priori tu n’as pas l’air de vouloir changer de précision dans l’affichage, alors pourquoi le rendre pilotable ? Tu pourrais l’afficher en permanence en le liant au +5V

J’avais remplacé la broche 10 par la 6, mais effectivement nul besoin de piloter le point décimal qui doit être présent de manière permanente.

2 – Signe ( — ) en cas de température négative

Supprimer le delay (5)

Ajouter cette commande pour éteindre le signe

digitalWrite(signe, LOW);

Déplacer ce bout de code au tout début de la fonction " afficher_nombre"

// Lecture d’une condition particulière pour déterminet si la température est négative if (temp < 0 ) { // Si c’est le cas, on allume le transistor du digit du signe négatif digitalWrite(alim_signe, HIGH); // on allume le segment "g" horizontal central digitalWrite(signe, HIGH); delay(5); } else { // on éteint le transistor allumé digitalWrite(alim_signe, LOW); }

dans ton else, tu n’éteint pas le signe, ce qui explique pourquoi une fois allumé il ne s’éteint plus jamais. Aussi, je trouve que ce bout de code devrait appartenir à afficher_nombre plutôt que de traiter la valeur absolue. De plus, l’appel à delay(5) me parait simplement te faire perdre du temps. Les autres occurences sont justifiées car les afficheurs vont être éteint ensuite et on veut s’assurer que la LED aie eu le temps de produire la lumière et que l’observateur aie le temps de voir le chiffre s’afficher. Mais sur celle-ci, l’afficheur ne va pas être coupé, donc pas besoin de ce temps de pause.

Q 1 ? : Pourquoi le signe reste-t-il allumé si le digit n’est plus alimenté ?

3 – Affichage des valeurs négatives

Enlever cette ligne de code

3.1 – // initialisation d’une variable temporaire de type "float" pour isoler la décimale plus tard float temporaire ; float temporaire ; Si ce n’est qu’une variable temporaire à un calcul, tu peux le déclarer au plus proche du calcul et éviter d’en faire une variable globale (qui est plutôt une mauvaise pratique). De manière générale, toujours déclarer les variables au plus proche de leurs utilisations. De plus, je pense que tu n’en as pas besoin et que c’est une solution à un problème que tu as mal compris, mais j’y reviens dans un point plus bas.

3.2 – // Conversion la température en entier int temp = (int)temperature; lorsque tu cast un flottant en entier, tu le tronques. C’est pour ça qu’auparavent tu perdais purement et simplement tes décimales. De plus, je ne comprends pas pourquoi tu as besoin de le convertir plutôt que de changer afficher_nombre pour qu’il prenne un float en entrée.

Q 2 ? : Que veut dire le terme "cast" ?

J’ai trouvé cette solution pour aller ensuite chercher la décimale, parce que je ne maîtrise pas les types "char" et "float".

Q 3 ? Il faudrait donc modifier "afficher_nombre" de manière à avoir void afficher_nombre(float nombre) ou void afficher_nombre(int nombre) ?

4 – Obtention des chiffres à afficher 4.1 -

if (nombre > 9) // si le nombre reçu dépasse 9 { dizaine = nombre / 10; // on récupère les dizaines

unite = nombre - (dizaine * 10); // on récupère les unités

// on récupère la première décimale à partir de la variable float créée en amont, // après avoir transformé sa valeur en un entier pour pouvoir appliquer le modulo decimale = (int) (temporaire * 10) % 10 ; }

Comme déjà relevé, ta condition du if. Tu ne traites la décomposition que si le nombre est supérieur à 9, or ce n’est pas ce que tu veux et tu semble l’avoir compris. Le rôle que tu peux donner à une telle condition pour moi est double : soit il va permettre de gérer des nombres non-affichable (valeur supérieure à 99.9), soit il va permettre de gérer le format d’affichage (éviter d’afficher '07.0' mais plutôt '7' ou '7.0' etc…) donc quel format d’affichage est-ce que tu veux ? La présence des zéros ne me dérangent pas pour l’instant et je pense qu’il faudrait ajouter pas mal de code pour éteindre les digits concernés le cas échéant ???

4.2 – La méthode que tu as appliqué sur la décimale, tu peux l’appliquer pour extraire n’importe quel chiffre. Tu fais en sorte de mettre le chiffre qui t’interesse dans les unités en multipliant par la puissance de 10 appropriée, puis tu tronques en castant en int, et enfin tu extrait l’unité par un modulo 10. Donc tu peux avoir le code. dizaine = static_cast<int>(nombre/10)%10;
// on cherche le chiffre 101 donc on multiplie par 10-1 unite = static_cast<int>(nombre)%10; // on cherche le chiffre 100 donc on multiplie par 100 decimale = static_cast<int>(nombre*10)%10; // on cherche le chiffre 10-1 donc on multiplie par 101 Aussi, en les tronquant ainsi, tu va avoir la décimale immédiatement inférieure. Est-ce que ça te convient ou est-ce que tu cherches un arrondi ? Une température de 17.48 doit afficher 17.5 ou 17.4 ? Et quid de 17.45 ? (Attention sur l’arrondi à 17.96 qui va donner 18.0 et donc modifier aussi l’unité)

Là encore, à ce stade, je ne cherche pas l’ultime précision : 17.4 me convient. Initialement, je pensais même me satisfaire d’un affichage sans décimale comme celui réalisé précédemment qui me sert uniquement pour mesurer la température du compost.

5 – Affichages de debug OK, c’est bien noté et je reçois sur le moniteur série les informations attendues, c’est-à-dire les températures mesurées y compris lorsqu’elles sont négatives à la différence de ce qui se passe sur les afficheurs

// Affichage dans le moniteur série pour contrôle Serial.print ("température : ") ; Serial.print (temperature) ; Serial.println( ) ; Serial.print ("variable temporaire : ") ; Serial.print (temporaire) ; Serial.println( ) ; Ce sont des affichages de debug, ce sont des informations utiles pour trouver un problème, ce sont donc des informations que tu peux nous donner quand tu demandes de l’aide.

6 – Améliorations et évolutions futures

La valeur de 5 secondes a été choisie pour les tests. Dans la réalité une mesure toutes les dix minutes ou plus serait suffisante car ce projet doit intégrer une station météo.

Ta remarque est importante car j’envisage de mettre ces mesures en mémoire pour ultérieurement pouvoir consulter des statistiques ou lancer des alertes… Je ne suis pas au bout de mes peines…

// valeur fixant le temps de rafraichissement de la lecture de la sonde while ((millis() - temps) < 5000) Je suppose que cette boucle est là pour ne pas changer en permanence de valeur au point que ce soit illisible. C’est une bonne idée mais pour moi ce n’est pas le rôle de la fonction d’affichage. Sur ton application ça ne va peut-être pas poser problème, mais ça me semble être une erreur de conception qui pourrait te bloquer dans des évolutions, car il rend ton affichage bloquant (et pour 5 secondes !). Pour moi, ce que tu cherches à faire c’est de prélever ta mesure toute les 5 secondes, soit de l’échantillonage. C’est donc une condition qu’on devrait trouver plutôt au prélevement de la mesure sur la sonde (actuellement dans la fonction loop). Ainsi tu pourrais faire l’appel au prélèvement que si 5 secondes se sont écoulées et continuer d’afficher à chaque tour de boucle. De plus, avec une telle structure, tu pourras appliquer des calculs pour adoucir ta mesure si la lib ne le fait pas déjà, comme une moyenne ou une médiane glissante sur X mesures. // Fonction traduisant le chiffre décimal en une représentation binaire pour contrôler le décodeur BCD // et afficher ce chiffre sur l’afficheur 7 segments sélectionné. void afficher(char chiffre) ETC… { C’est juste, et je sais que c’est le code du tuto, mais je vais proposer une autre version que je trouve plus lisible, plus concise et plus optimisée. Je pense que le tuto l’a évité pour s’épargner le concept de masque, et l’explication des éléments de langages que sont les opérateurs binaires, l’opérateur ternaire et les notations litérales alternatives (parce que c’est plus le rôle d’un tuto de langage que de tuto embarqué). Je pose ça là et on pourra en parler, mais essaie déjà de comprendre le reste du code avant. void afficher(char chiffre) { digitalWrite(bit_A, (chiffre&0b0001)?HIGH:LOW); digitalWrite(bit_B, (chiffre&0b0010)?HIGH:LOW); digitalWrite(bit_C, (chiffre&0b0100)?HIGH:LOW); digitalWrite(bit_D, (chiffre&0b1000)?HIGH:LOW); }

Je ne demande qu'à apprendre, mais n'allons pas trop vite en besogne
+0 -0

@Romsie N’hésites pas à citer les messages avec le bouton Citer ce qui permet de mieux s’y retrouver entre les citations et les réponses !

Capture d'écran du bouton "Citer"
Capture d’écran du bouton "Citer"

Tu peux aussi écrire directement en Markdown sans utiliser le bouton (tel qu’expliqué dans le tutoriel "Rédiger sur ZDS") :

> Ceci est une citation
> 
> sur plusieurs lignes
Source: Citez vos sources !

Ceci est une citation

sur plusieurs lignes

Citez vos sources !
+0 -0

Q 1 ? : Pourquoi le signe reste-t-il allumé si le digit n’est plus alimenté ?

Romsie

Il l’est, parce que tu n’as pas de circuit qui vient couper l’alimentation comme tu l’as fait avec les trois autres afficheurs. C’est à dire, tu n’as pas de transistor sur la cathode commune, et tu n’as rien de branché sur la pin 10 de l’arduino. Donc quand tu fais digitalWrite(alim_signe, LOW);, tu ne pilote en fait rien.

Q 2 ? : Que veut dire le terme "cast" ?

Romsie

Pardon, je fais de l’anglicisme. En français c’est du transtypage. C’est un terme assez propre à la programmation car il s’agit de changer le type d’une variable. Et tu comprends bien que les differents types ne peuvent pas forcément représenter les mêmes valeurs, donc certaines règles s’appliquent. Et dans un transtypage de float (nombre réel) vers int (nombre entier) la valeur est tronquée à sa valeur entière immédiatement inférieure si elle n’est pas entière.

je ne maîtrise pas les types "char" et "float".

Romsie

float est un type permettant de représenter des nombres réels. La représentation mémoire est un peu compliquée pour que je l’explique là, et elle n’est pas importante à connaitre pour faire ce que tu fais (je ne sais même pas vraiment dans quel cas ce serait utile, je l’ai juste vu à l’école). Donc faut juste savoir que si t’as des nombres non entier, il faut utiliser float (ou double qui permet une plus grande amplitude de valeur)

char est un peu plus fourbe parce que c’est un type conçu pour représenter un caractère ascii (character) mais est très souvent utiliser aussi comme un entier sur 8 bits (donc entre -128 et 127) car c’est come ça que sont encodé les caractères. Le standard a mis de nouveaux types pour maitriser la taille des types entiers pour ajouter un peu plus de sens et éviter ce genre de confusion, avec std::int8_t mais je ne sais pas si t’y a accès sur arduino. Mais en bref, dans ton cas, il te suffit de te dire que char est un petit entier.

Q 3 ? Il faudrait donc modifier "afficher_nombre" de manière à avoir void afficher_nombre(float nombre) ou void afficher_nombre(int nombre) ?

Romsie

C’est ce que je préconise parce que je trouve que ça a plus de sens, oui.

La présence des zéros ne me dérangent pas pour l’instant et je pense qu’il faudrait ajouter pas mal de code pour éteindre les digits concernés le cas échéant ???

Romsie

ça dépend ce qu’on appelle pas mal, mais oui ça en ajoute. ça devrait être accessible avec tes connaissances actuelles, il s’agit de conditions, donc de blocs if. Après personnellement ça ne me choque pas non plus d’avoir un affichage '05.0' sur des afficheurs 7 segments.

+0 -0

Je suppose que ta sonde est reliée à un circuit appelé convertisseur analog-digital. Ce qui veut dire convertir un voltage ou un courant en un nombre.

Autant que je sache, ce nombre est toujours un nombre entier.

Il y a des convertisseurs qui le font avec une précision de 8 bits et d’autres 16 bits (ou autres).

Et ce nombre ne représente pas forcément la température. Il faut parfois calibrer en ajustant des résistances.

De plus, la fonction peut faire la conversion appropriée, et elle le fait généralement dans un nombre réel.

Puisque la précision n’est pas extrême, un floatsuffit dans ce cas.

Situphen, il y a une heure

Options du message

@Romsie N’hésites pas à citer les messages avec le bouton Citer ce qui permet de mieux s’y retrouver entre les citations et les réponses !>

Merci Situphen, de tes conseils. Je vais potasser ce tuto pour respecter au mieux les règles du forum

Bien sur que ça m’intéresse, mais j’y vais à petite vitesse. Mes années d’études sont lointaines, mais en 1964 ou 65, j’ai quand même découvert le terme "numérique" au sujet d’une fraiseuse commandée par bandes à trou… C’était une autre époque, mais déjà des "0" et des "1" : un trou ou pas de trou !

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte