delai avec millis() qui fait des trucs randoms

Salut !
je voudrais effectuer des mesures de températures à intervalle régulier, et pouvoir changer le délais avec un potentiomètre. je fais donc ceci au niveau du code :

void setup()
{
   //du bordel, initialisation de la carte sd et du capteur de température

   temps = millis();
}

void loop()
{
  secondes = map(analogRead(0), 0, 1024, 10, 121);
  Serial.println(secondes);
  
  if ((millis() - temps) > (secondes * 1000))
  {
   //mesure de la temperature et écriture sur la carte sd
   Serial.println("mesures en cours");

    temps = millis();
  }
}

ça doit donc normalement choisir un délais entre 10 et 120 secondes et effectuer les mesures une fois ce délais atteint. Le problème, c'est qu'à chaque fois que le potentiomètre arrive à mi-course (secondes ~60) la mesure s'effectue, quel que soit le délais précédemment écoulé...
est-ce un erreur de code ou le matériel qui est planté ?
le potentiomètre est un module grove branché sur A0 via le shield.

PS:je précise que toutes les valeurs que Serial.println(secondes) me renvoie sont "cohérentes" : ca augmente régulièrement, de 0 à 120, c'est juste au passage d'une valeur entre 60 et 70 (66 je crois mais pas certain) ça déclenche l'action, je suis même tombé sur une fois ou le moniteur série affichait un intervalle de 60 environ mais les actions se faisaient toutes les quelques secondes, sans rien toucher.

Si quelqu’un à la solution, merci !

Bonjour,

Il faut mettre le programme en entier. On ne voit pas la définition des variables.
Est ce que temps et secondes sont bien définis en unsigned long?

voici le code complet :

#include <SPI.h>
#include <SD.h>
#include <OneWire.h>

File Temperatures;
OneWire ds(2);
long temps = 0;
int secondes;
float temperature;
String ligneAEcrire;

void setup() 
{
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) 
  {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  
  Serial.print("Initialisation du lecteur SD...");
  if (!SD.begin(4)) 
  {
    Serial.println("Initialisation échouée !!");
    while (1);
  }
  Serial.println("Initialisation terminée.");

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  Temperatures = SD.open("temp.csv", FILE_WRITE);

  // if the file opened okay, write to it:
  if (Temperatures) 
  {
    Serial.print("Ecriture sur temp.csv...");
    Temperatures.println(' ');
    Temperatures.println("Heure :, Teperature :,");
    // fermeture du fichier:
    Temperatures.close();
    Serial.println("terminé");
  } else 
  {
    // if the file didn't open, print an error:
    Serial.println("erreur a l'ouverture du fichier, impossible d'initialiser");
  }
  
  temps = millis(); //initialisation du temps
}

void loop()
{
  secondes = map(analogRead(0), 0, 1024, 10, 121);
  Serial.println(secondes);
  
  if ((millis() - temps) > (secondes * 1000))
  {
    Serial.println("mesure de la température...");
    temperature = getTemperature(); // on mesure la temperature

    ligneAEcrire = millis()
    ligneAEcrire += temperature
    
    temps = millis();
  }
}

//---------------------------------------------------------------SD-------------------------------------------------
void ecrireSD(String ligne)
{
  Temperatures = SD.open("temp.csv", FILE_WRITE);

    if (Temperatures) 
    {
      Serial.print("Ecriture de la température...");
      Temperatures.println(ligne);
      // close the file:
      Temperatures.close();
      Serial.println("terminé");
    } else 
    {
      // if the file didn't open, print an error:
      Serial.println("erreur a l'ouverture du fichier, impossible de stocker les données.");
    }
}

