Leggere valori sensore Co2 MG-811

Ciao a tutti, mi sto avvicinando da poco all'elettronica, vi spiego subito cosa voglio fare: voglio leggere il valore di concentrazione di Co2 in una stanza con arduino.
Il mio problema è che non riesco a "decifrare" il valore che entra in arduino tramite la porta analogica nel valore corrispondente in ppm. Su internet alcuni usano il logaritmo e altri effettuano delle calibrazioni.
Io vorrei usare il logaritmo ma le formule che ho trovato su internet non mi danno valori corretti, sareste cosi gentili da spiegarmi come ricavare la formula per convertire il valore di arduino in ppm, dal grafico del datasheet non riesco a capire perchè è fuori scala.
Per adesso, visto che ancora non ho un arduino sto facendo solo delle simulazioni al computer.
Grazie a tutti in anticipo. :wink:

Sensore con datasheet: MG-811 CO2 Sensor Module | Sandbox Electronics
Formula che ho provato: Antilog converter linearizes carbon dioxide sensor -

Il cross-posting è vietato.
http://forum.arduino.cc/index.php?topic=304868.msg2119798#msg2119798

Poi in sezione internazionale DEVI usare l'inglese.

Ti invitiamo a presentarti (dicci quali conoscenze hai di elettronica e di programmazione) qui: Presentazioni
e a leggere il regolamento: Regolamento

Si, avevo sbagliato sezione, adesso mi presento :slight_smile:

ma scusa, al link che hai nesso tu stesso MG-811 CO2 Sensor Module | Sandbox Electronics c'è anche il codice bello e fatto!

credo di non avere capito la domanda!

La formula del secondo link fa riferimento al solo sensore (range uscita 265-325 mV).

Il primo link, invece, fa riferimento al modulo che comprende anche un amplificatore operazionale per aumentare il segnale in uscita sino ai 5V di Arduino.

Intanto vi ringrazio, il problema è che anche con i calcoli di sandboxelectronics mi da dei risultati errati.
Cyberhs sapresti dirmi come fare per ottenere la formula con il logaritmo con il sensore montato sul modulo?

Fammi vedere il tuo listato che provo a verificarlo.

Ok, il programma è questo, spero che tu riesca a capire:

#include <LiquidCrystal_I2C.h>
#include <Wire.h> 
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display
const int apertura = 13;
const int chiusura = 12;
const int analogPin = A0;
int ValoreConvertire;
int Valoreppm;
int stato = 1; //imposto inizialmente la finestra chiusa
float deltavs;
float v400ppm = 4.535;   //IMPOSTARE CON CALIBRAZIONE   /_____________________________________
float v40000ppm = 3.206; //IMPOSTARE CON CALIBRAZIONE   \
float deltavs = (v400ppm - v40000ppm);
float A = deltavs/(log10(400) - log10(40000));
float B = log10(400);

//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void setup() {
  pinMode(apertura, OUTPUT); //definisce i pin apertura e chiusura come output
  pinMode(chiusura, OUTPUT);
  // inizia comunicazione seriale a 9600
  Serial.begin(9600);
  lcd.init();
}

//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void loop() {
  int ValoreConvertire = analogRead(analogPin); //legge valore da sensore
  float voltaggio = ValoreConvertire/204.6; //converte valore da sensore in voltaggio
  float power = ((voltaggio - v400ppm)/A) + B; //calcola CO2 con formula e logaritmo
  float co2ppm = pow(10,power);
  Valoreppm = co2ppm;
  lcd.home();
  lcd.print("Co2 in ppm = ");
  lcd.print(Valoreppm);
  // attiva pin 13 apertura se valore ppm superiore a 1300
  if ((Valoreppm>1300)&&(stato == 1)){
    lcd.home();
    lcd.print("Valore superiore a 1300ppm... ");
    digitalWrite(chiusura, LOW); // spengo segnale di chiusura voglio essere sicuro che il segnale di chiusura sia spento, il motore si era gia spento dal circuito fisico con fc
    lcd.setCursor(0,1);
    lcd.print("Apro la finestra");
    digitalWrite(apertura, HIGH); //faccio partire l'apertura con circuito fisico si ferma quando aperta del tutto
    stato = 1 - stato; //0 = finestra aperta o in apertura
  }
  if ((Valoreppm<800)&&(stato == 0)){
    lcd.home();
    lcd.print("Valore inferiore a 800ppm... ");
    digitalWrite(apertura, LOW); //spengo o lascio spento il segnale di apertura voglio essere sicuro che il segnale di apertura sia spento, il motore era già spento dal circuito fisico con fc
    lcd.setCursor(0,1);
    lcd.print("Chiudo la finestra");
    digitalWrite(chiusura, HIGH); //faccio partire la chiusura con circuito fisico si ferma quando chiusa del tutto
    stato = 1 - stato; //0 = finestra chiusa o in chiusura

  }
  delay(5000); //aspetta mezzo secondo prima di ripartire
}

Se hai il modulo della Sandbox devi usare il loro software, eventualmente modificato per le tue esigenze.

Comunque, ho notato che leggi solo una volta l'ingresso analogico: devi fare almeno 10 misure e fare la media dei valori.

float voltaggio = ValoreConvertire / 204.6;

Non capisco da dove hai tirato fuori questa conversione.

L'amplificatore del modulo amplifica il segnale di 8.5 volte quindi il massimo che leggerai sarà 8.5 x 322mV = 2.74V: considerando che il convertitore ha un passo di circa 5mv dovresti leggere il valore 548.

Hai usato poi la costante float v40000ppm = 3.206; ma quel sensore ha un range sino a 10000 ppm.

Grazie mille! Il codice l'avevo preso da questo sito: http://www.projectems.it/monitoraggio-ambientale-monitoraggio-co2-arduino/
Su alcuni calcoli ero in dubbio anche io ma non sapevo cosa fare. Il programma di sandbox è questo, prima di provarlo mi potresti dire come funziona e a cosa servono tutti i calcoli che fa?
E' questo:

/*******************Demo for MG-811 Gas Sensor Module V1.1*****************************
Author:  Tiequan Shao: tiequan.shao@sandboxelectronics.com
         Peng Wei:     peng.wei@sandboxelectronics.com

Lisence: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)

Note:    This piece of source code is supposed to be used as a demostration ONLY. More
         sophisticated calibration is required for industrial field application. 

                                                    Sandbox Electronics    2012-05-31
************************************************************************************/

/************************Hardware Related Macros************************************/
#define         MG_PIN                       (0)     //define which analog input channel you are going to use
#define         BOOL_PIN                     (2)
#define         DC_GAIN                      (8.5)   //define the DC gain of amplifier

/***********************Software Related Macros************************************/
#define         READ_SAMPLE_INTERVAL         (50)    //define how many samples you are going to take in normal operation
#define         READ_SAMPLE_TIMES            (5)     //define the time interval(in milisecond) between each samples in 
                                                     //normal operation

/**********************Application Related Macros**********************************/
//These two values differ from sensor to sensor. user should derermine this value.
#define         ZERO_POINT_VOLTAGE           (0.220) //define the output of the sensor in volts when the concentration of CO2 is 400PPM
#define         REACTION_VOLTGAE             (0.020) //define the voltage drop of the sensor when move the sensor from air into 1000ppm CO2

/*****************************Globals***********************************************/
float           CO2Curve[3]  =  {2.602,ZERO_POINT_VOLTAGE,(REACTION_VOLTGAE/(2.602-3))};   
                                                     //two points are taken from the curve. 
                                                     //with these two points, a line is formed which is
                                                     //"approximately equivalent" to the original curve.
                                                     //data format:{ x, y, slope}; point1: (lg400, 0.324), point2: (lg4000, 0.280) 
                                                     //slope = ( reaction voltage ) / (log400 –log1000) 

void setup()
{
    Serial.begin(9600);                              //UART setup, baudrate = 9600bps
    pinMode(BOOL_PIN, INPUT);                        //set pin to input
    digitalWrite(BOOL_PIN, HIGH);                    //turn on pullup resistors

   Serial.print("MG-811 Demostration\n");                
}

void loop()
{
    int percentage;
    float volts;

    volts = MGRead(MG_PIN);
    Serial.print( "SEN-00007:" );
    Serial.print(volts); 
    Serial.print( "V           " );

    percentage = MGGetPercentage(volts,CO2Curve);
    Serial.print("CO2:");
    if (percentage == -1) {
        Serial.print( "<400" );
    } else {
        Serial.print(percentage);
    }

    Serial.print( "ppm" );  
    Serial.print("\n");

    if (digitalRead(BOOL_PIN) ){
        Serial.print( "=====BOOL is HIGH======" );
    } else {
        Serial.print( "=====BOOL is LOW======" );
    }

    Serial.print("\n");

    delay(200);
}

/*****************************  MGRead *********************************************
Input:   mg_pin - analog channel
Output:  output of SEN-000007
Remarks: This function reads the output of SEN-000007
************************************************************************************/ 
float MGRead(int mg_pin)
{
    int i;
    float v=0;

    for (i=0;i<READ_SAMPLE_TIMES;i++) {
        v += analogRead(mg_pin);
        delay(READ_SAMPLE_INTERVAL);
    }
    v = (v/READ_SAMPLE_TIMES) *5/1024 ;
    return v;  
}

/*****************************  MQGetPercentage **********************************
Input:   volts   - SEN-000007 output measured in volts
         pcurve  - pointer to the curve of the target gas
Output:  ppm of the target gas
Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm) 
         of the line could be derived if y(MG-811 output) is provided. As it is a 
         logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic 
         value.
************************************************************************************/ 
int  MGGetPercentage(float volts, float *pcurve)
{
   if ((volts/DC_GAIN )>=ZERO_POINT_VOLTAGE) {
      return -1;
   } else { 
      return pow(10, ((volts/DC_GAIN)-pcurve[1])/pcurve[2]+pcurve[0]);
   }
}