erreur premier retour de fonction attribué dans une variable

Bonjour,

je viens faire appel à vos connaissances et avis pour m’aider à comprendre un petit problème que je rencontre avec un retour de fonction!

pour expliquer dans un premier temps:

J’ai un programme qui lit dix fois une sonde de T°, avant de réaliser une moyenne et me retournée la valeur de température!

ce programme marche, il pilote un transistor pour lire la sonde tte les 200ms et au bout de 2 secondes(10 lectures), me print la température calculer!

Je décide alors de le transformé en bibliothèque pour “simplifier” son utilisation dans un programme plus grand. et pouvoir printer le retour de temperature seulement si il varie de plus ou moin 0.5°c

je fais le .cpp je fais le .h et un programme de test en .ino

Dans le programme de test, j’attribue à une variable, le retour de ma fonction qui calcul la température.

Des que je test le programme, la première valeur est toujours fausse! On dirait que la fonction force la condition pour attribué une valeur et ensuite tous ce déroule comme prevu!
cette valeur est tjr la même!

Le programme de test ci dessous me retourne comme première valeur 48.40 puis ensuite tout rentre dans l’ordre.

si je me contente de faire le print directement dans la fonction du .cpp et que j’appel simplement la fonction dans le .ino, il me retourne une valeur bonne.

si j’attribue a une variable, le retour de fonction, la première valeur renvoyée semble “forcer” la fonction.