//-------------------------------------------------------------Temperature-------------------------------------------
float getTemperature()
{
  byte i;
  byte data[12];
  byte addr[8];
  float temp = 0.0;

  //Il n'y a qu'un seul capteur, donc on charge l'unique adresse.
  ds.search(addr);

  // Cette fonction sert à surveiller si la transmission s'est bien passée
  if (OneWire::crc8( addr, 7) != addr[7]) 
  {
    Serial.println("getTemperatureDS18b20 : <!> CRC is not valid! <!>");
    return false;
  }

  // Demander au capteur de mémoriser la température et lui laisser 850ms pour le faire (voir datasheet)
  ds.reset();
  ds.select(addr);
  ds.write(0x44);
  delay(850);
  // Demander au capteur de nous envoyer la température mémorisé
  ds.reset();
  ds.select(addr);
  ds.write(0xBE);

  // Le MOT reçu du capteur fait 9 octets, on les charge donc un par un dans le tableau data[]
  for ( i = 0; i < 9; i++) 
  {
    data[i] = ds.read();
  }
  // Puis on converti la température (*0.0625 car la température est stockée sur 12 bits)
  temp = ( (data[1] << 8) + data[0] )*0.0625;

  return temp;
}

temps est un long, et j’ai oublié le unsigned, mais pourquoi secondes devrait être long aussi ? la valeur ne change que entre 10 et 120, int suffit non ?

secondes ne doit pas être obligatoirement long, mais ceci (secondes * 1000) doit être unsigned long sinon il y a débordement.
Soit tu déclares secondes comme unsigned long soit tu forces unsigned long sur la constante et tu écris (secondes * 1000UL)

Ok, j’essaierais ça la prochaine fois, mais ça peut avoir causé des problèmes sur presque UNE SEULE valeur ? Toutes les autres fonctionnaient, que ce soit au dessus ou en dessous de 60...

Comment savez vous que ça fonctionnait ? Le débordement va donner une valeur plus ou moins farfelue (mais très mathématique)

eh bien toutes les valeurs fonctionnait sauf autour de 60 car :
-le moniteur série m'affichait des valeurs croissantes et cohérentes, entre 10 et 120
-et surtout car pour tous les intervalles autres, j'avais bien le délais voulu entre chaque mesure et écriture, sauf pour 60.

c'est pour cela qu'une erreur de déclaration de variable m'étonne un peu, mais dès que j'aurais à nouveau le matériel je ferais le test pour vérifier

Le potentiomètre est neuf ou c’est du matériel d’occasion? La piste peut être abîmée à cet endroit précis

Vous n’imprimez que secondes pas le résultat des maths. Si votre potentiomètre fonctionne vous verrez un nombre entre 10 et 120.

Ensuite cependant Tout dépend de la représentation d’un int sur votre architecture 16 bits ou 32 bits. Sur un UNO c’est 16 bits.

Secondes est un int et par défaut quand vous écrivez juste 1000 le compilateur met cette variable dans le plus petit type signé capable de représenter cette valeur à partir d’un int. Ici 1000 rentre dans un int donc sera un int

Quand le compilateur voit deux int dans une opération il met le résultat dans un int

Un int sur UNO standard tient sur 2 octets - Donc va varier entre -32768 et +32767

Si vous êtes à 32767 et ajoutez 1 le résultat devient donc -32768, c’est ce qu’on appelle le débordement/ rollover

Vos secondes varient entre 10 et 120 compris et vous multipliez ça par 1000

de 10 à 32 pas de soucis ça fait de 10000 à 32000 ça rentre dans un int

mais Par exemple à 33 vous obtenez 33000 et ça ne ne rentre plus, le résultat du calcul fait -32536 pour votre arduino

millis() retourne un unsigned long et des math entre entiers signés et non signés devient non signé donc votre millis()-temps sera toujours positif ou nul et vous avez des long donc c’est un unsigned long

Donc quand vous comparez votre millis()-temps avec un nombre négatif c’est tout de suite vrai

à 60 x 1000 votre 60000 devient -5536 donc c’est pareil

à 70 x 1000 vous avez 70000 qui devient 4464 (si je ne me suis pas gouré dans mes maths) donc vous n’avez pas un déplaît de 70 secondes mais juste un peu plus de 4 secondes

