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.
#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...
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
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)
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...
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
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) !