(non respect du IF(ptr>=NUMSAMPLES) pour aller chercher le retour de T.

Je met le .cpp:

#include <arduino.h>
#include "TEMPmoyennePILOTEE.h"



int ptr=0;  
#define NUMSAMPLES 10 //nombre de lecture
int samples[NUMSAMPLES];
int ThermistorPin = A0; //pin analogique pour sonde NTC100K


void initialiseTEMPmoyennePILOTEE(){
   
   analogReference(EXTERNAL);
   pinMode(0,INPUT);
   pinMode(12,OUTPUT);
   digitalWrite(12,LOW);
}

float getValueTemperature(){
        
    unsigned long temps=millis();
    unsigned long interval=200; // interval entre prise de temp° pour moyenne
    
    while (millis()< (temps+interval) ); 
    ReadTemp(ptr);
    ptr ++; 

  /*Serial.print("ptr");
    Serial.print( ptr);
    Serial.println();
    Serial.println("samples[]");
    Serial.println(samples[0]);
    Serial.println(samples[1]);
    Serial.println(samples[2]);
    Serial.println(samples[3]);
    Serial.println(samples[4]);
    Serial.println(samples[5]);
    Serial.println(samples[6]);
    Serial.println(samples[7]);
    Serial.println(samples[8]);
    Serial.println(samples[9]);
    Serial.println();  */  
     
    if(ptr>=NUMSAMPLES){
      
      float Moyenne=0;
      
      for (int i=0; i<NUMSAMPLES; i++) {
      Moyenne += samples[i];}
      
      Moyenne /= NUMSAMPLES;
      
      float R1 = 10000; //valeur R a temperature ambiante
      float logR2, R2, T ;
      float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;
      
      R2 = R1 * (1023.0 / Moyenne - 1.0);
      logR2 = log(R2);
      T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
      T = T - 273.15;
      // T = (T * 9.0)/ 5.0 + 32.0; // pour affichage en degree Farhenheit
 
     
    /*  Serial.print ("Temperature:");
      Serial.print ( T);
      Serial.println ("C");  */
      
     
     /* //sendTEMPToNextion();
      Serial.print("t3.txt=");
      Serial.print("\"");
      Serial.print(T);
      Serial.print("\"");
      Serial.write(0xff);
      Serial.write(0xff);
      Serial.write(0xff); */ 
      ptr=0;      
      return (T);
      } 
      
}


void ReadTemp(int n) {
  
   digitalWrite(12,HIGH);
   samples[n] = analogRead(ThermistorPin); 
   digitalWrite(12,LOW);

}

Le .h:

#ifndef TEMPmoyennePILOTEE_h
#define TEMPmoyennePILOTEE_h

void initialiseTEMPmoyennePILOTEE(); // initialise les variables

float getValueTemperature(); // prend la temperature sur 10 lectures
//sur un interval de 200ms soit 2secondes et retourne Temperature

void ReadTemp(int n); // fonction qui releve la temperature sur A0 en activant la pin 12

#endif TEMPmoyennePILOTEE_h

Le programme de test en .ino:

#include "TEMPmoyennePILOTEE.h"

float TemperatureUne;
float TemperatureDeux;

void setup(){

  Serial.begin(115200); 
  Serial.println("****DEBUT_PROGRAMME****");
  Serial.println("");

  initialiseTEMPmoyennePILOTEE();
  TemperatureUne=0;
  TemperatureDeux=0;
  
}


void loop(){

  
  
  TemperatureUne=getValueTemperature(); // renvoi une premiere mesure de 48.40 fausse!!
       
                            
   if ( (TemperatureUne < (TemperatureDeux -0.5)) || (TemperatureUne > (TemperatureDeux +0.5)) ){ 
 
      TemperatureDeux = TemperatureUne;
      Serial.print ("Temperature:");
      Serial.print (TemperatureUne);//
      Serial.println ("C");
       
   }
  
}

Je cherche a comprendre pourquoi le premier retour “n’attend” pas la fin de la fonction.

N’hésitez pas à apporté également des idées d’améliorations si possible

c’est mes premières bibliothèques, soyez indulgent ^^ .

Merci d’avance pour vos retours.

float getValueTemperature(); // prend la temperature sur 10 lectures

Mais dans getValueTemperature() il n’y a pas de boucle pouvant faire 10 lectures

la première fois ptr vaut 0

unsigned long temps=millis();
unsigned long interval=200; // interval entre prise de temp° pour moyenne
while (millis()< (temps+interval) );
Tout ceci est l’équivalent de delay(200)

ReadTemp(ptr);
ptr ++;
La première fois je lis la température que je mets dans samples[0]

if(ptr>=NUMSAMPLES){
La première fois que l’on appelle cette fonction la condition n’est jamais valide et la fonction se terminera sans passer par le return.

En mettant les prints dans la fonction, il faut attendre 10 boucles pour avoir la condition d’affichage correcte et quand on a les 10 valeurs, il affiche la moyenne. Si on appelle encore cette fonction ptr vaudra 11 puis 12… il écrit en dehors du tableau et tout peut se passer correctement jusqu’à ce qu’on ait rempli tout l’espace des données et que l’on écrase la pile.

En la mettant dans le loop, les 10 premières fois on ne passe pas par le return et la fonction ce qu’on lit peut être n’importe quoi. Il est possible que les fois suivantes, on lise le retour de ReadTemp ou autre chose.

Bonjour vileroi,

PTR est remis a 0 en fin de IF.

ta remarque pour la correspondance "delay (200)" est juste! sauf que millis n'est pas bloquante (pour ce que je fais c'est mieux).

Mon problème comme tu le dis ci bien, c'est que la fonction retourne une valeur , sans être passer dans le IF la première fois!! Elle "FORCE" l'aquisition du T en violant la conditions! (je le vois comme çà!)

d’après la condition IF(PTR>=NUMSAMPLES) je ne devrais pas avoir de valeur retourner avant , puisque la variable T est déclarée exprès en local dans ce IF et "return T est aussi dans le IF de la fonction!

tu as bien résumer ce que je cherche a faire!

La question, c'est pourquoi la fonction "viole" le IF et ne renvoi pas la bonne valeur (donc ne respecte pas ce que je lui demande!!!), au lieu d'attendre d'avoir la bonne valeur à retourné après avoir put rentrer dans le IF en le respectant?

Je veut bien ne pas faire les choses parfaitement, et on apprend comme ça! Mais si le truc decide tous seul!! a quoi sert return? et la condition?

tu décris bien mon problème, quelle serais la solution a mettre en place!!hors "delay" et hors chargement d'un temps d'attente dans le .ino

pourquoi la fonction seule, attend, et renvoi la bonne valeur, alors que quand je veut mettre la valeur retourner dans une variable, elle force sans attendre le return?

merci d'avance!

Bonjour,

2terium:
ta remarque pour la correspondance "delay (200)" est juste! sauf que millis n'est pas bloquante (pour ce que je fais c'est mieux).

Ça dépend de la façon dont on l'utilise. Comme tu fais une boucle c'est aussi bloquent que delay().

2terium:
d’après la condition IF(PTR>=NUMSAMPLES) je ne devrais pas avoir de valeur retourner avant , puisque la variable T est déclarée exprès en local dans ce IF et "return T est aussi dans le IF de la fonction!

En C/C++ il y a toujours une valeur retournée. Une fonction qui retourne une valeur DOIT toujours retourner une valeur. Le compilateur devrait signaler une erreur.

La solution qui est souvent utilisée en C/C++ quand on ne peut pas retourner de valeur est de retourner une valeur est de retourner une valeur caractéristique qui ne peut pas normalement advenir par exemple -1000.
L'appelant peut alors tester cette valeur caractéristique pour traiter ou non le retour.

  TemperatureUne = getValueTemperature();
  if (TemperatureUne!=-1000)
  {
    // on a reçu une valeur -> on la traite
    // ...
  }

je met un print ecran au cas ou!!

Ok Kamill,

donc en gros c'est une erreur normal !! :wink: faut la gérer quoi!

Le compilateur ne bronche pas d'un yoda! même pas un ptit sursaut ou un hoquet! mdr!

je pensais bêtement que la fonction attendrais de pouvoir acquérir la bonne valeur!!

Une fonction qui retourne une valeur DOIT toujours retourner une valeur

Les fonctions qui doivent retourner un float doivent mettre la valeur de retour dans les registres R16 à R19 du processeur. Il n'est pas impossible qu'une fonction remplisse cette valeur autrement que par le return. Si la valeur de retour est issu d'un calcul asm, elle peut être mise directement dans les bons registres, puis la fonction se termine naturellement. Ceci n'est possible que si le compilateur laisse faire. C'est peut être pour cela qu'il ne génère pas d'erreur. Néanmoins, il devrait émettre au moins un avertissement.
J'ai écris une fois un code faux qui a été ignoré par le compilateur sans avoir de message d'erreur non plus.

La conséquence de cela est que si on ne retourne pas de valeur explicitement, le programme appelant va tout de même pouvoir récupérer une valeur, vu que les registres contiennent nécessairement une valeur. Pas la bonne forcément. Les registres R16 à R19 peuvent servir dans la fonction.

PTR est remis a 0 en fin de IF.

Donc on ne débordera pas. Je n'avais pas tout analysé.