Imprimez la valeur Serial.println (secondes * 1000); juste avant votre test et vous verrez ce qu’il en est (ensuite il se peut que le compilateur optimise des choses pour vous et donc activez les warnings à la compilation pour voir ce qu'il en est)

Pour vous convaincre des maths, essayez le code suivant:

volatile int secondes; // volatile pour éviter les optimisations du compilo

void setup() {
  Serial.begin(115200);
  for (secondes = 10; secondes < 121; secondes++) {
    Serial.print(secondes); 
    Serial.print(F("\t-> "));
    Serial.println(secondes * 1000);
  }
}

void loop() {}

Vous verrez alors dans la console série (regardez pour 33 on a le dépassement que j’ai marqué):

10	-> 10000
11	-> 11000
12	-> 12000
13	-> 13000
14	-> 14000
15	-> 15000
16	-> 16000
17	-> 17000
18	-> 18000
19	-> 19000
20	-> 20000
21	-> 21000
22	-> 22000
23	-> 23000
24	-> 24000
25	-> 25000
26	-> 26000
27	-> 27000
28	-> 28000
29	-> 29000
30	-> 30000
31	-> 31000
32	-> 32000
33	-> -32536    // <<=== OVERFLOW / ROLLOVER
34	-> -31536
35	-> -30536
36	-> -29536
37	-> -28536
38	-> -27536
39	-> -26536
40	-> -25536
41	-> -24536
42	-> -23536
43	-> -22536
44	-> -21536
45	-> -20536
46	-> -19536
47	-> -18536
48	-> -17536
49	-> -16536
50	-> -15536
51	-> -14536
52	-> -13536
53	-> -12536
54	-> -11536
55	-> -10536
56	-> -9536
57	-> -8536
58	-> -7536
59	-> -6536
60	-> -5536
61	-> -4536
62	-> -3536
63	-> -2536
64	-> -1536
65	-> -536
66	-> 464
67	-> 1464
68	-> 2464
69	-> 3464
70	-> 4464
71	-> 5464
72	-> 6464
73	-> 7464
74	-> 8464
75	-> 9464
76	-> 10464
77	-> 11464
78	-> 12464
79	-> 13464
80	-> 14464
81	-> 15464
82	-> 16464
83	-> 17464
84	-> 18464
85	-> 19464
86	-> 20464
87	-> 21464
88	-> 22464
89	-> 23464
90	-> 24464
91	-> 25464
92	-> 26464
93	-> 27464
94	-> 28464
95	-> 29464
96	-> 30464
97	-> 31464
98	-> 32464
99	-> -32072
100	-> -31072
101	-> -30072
102	-> -29072
103	-> -28072
104	-> -27072
105	-> -26072
106	-> -25072
107	-> -24072
108	-> -23072
109	-> -22072
110	-> -21072
111	-> -20072
112	-> -19072
113	-> -18072
114	-> -17072
115	-> -16072
116	-> -15072
117	-> -14072
118	-> -13072
119	-> -12072
120	-> -11072

la valeur prise par le résultat du calcul pour une valeur donnée de secondes entre 10 et 120

Ok, merci beaucoup, j'oublie toujours que int accepte des valeurs allant "seulement" jusqu’à 32000... et aussi qu'en millisecondes ça augmente vite...

Du coup il faudrait juste que je remplace temps et secondes par des unsigned long c'est ça ?

Jambe:
Le potentiomètre est neuf ou c’est du matériel d’occasion? La piste peut être abîmée à cet endroit précis

étant donné que quand les secondes étaient à 66 les mesures se faisaient à répétition, et que comme on le voit dans la table de J-M-L ça fait un intervalle de 400ms, je pense que le problème est encore une fois causé par une de mes erreurs de code...

J'essairais tout ça vendredi prochain, merci !

Oui mettez tout ce qui concerne le temps en unsigned long et faites des soustractions pas des additions quand vous devez comparer des durées - c’est à dire faites

if (millis() - tempsPrecedent > duree) {...

Et pas

if (millis() > tempsPrecedent + duree) {...

Car l’addition risque de générer un overflow

j’utilisais déjà une soustraction, donc c’est bon (même d’un point de vue logique je trouve ça mieux de comparer le temps écoulé à l’intervalle que l’autre méthode) !

Oui c’était juste au cas où vous aviez fait cela juste « pour faire beau », il y a une raison mathématique et technique pour l’écrire ainsi :slight_smile: