Go Down

Topic: Amperometro con arduino (Read 9231 times) previous topic - next topic

elvis

Ciao a tutti,
     ho trovato il seguente codice su openenergy:
Code: [Select]

#include "EmonLib.h"                   // Include Emon Library
EnergyMonitor emon1;                   // Create an instance
EnergyMonitor emon2;                   // Create an instance


void setup()

  Serial.begin(9600);
 
  emon1.current(3, 111.1);             // Current: A3 input pin, calibration.
    emon2.current(4, 111.1);             // Current: A4 input pin, calibration.

}

void loop()
{
    double Irms1 = emon1.calcIrms(1480);  // Calculate Irms only
    double Irms2 = emon2.calcIrms(1480);  // Calculate Irms only

 
  Serial.print("Potenza Generata dal FV Kw: ");
  Serial.println(Irms1);        // Irms
 
  Serial.print("Potenza Consumata in Casa Kw: ");
  Serial.println(Irms2);        // Irms
}


funziona perfettamente, ma se inserito in un altro codice che ho già in funzione su arduino, mi rallenta tutto il processo.
Qualcuno mi sa spiegarne il motivo? Dipende dalla libreria? E' possibile velocizzarlo?
Più o meno ottengo due letture al secondo, ma arduino non fa circa 60 cicli al sec?

Grazie

PaoloP


Più o meno ottengo due letture al secondo, ma Arduino non fa circa 60 cicli al sec?