(millis n'est pas bloquante) ->>> pour ce que je fais c'est mieux.

Dans la trame qui se dégage, l'appel à la fonction doit retourner la moyenne des 10 valeurs. Il faut donc attendre. Dans le principe la fonction est bloquante. On peut donc utiliser une attente bloquante.

Si on avait un appel pour dire de commencer l’échantillonnage, puis en attendant la fin des conversion on en profitait pour préparer l'affichage, et quand celui ci st terminé on va lire la moyenne qui est prête, alors il faudrait que la fonction ne soit pas bloquante. Mais ce n'est pas le cas.

La question, c'est pourquoi la fonction "viole" le IF et ne renvoi pas la bonne valeur (donc ne respecte pas ce que je lui demande!!!), au lieu d'attendre d'avoir la bonne valeur à retourné après avoir put rentrer dans le IF en le respectant?

Si on demande de faire cette partie si la condition est vraie, mais que la condition est fausse, elle ne sera pas faite. Si on demande d'attendre, on attend. Mais la la demande n'est pas faite.

Pour avoir une image de la vie réelle, c'est dire à la bonne: va au marché si c'est jour de marché, et ramène un jambon. Après tu rentre chez toi. Si ce n'est pas jour de marché, la bonne va directement rentrer chez elle. C'est un peu ce qui est demandé dans la fonction

Je veut bien ne pas faire les choses parfaitement, et on apprend comme ça! Mais si le truc decide tous seul!! a quoi sert return? et la condition?

Il ne décide rien; La condition est fausse, on lui dit de ne pas la faire, elle n'est pas exécutée.

Le return permet de terminer la fonction avant la fin. mais ici, on ne tombe pas dessus.

Il y a le besoin réel, le besoin exprimé, la réalisation... Normalement tout devrait être identique. mais ce m'est pas toujours le cas, comme ici.

Si on dit à un informaticien "va au marché et ramène un litre de lait. Et si il y a des oeufs, tu en prend 6". Le besoin est clairement exprimé. L'informaticien va au marché, et comme il y a des oeufs, il ramène les 6 littres de lait. Il répond à ce qu'on lui a demandé. Mais pas à ce qu'on voulait.

tu décris bien mon problème, quelle serais la solution a mettre en place!!hors "delay" et hors chargement d'un temps d'attente dans le .ino

Je ne suis pas bien sûr d'avoir compris. Si c'est pour que la fonction ne bloque pas, ça se complique. Il faut par exemple passer par les interruptions. Ca viendra mais pas dans l'immédiat.

pourquoi la fonction seule, attend, et renvoi la bonne valeur, alors que quand je veut mettre la valeur retourner dans une variable, elle force sans attendre le return?

Si les print dans la fonction, elle ne "répondra" que la dixième fois, mais cela va si vite qu'on ne le sait pas. On ne voit pas les 9 premiers appels. Alors que si on met le print dans me loop, on afficha à chaque fois.

Et la fonction ne voit pas le return vu qu'il est dans une partie qu'on lui demande de ne pas exécuter, comme la bonne qui n'achète pas le jambon.


Ce qu'on peut faire par exemple (ce qui se rapproche sans doute le plus de ce qui est exprimé), c'est
dans la fonction getValueTemperature() faire une boucle for pour récupérer les 10 valeurs. Bloquante car i n'y a rien d'autre à faire. Supprimer le if car de toutes façon on a récupéré les 10 valeurs et il ne sert plus à rien (la condition serait toujours vraie).

Vileroi, merci pour tes explications.

Vue seule! effectivement je pourrais utiliser delay dans ma fonctions, mais ce morceau de programme dois s’intégrer dans un programme plus grand, utilisant des interruptions et timer.

je pense avoir compris qu'il fallait que je décompose encore un peu pour pouvoir dire à mon programme,

"quand la variable est dispo => tu peut l'attribuer"! via une fonction bool dans la biblio!

En fait, je pensais que le programme attendrais!! Mais comme tu le montres ci bien! il prend 6 bouteilles de lait au lieu de prendre des oeufs!!! :wink:

j'ai passé ma journée a essayer d’intégrer un attente via millis dans une boucle for! et je crois que cela ne doit pas être possible. ça marche tres bien avec delay mais avec millis, je galere! donc je vais revoir mon architecture complete!

merci pour les renseignements / explications!

Ok.

Mais dans le premier code, l'utilisation de millis était bonne.

Bon ben voilà!

ça marche! j’ai transformé ma fonction getValueTemp () en bool avec retour true or false.

et attribue directement la valeur de la variable après possibilité de calculer la moyenne!

le fichier .cpp:

#include <arduino.h>
#include "TEMPmoyennePILOTEE.h"

unsigned long oldTime;

int ptr=0;  
#define NUMSAMPLES 10 //nombre de lecture
int samples[NUMSAMPLES];
int ThermistorPin = A0; //pin analogique pour sonde NTC100K



void initialiseTEMPmoyennePILOTEE(){
   
   analogReference(EXTERNAL);
   pinMode(0,INPUT);
   pinMode(12,OUTPUT);
   digitalWrite(12,LOW);
   oldTime=0;
}



bool getValueTemperature(){
          
    if(millis()-oldTime >= 500 && ptr<NUMSAMPLES) { 
      oldTime=millis();
      ReadTemp(ptr);
      ptr++;   
   }
  
   if(ptr>=NUMSAMPLES){
    return true ;   
     }
   
   else {
    return false;
   }
}


   
float calculTemperature () {
        
      float Moyenne=0;
      
      for (int i=0; i<NUMSAMPLES; i++) {
      Moyenne += samples[i];
      }
      
      Moyenne /= NUMSAMPLES;
      
      float R1 = 10000; //valeur R a temperature ambiante
      float logR2, R2, T ;
      float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;
      
      R2 = R1 * (1023.0 / Moyenne - 1.0);
      logR2 = log(R2);
      T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
      T = T - 273.15;
      // T = (T * 9.0)/ 5.0 + 32.0; // pour affichage en degree Farhenheit
  
      ptr=0; 
           
      return (T);
      
   }



void ReadTemp(int n) {
  
   digitalWrite(12,HIGH);
   samples[n] = analogRead(ThermistorPin); 
   digitalWrite(12,LOW);

le fichier .ino:

#include "TEMPmoyennePILOTEE.h"

float TemperatureUne;
float TemperatureDeux;

void setup(){

  Serial.begin(115200); 
  Serial.println("****DEBUT_PROGRAMME****");
  Serial.println("");

  initialiseTEMPmoyennePILOTEE();
  TemperatureUne=0;
  TemperatureDeux=0;
  
}


void loop(){



  if(getValueTemperature()==true){ ;

  TemperatureUne = calculTemperature ();
  }
                                 
   if ( (TemperatureUne < (TemperatureDeux -0.5)) || (TemperatureUne > (TemperatureDeux +0.5)) ){  
      TemperatureDeux = TemperatureUne;
      Serial.print ("Temperature:");
      Serial.print (TemperatureUne);//
      Serial.println ("C");
       
   }
  
}

Il n’en reste pas moins que je ne suis pas arrivé a faire fonctionner un boucle for avec un timing via millis!!

Si quelqu’un a la réponse, voir la solution, sait on jamais, ça peut, peut être servir!

Merci pour le coup d’pate!! :wink:

Il n'en reste pas moins que je ne suis pas arrivé a faire fonctionner un boucle for avec un timing via millis!!

Je n'ai pas compris ce que tu cherches à faire. La boucle for sert à quoi?

Vileroi, je cherchais a mettre une boucle for en lieu et place de ma boucle while (dans ma premiere version).

Cela ne fonctionné pas, je suis passé par une boucle if!

Je me demandé juste si c'est moi, qui n'y arrive pas, ou si la boucle for, n'accepte tous simplement pas une utilisation de millis en tempo!(ce qui me parait bizarre, et, fait apparaître cher moi une furieuse question: Pourquoi????).

Comme j'ai pus constater que le placement/déclaration des variables était assé pointilleux, je n’écarte pas encore l’hypothèse de m'y être mal pris de part mes essais!

C'est juste, de la pure curiosité! :wink:

Bonne journée ^^

Le mieux c'est de donner un code et de dire ce qu'on attend de lui, et on peut ainsi dire pourquoi cela ne fonctionne pas.

Vileroi,

pour te donner une idée de l’architecture employée:

for(ptr=0; ptr<=NUMSAMPLES ; ptr++){ 
    (millis() - oldTime >=interval);  /// LIGNE N°2 POUR EXEMPLE
    oldTime=millis(); 
    ReadTemp(ptr);
    ptr++;
 
    Serial.print("ptr");
    Serial.print( ptr);
    Serial.println();

}

si on remplace la ligne N°2 par delay, la boucle for, respect un delai entre deux incrémentation de ptr.

Avec un interval via millis(), même dans un if, ça ne marche pas!

je fais surement un truc mal! mais après avoir fait planter ma ligne serie un certain nombre de fois!!en bidouillant! J’arrête, les : out of memorie!! MDR!

Si tu arrives a faire marcher un boucle for avec un temps d’attente via millis(), je veut bien que tu me mettent le code pour voir comment ça marche!

si c’est impossible, c’est impossible! c’est comme ça! je le saurais!! :wink:

C’est très simple de faire un temps d’attente avec une boucle for et millis()

  for (unsigned long start=millis(); millis()-start<1000;)
  {
  }

Mais depuis le début on t’explique que si tu fais une boucle avec millis, c’est bloquant comme delay()

Kamill, bonjour et merci pour l'info.

Il me semblé avoir compris que la boucle for était bloquante, cela n’empêche pas de faire différent tests, ni de voir comment on peut faire autrement. Ni de tester en condition, si effectivement!! c'est bloquant!!et comment c'est bloquant.

Perso, c'est de cette manière que j'apprend!!

j'essai le plus souvent possible de comprendre, mais je ne peut pas non plus deviner toute les subtilités de la logique de programmation..

C'est loin d’être un critique, c'est juste que ce qui peut paraître inutile aux uns, l'est peut être aux autres!

Donc je le répète! Merci pour l'info! :wink:

Au fait!

si j’ai bien compris ce que vous m’avez dit!

la boucle while de mon premier programme poster que j’utilise devrai être bloquante aussi? non?

comment ça ce fait que dans le programme complet, j’arrive a faire des print en dehors de la boucle et pendant son deroulement?

Vous entendez quoi par bloquant???

je mettrais le programme si vous voulez, mais je previens, d’abord! Il pique les n’oeils…:wink:

bloquant ça veut dire que le déroulement du programme est bloqué tant que la boucle n'est pas terminée. Bien sur le programme continue après (heureusement).

Et dans le cas de ce programme, il FAUT que la fonction soit bloquante parce que l’on a besoin des 10 valeurs. Ce n’est pas une tare. Je viens d’écrire un librairie graphique et toutes les fonctions de dessin sont bloquantes. Et cela fonctionne bien. Il n’y a pas de honte. Parfois on a besoin que la fonction ne le soit pas, mais ce n’est pas systématique. Je dirai même le contraire. Le problème qu’il y a eu au départ était justement que la fonction ne terminait pas son travail.

J’aurais tendance à dire que l’on fait des fonctions bloquantes systématiquement et une fois sur 1000, il en faut une non bloquante et on a une demande d’aide. Dans les autres, on n’a pas d’alertes.

for(ptr=0; ptr<=NUMSAMPLES ; ptr++){
    (millis() - oldTime >=interval);  /// LIGNE N°2 POUR EXEMPLE
    oldTime=millis();

Il manque un if.

Avec un if:

for(ptr=0; ptr<=NUMSAMPLES ; ptr++){
    if (millis() - oldTime >=interval);  /// LIGNE N°2 POUR EXEMPLE
    oldTime=millis();

Que la condition soit vraie ou fausse, on ne fait rien. En fait il faut que la ligne 2 soit bloquante, comme le delay (preuve: ça fonctionne avec delay). Si on veut attendre avec millis il faut quelque chose qui recommencr le test tant qu’il est faux. Pas seulement une fois. → while ou do while. Par exemple:

for(ptr=0; ptr<=NUMSAMPLES ; ptr++){
    while (millis() - oldTime >=interval);  /// LIGNE N°2 POUR EXEMPLE
    oldTime=millis();

Les gars, merci pour votre implication.

Vileroi, chez moi ça ne marche pas!! que ce soit le IF ou le WHILE derrière le for!! les deux partent en sucette!

(entre nous, WHILE pire que IF) Le comportement n'as rien a voir par rapport a celui avec delay!!

pas grave! j'ai acquis le truc! dans tous les cas c'est bloquant ;)!! autant pas ce prendre la tête, envoyer du delay!!

tu peut faire un essai simple si ça marche cher toi! je veut bien essayer ton code derrière, mais j'en suis a trop de plantade de mon cote pour insister!! :wink:

je vois que dans ton exemple, tu n'as pas mis d'accolade derrière le if! Bon je me suis dit: peut être c'est ça l'astuce!! mais que nenni!

je vais garder la boucle IF seule! elle fait le job! ça me vas!

Kamill, en fait j'ai compris! ça bloque sur 1 et un seul cycle de la boucle! d'ou les multiples de 200ms dans mon print ecran!

pour moi, bloquant c’était: tant que le FOR n'est pas terminer (autrement dit! pour cette exemple, je voyais mon truc bloquer pendant 2 secondes (10x200ms))!! et là ça change énormément niveau vision du truc!!

le mot "bloquant" en fait est traitre, car il bloque la lecture de loop en court! mais ne stop pas les incrémentations d' interruptions millis() ou autres timers!!

fallait le savoir quoi!!

Merci pour vos retours, ça m'as permis de comprendre un peut plus et d’appréhendé autrement ma vision!

Aller! je passe aux lectures series, je sens que je vais bien m'amuser!!

bonne soirée!