J'ai un projet de mesure du vent et de la température en cours qui fonctionne mais avec un message alarmant lors de la compilation : "Mémoire disponible faible, des problèmes de stabilité pourraient survenir".
Quelqu'un pourrait-il m'aider à optimiser le code et voir comment récupérer de la mémoire dynamique ?
J'ai bien quelques pistes :
Moyenne de la vitesse avec un tableau de 48 mesures pour une moyenne sur 2 mn (c'est court, j'aurais aimé 5 mn soit 120 mesures;
Moyenne de la direction du vent, idem ci dessus;
Bibliothèque "cactus_io_DS18B20.h" ?
Merci pour votre aide.
Fitness04
//Capteur anémomètre-Girouette DAVIS
//Inspiré du site ci dessous
//http://cactus.io/hookups/weather/anemometer/davis/hookup-arduino-to-davis-anemometer-software
#include <SPI.h>
#include <Ethernet.h>
#include "TimerOne.h"
#include <math.h>
#include "cactus_io_DS18B20.h"
#define TX_Pin 8
#define DS18B20_Pin 9
#define WindSensor_Pin (2)
#define WindVane_Pin (A2)
#define VaneOffset 0
volatile unsigned long tipCount;
volatile unsigned long contactTime;
volatile unsigned int timerCount;
volatile unsigned long rotations;
volatile unsigned long contactBounceTime;
const float DEG2RAD = 3.14156 / 180.0; // convert degrees to radian
const float RAD2DEG = 180 / 3.14156; //convert radian to degrees
float winDir[48];
float sinSum = 0;
float cosSum = 0;
volatile float windSpeed;
volatile float xMin;
int vaneValue;
int vaneDirection;
int calDirection;
int lastDirValue;
float minTemp;
float maxTemp;
const int numReadings = 48;//2mn
const int numReadingsDir = 48;//2mn
int readings[numReadings];
int readIndex = 0;
int total = 0;
int windDirection = 0;
int windSpeedMax = 0;
int averageSpeed = 0;
int readingsDir[numReadingsDir];
int readIndexDir = 0;
int avg_windDirection = 0;
int avgWinDir = 0;
String girouette = "";
DS18B20 ds(DS18B20_Pin); // on digital pin 9
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 1, 19);
EthernetServer server(80);
void setup() {
lastDirValue = 0;
rotations = 0;
timerCount = 0;
ds.readSensor();
minTemp = ds.getTemperature_C();
maxTemp = ds.getTemperature_C();
// disable the SD card by switching pin 4 high
pinMode(4, OUTPUT);
digitalWrite(4, HIGH);
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
Serial.begin(9600);
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0;
}
for (int readIndexDir = 0; readIndexDir < numReadingsDir; readIndexDir++) {
winDir[readIndexDir] = 0;
}
pinMode(TX_Pin, OUTPUT);
pinMode(WindSensor_Pin, INPUT);
attachInterrupt(digitalPinToInterrupt(WindSensor_Pin), isr_rotation, FALLING);
// Setup the timer interupt for 0.5 second (500 000 microSecondes)
Timer1.initialize(500000);
Timer1.attachInterrupt(isr_timer);
sei();
}
void loop() {
ds.readSensor();
// update min and max temp values
if (ds.getTemperature_C() < minTemp) {
minTemp = ds.getTemperature_C();
}
if (ds.getTemperature_C() > maxTemp) {
maxTemp = ds.getTemperature_C();
}
getWindDirection();
// Only update the display if change greater than 5 degrees.
if (abs(calDirection - lastDirValue) > 5) {
lastDirValue = calDirection;
}
EthernetClient client = server.available();
if (client) {
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
digitalWrite(TX_Pin, HIGH);
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println("Refresh: 10");
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html><body>");
client.print("<span style=\"font-size: 15px\";>");
client.print("
Vent instantane : ");
client.print(windSpeed);
client.println(" Km/h");
client.print("
Vent moyen (sur 2 mn) ");
client.print(averageSpeed);
client.println(" Km/h");
client.print("
Vent maxi ");
client.print(windSpeedMax);
client.println(" Km/h");
getWindDirection();
client.print("
Direction instantannee : ");
getHeading(calDirection);
client.print(girouette);
client.print(" - ");
client.print(calDirection);
client.print(" ° ");
getWindDirection();
client.print("
Direction moyenne (sur 2 mn) : ");
getHeading(avg_windDirection);
client.print(girouette);
client.print(" - ");
client.print(avg_windDirection);
client.print(" ° ");
client.print("
Temperature : ");
client.print(ds.getTemperature_C());
client.println(char(176));
client.println(" C");
client.print("
Temperature mini : ");
client.print(minTemp);
client.println(char(176));
client.println(" C");
client.print("
Temperature maxi : ");
client.print(maxTemp);
client.println(char(176));
client.println(" C </span>");
client.println("</html>");
digitalWrite(TX_Pin, LOW);
break;
}
if (c == '\n') {
currentLineIsBlank = true;
} else if (c != '\r') {
currentLineIsBlank = false;
}
}
}
}
delay(1);
client.stop();
Ethernet.maintain();
}//Fin loop
// isr routine for timer interrupt
void isr_timer() {
timerCount++;
if (timerCount == 5)//5 x .5 = 2.5 s
{
// convert to mp/h using the formula V=P(2.25/T)- Davis Anemometer
// V = P(2.25/2.5) = P * 0.9
//en Km/h = P * 0.9 * 1.60934
windSpeed = rotations * 0.9 * 1.60934;
// ************Calcul moyenne sur 2 mn************
total = total - readings[readIndex];
readings[readIndex] = windSpeed;
total = total + readings[readIndex];
readIndex = readIndex + 1;
if (readIndex >= numReadings) {
readIndex = 0;
}
averageSpeed = total / numReadings;
if (windSpeed >= windSpeedMax ) {
windSpeedMax = windSpeed;
}
rotations = 0;
timerCount = 0;
}
}
// interrupt handler to increment the rotation count for wind speed
void isr_rotation () {
if ((millis() - contactBounceTime) > 15 ) {
rotations++;
contactBounceTime = millis();
}
}
// Get Wind Direction
void getWindDirection() {
vaneValue = analogRead(WindVane_Pin);
// Serial.print(vaneValue);
// Serial.println();
vaneDirection = map(vaneValue, 0, 1023, 0, 360);
calDirection = vaneDirection + VaneOffset;
if (calDirection > 360)
calDirection = calDirection - 360;
if (calDirection < 0)
calDirection = calDirection + 360;
//*********Calcul Moyenne Direction**************
winDir[readIndexDir] = calDirection;
readIndexDir = readIndexDir + 1;
if (readIndexDir == numReadingsDir ) {
for (readIndexDir = 0; readIndexDir < numReadingsDir; readIndexDir++)
{
sinSum += sin((winDir[readIndexDir]) * DEG2RAD);
cosSum += cos((winDir[readIndexDir]) * DEG2RAD);
}
float avgWinDir = atan2(sinSum, cosSum);
avgWinDir = avgWinDir / DEG2RAD;
if ( avgWinDir < 0 )
{
avgWinDir += 360;
}
int windDirection = (int)avgWinDir % 360;
avg_windDirection = windDirection;
// Serial.print (windDirection);
// Serial.println ("; ");
sinSum = 0;
cosSum = 0;
readIndexDir = 0;
}
}
// Converts compass direction to heading
void getHeading(int direction) {
if (direction < 22)
girouette = (" N");
else if (direction < 67)
girouette = (" NE");
else if (direction < 112)
girouette = (" E");
else if (direction < 157)
girouette = (" SE");
else if (direction < 202)
girouette = (" S");
else if (direction < 247)
girouette = (" SO");
else if (direction < 292)
girouette = (" O");
else if (direction < 337)
girouette = (" NO");
else
girouette = (" N");
}
Théorème de Lesept : "Si tu as une erreur de compilation, quelqu'un l'a eue avant toi"
Donc, tu copies le texte de l'erreur (ou les termes les plus informatifs) dans ton browser et Google te trouvera (c'est un corollaire du théorème) un message sur un forum qui en parle. Avec un peu de bol, le problème sera résolu dans ce message...
Le tableau float winDIR[] occupe 4x48 = 192 octets de RAM
Tout ça pour y stocker quoi ? le contenu de la variable calDirection, de type int avec une valeur qui varie de 0 à 360
beurk beurk
int winDIR[48];//et hop 96 octets facilement gagnés
Et encore, 2 octets pour stocker une valeur comprise entre 0 et 360 c'est luxueux.
En se cassant un peu la tête, le tableau tomberait à 54 octets en utilisant 9 bits par mesure
Et se cassant un peu plus la tête, le tableau tomberait à 51 octets en utilisant 17 bits par paire de mesures (valeur 0 à 360x360)
Tout ça sans rien perdre en précision d'information Edit : log(361)/log(2)*48/8=50,975 donc le mini est bien à 51 octets
L'erreur souvent commise est de transformer tout de suite la donnée issue d'un capteur pour la mémoriser dans un format plus lourd (par exemple float).
Il est plus efficace de conserver un historique des valeurs brutes retournées par les capteurs, et de les convertir uniquement au moment où on veut les restituer, pour les rendre compréhensibles par un humain.
Voici le code optimisé suivant vos suggestions et surtout celles de rjnc38 pour la gestion de la vitesse max avec un travail sur la variable "rotations" et une application de la formule de vitesse à la fin du traitement, juste avant la publication.
Encore merci à tous !
//Capteur anémomètre-Girouette DAVIS
//Inspiré du site ci dessous
//http://cactus.io/hookups/weather/anemometer/davis/hookup-arduino-to-davis-anemometer-software
#include <SPI.h>
#include <Ethernet.h>
#include "TimerOne.h"
#include <math.h>
#include "cactus_io_DS18B20.h"
#define TX_Pin 8
#define DS18B20_Pin 9
#define WindSensor_Pin (2)
#define WindVane_Pin (A2)
#define VaneOffset 0
volatile unsigned long tipCount;
volatile unsigned long contactTime;
volatile unsigned int timerCount;
//volatile unsigned long rotations;
volatile unsigned int rotations;
volatile unsigned int averageRotations;
volatile unsigned long contactBounceTime;
const float DEG2RAD = 3.14156 / 180.0; // convert degrees to radian
const float RAD2DEG = 180 / 3.14156; //convert radian to degrees
int winDir[48];
float sinSum = 0;
float cosSum = 0;
volatile float windSpeed;
volatile float xMin;
int vaneValue;
int vaneDirection;
int calDirection;
int lastDirValue;
float minTemp = 0;
float maxTemp = 0;
const int numReadings = 48;//5mn
//const int numReadings = 48;//2mn
int readings[numReadings];
int readIndex = 0;
int totalRotations = 0;
int windDirection = 0;
int windSpeedMax = 0;
int rotationsMax = 0;
int averageSpeed = 0;
int readingsDir[numReadings];
int readIndexDir = 0;
int avg_windDirection = 0;
int avgWinDir = 0;
String girouette = "";
DS18B20 ds(DS18B20_Pin); // on digital pin 9
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 1, 19);
EthernetServer server(80);
void setup() {
lastDirValue = 0;
rotations = 0;
timerCount = 0;
ds.readSensor();
minTemp = ds.getTemperature_C();
maxTemp = ds.getTemperature_C();
// disable the SD card by switching pin 4 high
pinMode(4, OUTPUT);
digitalWrite(4, HIGH);
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
Serial.begin(9600);
for (int readIndex = 0; readIndex < numReadings; readIndex++) {
readings[readIndex] = 0;
}
for (int readIndexDir = 0; readIndexDir < numReadings; readIndexDir++) {
winDir[readIndexDir] = 0;
}
pinMode(TX_Pin, OUTPUT);
pinMode(WindSensor_Pin, INPUT);
attachInterrupt(digitalPinToInterrupt(WindSensor_Pin), isr_rotation, FALLING);
// Setup the timer interupt for 0.5 second (500 000 microSecondes)
Timer1.initialize(500000);
Timer1.attachInterrupt(isr_timer);
sei();
}
void loop() {
ds.readSensor();
// update min and max temp values
if (ds.getTemperature_C() < minTemp) {
minTemp = ds.getTemperature_C();
}
if (ds.getTemperature_C() > maxTemp) {
maxTemp = ds.getTemperature_C();
}
getWindDirection();
// Only update the display if change greater than 5 degrees.
if (abs(calDirection - lastDirValue) > 5) {
lastDirValue = calDirection;
}
EthernetClient client = server.available();
if (client) {
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
digitalWrite(TX_Pin, HIGH);
client.println(F("HTTP/1.1 200 OK"));
client.println(F("Content-Type: text/html"));
client.println(F("Connection: close"));
client.println(F("Refresh: 10"));
client.println();
client.println(F("<!DOCTYPE HTML>"));
client.println(F("<html><body>"));
client.print(F("<span style=\"font-size: 15px\";>"));
client.print(F("
Vent instantane : "));
client.print(windSpeed);
client.println(F(" Km/h"));
client.print(F("
Vent moyen (sur 2 mn) "));
client.print(averageSpeed);
client.println(F(" Km/h"));
client.print(F("
Vent maxi "));
client.print(windSpeedMax);
client.println(F(" Km/h"));
getWindDirection();
client.print(F("
Direction instantannee : "));
getHeading(calDirection);
client.print(girouette);
client.print(F(" - "));
client.print(calDirection);
client.print(F(" ° "));
getWindDirection();
client.print(F("
Direction moyenne (sur 2 mn) : "));
getHeading(avg_windDirection);
client.print(girouette);
client.print(F(" - "));
client.print(avg_windDirection);
client.print(F(" ° "));
client.print(F("
Temperature : "));
client.print(ds.getTemperature_C());
client.println(char(176));
client.println(F(" C"));
client.print(F("
Temperature mini : "));
client.print(minTemp);
client.println(char(176));
client.println(F(" C"));
client.print(F("
Temperature maxi : "));
client.print(maxTemp);
client.println(char(176));
client.println(F(" C </span>"));
client.println(F("</html>"));
digitalWrite(TX_Pin, LOW);
break;
}
if (c == '\n') {
currentLineIsBlank = true;
} else if (c != '\r') {
currentLineIsBlank = false;
}
}
}
}
delay(1);
client.stop();
Ethernet.maintain();
}//Fin loop
// isr routine for timer interrupt
void isr_timer() {
timerCount++;
if (timerCount == 5)//5 x .5 = 2.5 s
{
// convert to mp/h using the formula V=P(2.25/T)- Davis Anemometer
// V = P(2.25/2.5) = P * 0.9
//en Km/h = P * 0.9 * 1.60934
windSpeed = rotations * 0.9 * 1.60934;
// ************Calcul moyenne sur 2 mn avec les rotations************
totalRotations = totalRotations - readings[readIndex];
readings[readIndex] = rotations;
totalRotations = totalRotations + readings[readIndex];
readIndex = readIndex + 1;
if (readIndex >= numReadings) {
readIndex = 0;
}
averageRotations = totalRotations / numReadings;
if (rotations >= rotationsMax) {
rotationsMax = rotations;
}
averageSpeed = averageRotations * 0.9 * 1.60934;
windSpeedMax = rotationsMax * 0.9 * 1.60934;
rotations = 0;
timerCount = 0;
}
}
// interrupt handler to increment the rotation count for wind speed
void isr_rotation () {
if ((millis() - contactBounceTime) > 15 ) {
rotations++;
contactBounceTime = millis();
}
}
// Get Wind Direction
void getWindDirection() {
vaneValue = analogRead(WindVane_Pin);
// Serial.print(vaneValue);
// Serial.println();
vaneDirection = map(vaneValue, 0, 1023, 0, 360);
calDirection = vaneDirection + VaneOffset;
if (calDirection > 360)
calDirection = calDirection - 360;
if (calDirection < 0)
calDirection = calDirection + 360;
//*********Calcul Moyenne Direction**************
winDir[readIndexDir] = calDirection;
readIndexDir = readIndexDir + 1;
if (readIndexDir == numReadings ) {
for (readIndexDir = 0; readIndexDir < numReadings; readIndexDir++)
{
sinSum += sin((winDir[readIndexDir]) * DEG2RAD);
cosSum += cos((winDir[readIndexDir]) * DEG2RAD);
}
float avgWinDir = atan2(sinSum, cosSum);
avgWinDir = avgWinDir / DEG2RAD;
if ( avgWinDir < 0 )
{
avgWinDir += 360;
}
int windDirection = (int)avgWinDir % 360;
avg_windDirection = windDirection;
sinSum = 0;
cosSum = 0;
readIndexDir = 0;
}
}
// Converts compass direction to heading
void getHeading(int direction) {
if (direction < 22)
girouette = (" N");
else if (direction < 67)
girouette = (" NE");
else if (direction < 112)
girouette = (" E");
else if (direction < 157)
girouette = (" SE");
else if (direction < 202)
girouette = (" S");
else if (direction < 247)
girouette = (" SO");
else if (direction < 292)
girouette = (" O");
else if (direction < 337)
girouette = (" NO");
else
girouette = (" N");
}