Sensore TGS 2442 . Aiuto!

Salve a tutti, sono nuovo di qui, e avrei bisogno del vostro aiuto per una questione abbastanza urgente! Per un'esame universitario il professore mi ha dato il compito di leggere il dato da questo sensore di monossido di carbonio, e consegnarlo in questa settimana. Il fatto è che purtroppo non ne so molto su arduino, e mi chiedevo se qualcuno di voi potrebbe aiutarmi a risolvere questo problema. In pratica, da quello che ho capito dai datasheet, devo usare un ciclo di riscaldamento per attivare il sensore,una volta che attivato c'è un ciclo di sensing
che ha periodo di 5 ms, e in quei 5 ms devo leggere il valore. Si riduce a questo, o c'è dell'altro?

Uhm, i 2442 non sono esattamente i sensori piu facili da usare, specie in campo hobbystico ... in pratica, si, devi applicarci l'impulso di riscaldamento per un secondo circa, poi applicare la tensione di lettura dopo aver staccato l'impulso di riscaldamento, e leggere a meta' i quel tempo, possibilmente facendo piu letture ed estrapolando la media ... una discreta temporizzazione potrebbe essere la seguente:

993mS di riscaldamento -> 1mS di pausa -> 5mS di lettura (valore da leggere 2,5mS dopo l'inizio del tempo di lettura, in un colpo solo) -> 1mS di pausa -> ecc

Considerando la lettura valida sulla media di 3 letture consecutive ... ed ovviamente scartando le piu vecchie man mano che procedi ... ad esempio, dalla terza lettura, media delle letture 1, 2, 3 ... dalla quarta, media delle letture 2, 3, 4 ... alla quinta media di 3, 4, 5 ... e cosi via ...

Purtroppo devo usare questo.
Vi posto un'esempio di codice che ho abbozzato per l'acquisizione

int figaroHeater = 6; //heat
int figaroCircuit = 5; //Sensing (sarebbere le due onde quadre

digitalWrite(figaroCircuit, LOW);
analogWrite(figaroHeater, 245); ( 4.8 volts)
delay(14);
analogWrite(figaroHeater, 0);
delay(981);
digitalWrite(figaroCircuit, HIGH);
delay(3)
figaroCOVal = analogRead(figaroCOPin); // prende la misurazione
delay(2);

Ora, per il fatto della media. come posso fare? non ne ho idea!!
Per il codice, che ne pensate?

Potresti fare un qualcosa del genere:

byte N = 10;    // numero di campioni
int Somma;    // somma dei campioni (max  32767)
int figaroCOVal;
...
Somma = 0;
for (byte I = 0; I < N; I ++) { 
Somma += analogRead(figaroCOPin);
}
figaroCOVal = Somma / N;    // media per eliminazione "rumore" ed errore su prima lettura

cyberhs:
Potresti fare un qualcosa del genere:

byte N = 10;    // numero di campioni

int Somma;    // somma dei campioni (max  32767)
int figaroCOVal;

Somma = 0;
for (byte I = 0; I < N; I ++) {
Somma += analogRead(figaroCOPin);
}
figaroCOVal = Somma / N;    // media per eliminazione “rumore” ed errore su prima lettura

Ok. Potrei farlo direttamente alla fine dell’acquisizione del dato? Ovvero, mi spiego meglio.

Il FOR che mi permette di fare la media tra i 10 valori acquisiti, lo posso estendere alla lettura del dato? Cioè, acquisisco i 10 valori, li metto all’interno di N, e una volta acquisiti tutti e 10 faccio la media. Che ne dite?

Se intendi caricare un vettore con le N=10 letture è possibile, ma inutile.

L'unico motivo per farlo sarebbe quello di dover trattare i dati prima di fare la media: ad esempio un filtro digitale passa basso.

cyberhs:
Se intendi caricare un vettore con le N=10 letture è possibile, ma inutile.

L’unico motivo per farlo sarebbe quello di dover trattare i dati prima di fare la media: ad esempio un filtro digitale passa basso.

Purtroppo sono alle prime armi! Molti dei concetti che voi esponete per me sono oscuri.
In tal caso, lo script, per quello che ho studiato, l’ho modificato come segue. Che ne dite?

int figaroHeater = 6; // Heat VCC
int figaroCircuit = 5; // Sensing VCC
int figaroCOPin = 0;
byte N = 10; // numero di campioni
int Somma; // somma dei campioni (max 32767)
int figaroCOVal=0;
void setup( )
{
Serial.begin(9600);
pinMode(figaroHeater, OUTPUT);
pinMode(figaroCircuit, OUTPUT);
}
void loop( )
{
Somma = 0;
digitalWrite(figaroCircuit, LOW); // turn off sensing VCC
analogWrite(figaroHeater, 245); // turn on heating (recommended 4.8 volts)
delay(14);
analogWrite(figaroHeater, 0); // turn off heating
delay(981);
digitalWrite(figaroCircuit, HIGH);
delay(3)
figaroCOVal = analogRead(figaroCOPin); // take measurement here
delay(2);
for (byte I = 0; I < N; I ++)
{
Somma += analogRead(figaroCOPin);
}
figaroCOVal = Somma / N; // media per eliminazione “rumore” ed errore su prima lettura
}

Poiché sei nuovo del forum ho pensato di riscriverti “in bella” il tuo sketch:

/*
 CO Meter
 for Arduino UNO R3 & IDE 1.0.5
 by Flavio ... 07/07/2013
 */

int FigaroHeater = 6;                     // Heat VCC
int FigaroCircuit = 5;                    // Sensing VCC
int FigaroCOPin = 0; 

byte N = 10;                              // numero di campioni
int Somma;                                // somma dei campioni (max 32767)

int FigaroCOVal = 0;

void setup() {

  Serial.begin(9600);
  pinMode(FigaroHeater, OUTPUT);
  pinMode(FigaroCircuit, OUTPUT);
  pinMode(FigaroCOPin, INPUT);
}

void loop( ) {

  digitalWrite(FigaroCircuit, LOW);       // turn OFF sensing VCC

  analogWrite(FigaroHeater, 245);         // turn ON heating (recommended 4.8 volts)
  delay(14);                              // heating time
  analogWrite(FigaroHeater, 0);           // turn off heating

  delay(981);                             // ritardo prima attivazione di lettura
  digitalWrite(FigaroCircuit, HIGH);      // turn ON sensing VCC
  delay(3);                               // ritardo prima della lettura 

  Somma = 0;
  for (byte I = 0; I < N; I ++) {         // ciclo di letture (@ 8620 sample/s)
    Somma += analogRead(FigaroCOPin);
  }
  FigaroCOVal = Somma / N;                // media per eliminazione "rumore" ed errore su prima lettura
  Serial.println(FigaroCOVal);            // display result (0-1023)
}

Ho modificato lo script, con una media con un'array dinamico che, fà la media solo tra i tre valori più recenti.
Che ne pensate?

int figaroHeater = 6; // Heat VCC
int figaroCircuit = 5; // Sensing VCC
int figaroCOPin = 0;
int valori = { 0, 0, 0}; //array che contiene i 3 valori che devo andare a mediare
//int N = 5; // numero di campioni
int somma=0; // somma dei campioni (max 32767)
int figaroCOVal=0;
float media=0;

void setup( )
{
Serial.begin(9600);
pinMode(figaroHeater, OUTPUT);
pinMode(figaroCircuit, OUTPUT);
pinMode(FigaroCOPin, INPUT);
}
void loop( )
{

digitalWrite(figaroCircuit, LOW); // turn off sensing VCC
analogWrite(figaroHeater, 245); // turn on heating (recommended 4.8 volts)
delay(14);
analogWrite(figaroHeater, 0); // turn off heating
delay(981);
digitalWrite(figaroCircuit, HIGH);
delay(3);
figaroCOVal = analogRead(figaroCOPin); // take measurement here
delay(2);
//array dinamico, ovvero, fà la media delle tre misure più recenti, eliminando la più vecchia, sostituendola con quella piu recente(visualizza il dato ogni 3 secondi)
valori[2]= valori[1];
valori[1]= valori[0];
valori[0]= figaroCOVal;
somma = valori[2]+valori[1]+valori[0];
media = somma/3; //media per eliminazione rumore

// somma = somma + analogRead(PIN); //acquisisco 5 valori e faccio la media(visualizzazione del valore ogni 5 secondi
// N ++;
// if (N >= 5)
// {
// media = somma/nr
// N = 0;
// somma = 0;
// }

}

cyberhs:
Poiché sei nuovo del forum ho pensato di riscriverti “in bella” il tuo sketch:

/*

CO Meter
for Arduino UNO R3 & IDE 1.0.5
by Flavio … 07/07/2013
*/

int FigaroHeater = 6;                     // Heat VCC
int FigaroCircuit = 5;                    // Sensing VCC
int FigaroCOPin = 0;

byte N = 10;                              // numero di campioni
int Somma;                                // somma dei campioni (max 32767)

int FigaroCOVal = 0;

void setup() {

Serial.begin(9600);
  pinMode(FigaroHeater, OUTPUT);
  pinMode(FigaroCircuit, OUTPUT);
  pinMode(FigaroCOPin, INPUT);
}

void loop( ) {

digitalWrite(FigaroCircuit, LOW);       // turn OFF sensing VCC

analogWrite(FigaroHeater, 245);         // turn ON heating (recommended 4.8 volts)
  delay(14);                              // heating time
  analogWrite(FigaroHeater, 0);           // turn off heating

delay(981);                             // ritardo prima attivazione di lettura
  digitalWrite(FigaroCircuit, HIGH);      // turn ON sensing VCC
  delay(3);                               // ritardo prima della lettura

Somma = 0;
  for (byte I = 0; I < N; I ++) {         // ciclo di letture (@ 8620 sample/s)
    Somma += analogRead(FigaroCOPin);
  }
  FigaroCOVal = Somma / N;                // media per eliminazione “rumore” ed errore su prima lettura
  Serial.println(FigaroCOVal);            // display result (0-1023)
}

Grazie cyberhs, non lo avevo letto!! Che ne pensi di quello che ho postato?

Innanzitutto usa l’apposito tag Code per inserire il codice (altrimenti il moderatore ti crocifigge!).

Continuo a non capire perché carichi un vettore: che vantaggio c’è?

Ho paura che 3 campioni siano pochi, esseno il primo con alta probabilità non affidabile.

Il sensore Figaro ha un preciso timing per il suo funzionamento: lo hai letto il datasheet?

Se noti ho eliminato l’ultimo delay (2ms) perché compenso il tempo delle istruzioni

HO letto il datasheet, preso da qui( TGS2442 datasheet & applicatoin notes - Datasheet Archive) .
sto facendo riferimento allo schema a pagina 12. Dalla figura, vedo che ci sono 3 onde quadre che devo creare in uscita da arduino (RL1,RL2 e Pulse) e prendere il valore di di tensione V1 per poi ricavare ƒ(Rs) = ( 5 - V1 ) / V1... Ora, devo far riferimento a questo schema , o a quello della figura 2 a pagina 2?! :fearful: :fearful: :fearful:
Sono molto confuso!!! Help :drooling_face: :drooling_face: :drooling_face: :drooling_face:
Perdonate la mia ignoranza

Purtroppo devo usare questo.

Ovviamente quello indicato dalla Figaro è uno schema di base: ad esempio il transistor PNP usato per il riscaldamento potrebbe essere tranquillamente sostituito da un NPN con emettitore a massa (invertendo la logica dell'impulso).

Il sensore assorbe ben 203mA @ 4.8V quindi è impensabile pilotarlo direttamente con Arduino le cui uscite digitali tollerano al massimo 40mA.

Ti allego un esempio di utilizzo che, anche se usa un PIC, puoi utilizzare come riferimento

mcs.uwsuper.edu/sb/Electronics/CO/schema1.png

cyberhs:

Purtroppo devo usare questo.

Ovviamente quello indicato dalla Figaro è uno schema di base: ad esempio il transistor PNP usato per il riscaldamento potrebbe essere tranquillamente sostituito da un NPN con emettitore a massa (invertendo la logica dell'impulso).

Il sensore assorbe ben 203mA @ 4.8V quindi è impensabile pilotarlo direttamente con Arduino le cui uscite digitali tollerano al massimo 40mA.

Ti allego un esempio di utilizzo che, anche se usa un PIC, puoi utilizzare come riferimento

mcs.uwsuper.edu/sb/Electronics/CO/schema1.png

Grazie mille!! ho anche un'altro schema(a pagina 2 del datasheet). dove, c'è descritto di utilizzare due transistor( uno sul pin 2 e uno sul pin 4 del sensore). Lo so ti sto facendo impazzire, ma purtroppo, avendo poche basi, mi sfugge sempre quello che dovrebbe essere ovvio.
=)

Ma no, figurati… è un piacere!

Dato che la cosa mi intrigava un po’, ho buttato giù uno schemino.

Dagli un’occhiata (usa l’alimentazione a 5V di Arduino se possibile)

In questa tesi è stato utilizzato il sensore in questione ed è presente anche una libreria per l’uso.
https://www.politesi.polimi.it/bitstream/10589/2229/3/719689%20-%20Domenico%20Schillaci.pdf (pag. 82)

/* ********************************************************************
******************************* TGS2442 ******************************
******************************************************************** */
TGS2442 :: TGS2442 ( int heaterPin , int circuitPin , int sensingPin ) {
hPin = heaterPin ;
cPin = circuitPin ;
sPin = sensingPin ;
pinMode ( hPin , OUTPUT );
pinMode ( cPin , OUTPUT );
}
/* ********************************************************************
******************************** getCox ******************************
******************************************************************** */
float TGS2442 :: getCox ( float tem , int nSamples ) {
this - > nSamples = nSamples ;
float Vl = heatAndSense ();
float Rl = 10000.0; // load resistance 10 kOhm
float R0 = ((5.0 * Rl ) /2.5) - Rl ; // sensing resistance at 100 ppm [ Ohm ]
float Rs = ((5.0 * Rl ) / Vl ) - Rl ; // sensing resistance at actual ppm [ Ohm ]
float Rs1 = Rs / getKTem ( tem ); // Rs temperature compensated [ Ohm ]
float RRatio = Rs1 / R0 ; // resistance ratio RS / R0
float cox = 124/( RRatio - 0.6);
return cox ;
}
/* ********************************************************************
**************************** heatAndSense ****************************
******************************************************************** */
float TGS2442 :: heatAndSense () {
int count =0;
int adcValue =0;
while ( count < nSamples )
{
// Heating phase (14 ms )
digitalWrite ( hPin , HIGH );
delay (14);
// No heat phase (986 ms )
digitalWrite ( hPin , LOW );
delay (981);
// Sensing phase
digitalWrite ( cPin , HIGH );
delay (2);
if ( count == nSamples -1) { adcValue = analogRead ( sPin );} // last cycle
delay (3);
digitalWrite ( cPin , LOW );
count ++;
}
float Vl = adcValue * 5.00 /1023; // voltage across load resistance
return Vl ;
}

Complimenti agli autori. XD
Non si capisce che è codice Arduino… nooo! :grin:

cyberhs:
Ma no, figurati... è un piacere!

Dato che la cosa mi intrigava un po', ho buttato giù uno schemino.

Dagli un'occhiata (usa l'alimentazione a 5V di Arduino se possibile)

Se ho a disposizione due NpN, il pnp posso cambiarne la configurazione (scambiando il collettore con l'emettitore se non erro). Ma di conseguenza non cambia anche lo sketch? Inoltre nel datasheet si parla anche di Sensor trouble detection(rispettivamente heater trouble e sensor element damage). ?? C

PaoloP:
In questa tesi è stato utilizzato il sensore in questione ed è presente anche una libreria per l’uso.
https://www.politesi.polimi.it/bitstream/10589/2229/3/719689%20-%20Domenico%20Schillaci.pdf (pag. 82)

/* ********************************************************************

******************************* TGS2442 ******************************
******************************************************************** /
TGS2442 :: TGS2442 ( int heaterPin , int circuitPin , int sensingPin ) {
hPin = heaterPin ;
cPin = circuitPin ;
sPin = sensingPin ;
pinMode ( hPin , OUTPUT );
pinMode ( cPin , OUTPUT );
}
/
********************************************************************
******************************** getCox ******************************
******************************************************************** /
float TGS2442 :: getCox ( float tem , int nSamples ) {
this - > nSamples = nSamples ;
float Vl = heatAndSense ();
float Rl = 10000.0; // load resistance 10 kOhm
float R0 = ((5.0 * Rl ) /2.5) - Rl ; // sensing resistance at 100 ppm [ Ohm ]
float Rs = ((5.0 * Rl ) / Vl ) - Rl ; // sensing resistance at actual ppm [ Ohm ]
float Rs1 = Rs / getKTem ( tem ); // Rs temperature compensated [ Ohm ]
float RRatio = Rs1 / R0 ; // resistance ratio RS / R0
float cox = 124/( RRatio - 0.6);
return cox ;
}
/
********************************************************************
**************************** heatAndSense ****************************
******************************************************************** */
float TGS2442 :: heatAndSense () {
int count =0;
int adcValue =0;
while ( count < nSamples )
{
// Heating phase (14 ms )
digitalWrite ( hPin , HIGH );
delay (14);
// No heat phase (986 ms )
digitalWrite ( hPin , LOW );
delay (981);
// Sensing phase
digitalWrite ( cPin , HIGH );
delay (2);
if ( count == nSamples -1) { adcValue = analogRead ( sPin );} // last cycle
delay (3);
digitalWrite ( cPin , LOW );
count ++;
}
float Vl = adcValue * 5.00 /1023; // voltage across load resistance
return Vl ;
}




Complimenti agli autori. XD
Non si capisce che è codice Arduino.... nooo! :grin:

Ook. L’ho visto anche se devo capirlo bene…

float TGS2442 :: getCox ( float tem , int nSamples ) {
this - > nSamples = nSamples ;
float Vl = heatAndSense ();
float Rl = 10000.0; // load resistance 10 kOhm
float R0 = ((5.0 * Rl ) /2.5) - Rl ; // sensing resistance at 100 ppm [ Ohm ]
float Rs = ((5.0 * Rl ) / Vl ) - Rl ; // sensing resistance at actual ppm [ Ohm ]
float Rs1 = Rs / getKTem ( tem ); // Rs temperature compensated [ Ohm ]
float RRatio = Rs1 / R0 ; // resistance ratio RS / R0
float cox = 124/( RRatio - 0.6);
return cox ;

QUi ci sono delle funzuine aggiuntuve come compensazione in temperatura e calibrazione. Secondo quale principio trovo R0 in quel modo?Rl a 10kohm perchè? E, Cox, che suppongo sia la concentrazione di CO, perchè

float cox = 124/( RRatio - 0.6);

??
Inoltre viene inizializzato un pin di sensing che , che tuttavia non viene mai richiamato all’interno del programma. o sbaglio?

Sono molto curioso e voglio capire :smiley: :smiley: :smiley:

Apri il PDF, c'è lo sketch completo che, per brevità, non ho riportato.

PaoloP:
Apri il PDF, c'è lo sketch completo che, per brevità, non ho riportato.

HO letto, purtroppo sono nuovo nel mondo arduino, e molti concetti che sono esposti in quella tesi sono per me oscuri.
A me basta che questo aggeggio riveli un dato(possibilmente preciso) sulla porta analogica.
Vedendo lo script di questa tesi, ho notato che ci sono cose in piu che non avevo considerato, ovvero:

float R0 = ((5.0 * Rl ) /2.5) - Rl ; // sensing resistance at 100 ppm [ Ohm ]

e

float cox = 124/( RRatio - 0.6);

.E volevo capire, da voi che siete molto piu esperti di me in questo settore, da dove escono fuori quei valori.
Perchè io non sò dove sbattere la testa..