Con il loop, quasi vuoto, a seconda delle ottimizzazioni, Arduino compie anche 230 mila cicli al secondo. (http://arduino.cc/forum/index.php/topic,141254.msg1061034.html#msg1061034)

leo72

Probabilmente la lentezza deriva dalla libreria usata. Se fa uso intenso di calcoli in virgola mobile il problema è lì perché l'unità aritmetica dell'Atmega gestisce solo calcoli interi in HW. Se vuoi accelerare il processo forse dovresti ricorrere all'uso di una MCU più potente oppure di una ALU esterna.

elvis

Ciao Leo72,
    Scusa la mia ignoranza ma non ho idea di cosa siano HW, MCU, ed ALU...
Dovrei quindi modificare la libreria EmonLib?
Grazie

nid69ita

HW   hardware
MCU  unità microprocessore
ALU  unità aritmetico-logica (coprocessore matematico)
my name is IGOR, not AIGOR

leo72


Dovrei quindi modificare la libreria EmonLib?

No. Ti sto dicendo che la lentezza registrata potrebbe essere data proprio dalla libreria stessa e dal tipo e quantità di calcoli che essa esegue.

elvis

... quindi, mi sembra di capire, non ci posso far nulla....

leo72

Scrivi che il problema nasce nel momento in cui inserisci le letture in un altro codice.
Non è che è l'altro codice che rallenta questo e non viceversa?

pitusso

Ciao,
con la libreria EmonLib ci ho giocato parecchio, di fatto ci ho aggiunto altri sensori (temperatura, luce, etc ) e shield Wifi/Eth con relative librerie.
Non ho riscontrato nessun problema.

Prova a postare il codice che utilizzi e che ti da problemi!

elvis

Fondamentalmente il mio interesse è vedere la corrente misurata dai TA su cosm im modo d'aver sotto controllo la potenza generata dal mio impianto fotovoltaico.

Ho già un codice che "gira" molto bene con il quale visualizzo su cosm i dati dell'impianto termosolare. Refresh dei dati ogni 45"... Perfetto.
Aggiungendo le poche righe per il controllo dei TA, arduino rallenta e le letture su cosm avvengono ogni 4 min. circa.

Fondamentalmente il refresh dei dati su cosm avviene ogni 250 cicli...

4 minuti non è comunque male... ma mi piacerebbe rimanere sui 45"...

elvis

Questo è il codice di partenza:
Code: [Select]

/* IDE 1.0.1
modified by Ettore Massimo Albani
*/

#include <SPI.h>
#include <Ethernet.h>

#define APIKEY         "XXXXXXXXXXXXXXXXXXXXXXXXXX"   
#define FEEDID         XXXXXX
#define USERAGENT      "TEST 2"   
byte mac[] = {   
  0xDE, 0xAD, 0xBC, 0xEF, 0xFE, 0xBD};
IPAddress ip(192, 168, 11, 21);
EthernetClient client;   
char server[] = "api.cosm.com"; 
unsigned long lastConnectionTime = 0; 
boolean lastConnected = false;
const unsigned long postingInterval = 10000;
String DataString = "";
char Buffer[10];                                           
int otherSensorReadingAria = 0; 
int otherSensorReadingCaldaia = 0;
int otherSensorReadingResistenza2Kw = 0;
int caldaiaON = 0;                                          //*INGRESSO digitale PER CONTROLLO WEB STATO CALDAIA
int Ventola = 0;                                            //*INGRESSO digitale PER CONTROLLO WEB STATO VENTOLA
int ResistenzaON = 0;                                            //*INGRESSO digitale PER CONTROLLO WEB STATO resistenza
const float AnaRef = 5.0;                                   // valore tensione (5V)
const unsigned int Risoluzione = 1024;                      // risoluzione (10 bit)
const float RangeMin = 2.0;                                 // temperatura minima °C sensore LM35DZ (alim. 5V, out con res. 2k in serie)
const float RangeMax = 100.0;                               // temperatura massima °C sensore LM35DZ (alim. 5V, out con res. 2k in serie)
const float Incremento = 0.01;                              // incremento (10 mV/°C)
float Volt = 0;                                             // valore sensori analogici in volt
const float Isteresi = 1.0;                                 // isteresi (1 °C)
float TempAria = 0.0;                                       // temperatura aria
float TempAriaMin = 2.0;                                    // soglia inferiore temperatura aria (min 2 °C = RangeMin)
float TempAriaMax = 30.0;                                   // soglia superiore temperatura aria (max 100 °C = RangeMax)
float TempAcquaOUTtermosolare = 0.0;                                      // temperatura acqua
float TempAcquaMin = 2.0;                                   // soglia inferiore temperatura acqua (min 2 °C)
float TempAcquaMax = 43.0;                                  // soglia superiore temperatura acqua (max 100 °C)
float TempAcquaINGTermosolare = 0.0;                                      // temperatura acqua in ingresso al termosolare
extern unsigned long timer0_millis;
float mela;
void setup() {
mela=1;
  analogReference(DEFAULT);                                 // DEFAULT (5V), INTERNAL (1,1V), EXTERNAL (0÷5V)

  pinMode(A0, INPUT);                                       // NB sensore di temperatura aria
  pinMode(A1, INPUT);                                       // sensore di temperatura acqua
  pinMode(A2, INPUT);                                       // sensore di temperatura acqua ingresso termosolare
  pinMode(2, OUTPUT);                                      // D2 uscita per relè in parallelo alla resistenza da 2Kw installata sul bollitore
  pinMode(3, INPUT);                                       //*D3 ingresso controllo stato ventola da D5   
  pinMode(4, INPUT);                                       //*D4 ingresso controllo stato caldaia da D6
  pinMode(5, OUTPUT);                                       //*USCITA IN PARALLELO AL RELE CALDAIA PER VISUALIZZAZIONE WEB STATO VENTOLA   
  pinMode(6, OUTPUT);                                       //*USCITA IN PARALLELO AL RELE ACQUA PER VISUALIZZAZIONE WEB STATO CALDAIA 
 
  pinMode(7, OUTPUT);                                       // relay ventola ON/OFF
  pinMode(8, OUTPUT);                                       // relay caldaia ON/OFF
  pinMode(9, INPUT);                                        // D10 ingresso per relè in parallelo alla resistenza da 2Kw installata sul bollitore
  Serial.begin(9600);

  if (Ethernet.begin(mac) == 0) {                           // start the Ethernet connection
    Ethernet.begin(mac, ip);                                // DHCP failed, so use a fixed IP address
    Serial.println("Failed to configure Ethernet using DHCP");
  }
}

void loop() {
    digitalWrite(2, HIGH);           
    Ventola = digitalRead(3); 
    caldaiaON = digitalRead(4);
    ResistenzaON = digitalRead(9);
  Volt = analogRead(A0) * 0.5;
  TempAria = Volt;
  delayMicroseconds(120);
  Volt = analogRead(A1) * 0.5;
  TempAcquaOUTtermosolare = ((Volt)+3);                 // temperatura acqua in °C +X°C PER COMPENSAZIONE TERMOMETRO TRIVALVOLA
  delayMicroseconds(120);                                   // 120 µs (min time reading = 100 µs x channel)
  Volt = analogRead(A2) * 0.5;             // valore sensore acqua in volt
  TempAcquaINGTermosolare = ((Volt)+3);                 // temperatura acqua in °C +X°C PER COMPENSAZIONE TERMOMETRO TRIVALVOLA
  delayMicroseconds(120);                                   // 120 µs (min time reading = 100 µs x channel)
  Serial.print("Temp. Aria: ");
  Serial.println(TempAria, 1);
    otherSensorReadingAria = Ventola; 
  Serial.print("Temp. Acqua: ");
  Serial.println(TempAcquaOUTtermosolare, 1);
   otherSensorReadingCaldaia = caldaiaON;
   Serial.print("Temp. Acqua Ing Termosolare: ");
  Serial.println(TempAcquaINGTermosolare);

  if (TempAria > (TempAriaMax + Isteresi)) {
    digitalWrite(7, HIGH);                                 // relay ventola ON
    digitalWrite(5, HIGH);                                 //*VENTILAZIONE ATTIVATA
    Serial.println("Aria calda - Ventola ON");
  }
  else if (TempAria < (TempAriaMax - Isteresi)) {
    digitalWrite(7, LOW);                                   // relay ventola OFF
    digitalWrite(5, LOW);                                    //*VENTILAZIONE DISATTIVATA
    Serial.println("Aria fredda - Ventola OFF");
  }
if ((TempAcquaOUTtermosolare > (TempAcquaMax + Isteresi)) && mela==1) (timer0_millis = 0, mela = 0 );

  if (TempAcquaOUTtermosolare > (TempAcquaMax + Isteresi) && (millis()>30000)) {
   digitalWrite(8, LOW);                                   // relay caldaia OFF
       digitalWrite(6, LOW);                               //*USCITA IN PARALLELO AL SEGNALE CALDAIA PER TELECONTROLLO
    Serial.println("Acqua Calda - Caldaia OFF");
  }
  else if (TempAcquaOUTtermosolare < (TempAcquaMax - Isteresi)) {
    digitalWrite(8, HIGH);                                  // relay caldaia ON
        digitalWrite(6, HIGH);        //*USCITA IN PARALLELO AL SEGNALE CALDAIA PER TELECONTROLLO
    mela=1;
    Serial.println("Acqua fredda - Caldaia ON");
  }
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }
  if (!client.connected() && lastConnected) {
    Serial.println();
    Serial.println("disconnecting...");
    client.stop();
  }
  if (millis() < lastConnectionTime) lastConnectionTime = millis();    // evita il blocco dopo 50gg poiché millis() si azzer
  if (!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
    DataString = "TempAria,";
    DataString += FloatFormat(TempAria, 10, 1, false, true);
    DataString += "\nVentola,";
  DataString += otherSensorReadingAria;
   DataString += "\nResistenzaON,";
    DataString += FloatFormat(ResistenzaON, 10, 1, false, true);
  DataString += "\nTempAcquaINGTermosolare,";
    DataString += FloatFormat(TempAcquaINGTermosolare, 10, 1, false, true);
    DataString += "\nTempAcquaOUTtermosolare,";
    DataString += FloatFormat(TempAcquaOUTtermosolare, 10, 1, false, true);
    DataString += "\nCaldaia,";
  DataString += otherSensorReadingCaldaia;
    sendData(DataString);
  }
  lastConnected = client.connected();
}
void sendData(String thisData) {
  if (client.connect(server, 80)) {
    Serial.println("connecting...");
    client.print("PUT /v2/feeds/");
    client.print(FEEDID);
    client.println(".csv HTTP/1.1");
    client.println("Host: api.cosm.com");
    client.print("X-ApiKey: ");
    client.println(APIKEY);
    client.print("User-Agent: ");
    client.println(USERAGENT);
    client.print("Content-Length: ");
    client.println(thisData.length());
    client.println("Content-Type: text/csv");
    client.println("Connection: close");
    client.println();
    client.println(thisData);
    Serial.println(thisData);
  }
  else {
    // if you couldn't make a connection:
    Serial.println("connection failed");
    Serial.println();
    Serial.println("disconnecting...");
    client.stop();
  }
  // note the time that the connection was made or attempted:
  lastConnectionTime = millis();
}
String FloatFormat(float X, char Size, unsigned char Decimal, boolean Plus, boolean AutoReduce) {
  char Buffer[Size + 1];
  String Z = dtostrf(X, Size, Decimal, Buffer);
  if (Plus && X > 0) Z[Z.lastIndexOf(' ')] = '+';
  if (AutoReduce) Z.trim();
  return Z;


pitusso

Ciao,
io sparo i dati su EmonCms (del progetto OpenEnergyMonitor) ogni 10 secondi.
Ripeto, senza problemi.

Prova a postare il tuo codice, senza quello si possono solo fare congetture.
Ora che hai postato il codice, c'è qualcosa in più su cui fare valutazioni

elvis

Ciao Pitusso,
    Hai visto il codice?
Riesci a darmi qualche consigli?
Ma come fai a inviare dati su cosm ogni 10"?

elvis

Rieccomi a chiedere aiuto.

Su questo progetto sto utilizzando la libreria EmonLib trovata su openenergymonitor. Tale libreria è stata "costruita" per calcolare:
- corrente
- tensione
- potenza

EmonLib.h:

Code: [Select]

/*
 Emon.h - Library for openenergymonitor
 Created by Trystan Lea, April 27 2010
 GNU GPL
*/

#ifndef EmonLib_h
#define EmonLib_h

#if defined(ARDUINO) && ARDUINO >= 100

#include "Arduino.h"

#else

#include "WProgram.h"

#endif

class EnergyMonitor
{
 public:

   void voltage(int _inPinV, double _VCAL, double _PHASECAL);
   void current(int _inPinI, double _ICAL);

   void voltageTX(double _VCAL, double _PHASECAL);
   void currentTX(int _channel, double _ICAL);

   void calcVI(int crossings, int timeout);
   double calcIrms(int NUMBER_OF_SAMPLES);
   void serialprint();

   long readVcc();
   //Useful value variables
   double realPower,
      apparentPower,
      powerFactor,
      Vrms,
      Irms;

 private:

   //Set Voltage and current input pins
   int inPinV;
   int inPinI;
   //Calibration coeficients
   //These need to be set in order to obtain accurate results
   double VCAL;
   double ICAL;
   double PHASECAL;

   //--------------------------------------------------------------------------------------
   // Variable declaration for emon_calc procedure
   //--------------------------------------------------------------------------------------
int lastSampleV,sampleV;   //sample_ holds the raw analog read value, lastSample_ holds the last sample
int lastSampleI,sampleI;                      

double lastFilteredV,filteredV;                   //Filtered_ is the raw analog value minus the DC offset
double lastFilteredI, filteredI;                  

double phaseShiftedV;                             //Holds the calibrated phase shifted voltage.

double sqV,sumV,sqI,sumI,instP,sumP;              //sq = squared, sum = Sum, inst = instantaneous

int startV;                                       //Instantaneous voltage at start of sample window.

boolean lastVCross, checkVCross;                  //Used to measure number of times threshold is crossed.
int crossCount;                                   // ''


};

#endif



Avendo io bisogno di calcolare solo la corrente come posso fare ad eliminare tutti i calcoli che il mio Arduino fa e che a me non servono e che mi rallentano solo il refresh dei dati su xively?

Riuscite a darmi un consiglio?
Grazie

elvis

EmonLib.cpp

Code: [Select]



//#include "WProgram.h" un-comment for use on older versions of Arduino IDE
#include "EmonLib.h"

#if defined(ARDUINO) && ARDUINO >= 100

#include "Arduino.h"

#else

#include "WProgram.h"

#endif

// Sets the pins to be used for voltage and current sensors
void EnergyMonitor::voltage(int _inPinV, double _VCAL, double _PHASECAL)
{
  inPinV = _inPinV;
  VCAL = _VCAL;
  PHASECAL = _PHASECAL;
}

void EnergyMonitor::current(int _inPinI, double _ICAL)
{
  inPinI = _inPinI;
  ICAL = _ICAL;
}

// Sets the pins to be used for voltage and current sensors based on emontx pin map
void EnergyMonitor::voltageTX(double _VCAL, double _PHASECAL)
{
  inPinV = 2;
  VCAL = _VCAL;
  PHASECAL = _PHASECAL;
}

void EnergyMonitor::currentTX(int _channel, double _ICAL)
{
  if (_channel == 1) inPinI = 3;
  if (_channel == 2) inPinI = 0;
  if (_channel == 3) inPinI = 1;
  ICAL = _ICAL;
}

// emon_calc procedure
// Calculates realPower,apparentPower,powerFactor,Vrms,Irms,kwh increment
// From a sample window of the mains AC voltage and current.
// The Sample window length is defined by the number of half wavelengths or crossings we choose to measure.
void EnergyMonitor::calcVI(int crossings, int timeout)
{
 int SUPPLYVOLTAGE = readVcc();
 int crossCount = 0;                             //Used to measure number of times threshold is crossed.
 int numberOfSamples = 0;                        //This is now incremented  

 // 1) Waits for the waveform to be close to 'zero' (500 adc) part in sin curve.
 boolean st=false;                                  //an indicator to exit the while loop

 unsigned long start = millis();    //millis()-start makes sure it doesnt get stuck in the loop if there is an error.

 while(st==false)                                   //the while loop...
 {
    startV = analogRead(inPinV);                    //using the voltage waveform
    if ((startV < 550) && (startV > 440)) st=true;  //check its within range
    if ((millis()-start)>timeout) st = true;
 }
 
 // 2) Main measurment loop
 start = millis();

 while ((crossCount < crossings) && ((millis()-start)<timeout))
 {
   numberOfSamples++;                            //Count number of times looped.

   lastSampleV=sampleV;                          //Used for digital high pass filter
   lastSampleI=sampleI;                          //Used for digital high pass filter
   
   lastFilteredV = filteredV;                    //Used for offset removal
   lastFilteredI = filteredI;                    //Used for offset removal  
   
   // A) Read in raw voltage and current samples
   sampleV = analogRead(inPinV);                 //Read in raw voltage signal
   sampleI = analogRead(inPinI);                 //Read in raw current signal

   // B) Apply digital high pass filters to remove 2.5V DC offset (centered on 0V).
   filteredV = 0.996*(lastFilteredV+(sampleV-lastSampleV));
   filteredI = 0.996*(lastFilteredI+(sampleI-lastSampleI));
 
   // C) Root-mean-square method voltage
   sqV= filteredV * filteredV;                 //1) square voltage values
   sumV += sqV;                                //2) sum
   
   // D) Root-mean-square method current
   sqI = filteredI * filteredI;                //1) square current values
   sumI += sqI;                                //2) sum
   
   // E) Phase calibration
   phaseShiftedV = lastFilteredV + PHASECAL * (filteredV - lastFilteredV);
   
   // F) Instantaneous power calc
   instP = phaseShiftedV * filteredI;          //Instantaneous Power
   sumP +=instP;                               //Sum  
   
   // G) Find the number of times the voltage has crossed the initial voltage
   //    - every 2 crosses we will have sampled 1 wavelength
   //    - so this method allows us to sample an integer number of half wavelengths which increases accuracy
   lastVCross = checkVCross;                    
   if (sampleV > startV) checkVCross = true;
                    else checkVCross = false;
   if (numberOfSamples==1) lastVCross = checkVCross;                  
                   
   if (lastVCross != checkVCross) crossCount++;
 }

 // 3) Post loop calculations
 //Calculation of the root of the mean of the voltage and current squared (rms)
 //Calibration coeficients applied.
 
 double V_RATIO = VCAL *((SUPPLYVOLTAGE/1000.0) / 1023.0);
 Vrms = V_RATIO * sqrt(sumV / numberOfSamples);
 
 double I_RATIO = ICAL *((SUPPLYVOLTAGE/1000.0) / 1023.0);
 Irms = I_RATIO * sqrt(sumI / numberOfSamples);

 //Calculation power values
 realPower = V_RATIO * I_RATIO * sumP / numberOfSamples;
 apparentPower = Vrms * Irms;
 powerFactor=realPower / apparentPower;

 //Reset accumulators
 sumV = 0;
 sumI = 0;
 sumP = 0;
}

double EnergyMonitor::calcIrms(int NUMBER_OF_SAMPLES)
{
 
int SUPPLYVOLTAGE = readVcc();

 
 for (int n = 0; n < NUMBER_OF_SAMPLES; n++)
 {
   lastSampleI = sampleI;
   sampleI = analogRead(inPinI);
   lastFilteredI = filteredI;
   filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI);

   // Root-mean-square method current
   // 1) square current values
   sqI = filteredI * filteredI;
   // 2) sum
   sumI += sqI;
 }

 double I_RATIO = ICAL *((SUPPLYVOLTAGE/1000.0) / 1023.0);
 Irms = I_RATIO * sqrt(sumI / NUMBER_OF_SAMPLES);

 //Reset accumulators
 sumI = 0;

 return Irms;
}

void EnergyMonitor::serialprint()
{
   Serial.print(realPower);
   Serial.print(' ');
   Serial.print(apparentPower);
   Serial.print(' ');
   Serial.print(Vrms);
   Serial.print(' ');
   Serial.print(Irms);
   Serial.print(' ');
   Serial.print(powerFactor);
   Serial.println(' ');
   delay(100);
}

//thanks to http://hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino
//and Jérôme who alerted us to http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/

long EnergyMonitor::readVcc() {
 long result;

 #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
 ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);  
 #elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
 ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
 ADCSRB &= ~_BV(MUX5);   // Without this the function always returns -1 on the ATmega2560 http://openenergymonitor.org/emon/node/2253#comment-11432
 #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
 ADMUX = _BV(MUX5) | _BV(MUX0);
 #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
 ADMUX = _BV(MUX3) | _BV(MUX2);
 #endif

 delay(2); // Wait for Vref to settle
 ADCSRA |= _BV(ADSC); // Convert
 while (bit_is_set(ADCSRA,ADSC));
 result = ADCL;
 result |= ADCH<<8;
 result = 1126400L / result; //1100mV*1024 ADC steps http://openenergymonitor.org/emon/node/1186
 return result;
}



Go Up