Sensore di temperatura

Leggendo le specifiche dell'Atmega328 leggo che contiene un sensore di temperatura interno (pag. 261 del datasheet). Se non ho capito male, questo sensore può essere attivato e la temperatura rilevata letta tramite il voltaggio restituito dall'ADC.

Sarebbe interessante come sensore di temperatura del chip, per capire magari quando questo inizia a surriscaldarsi (ottimo per ambienti particolari, pensavo ad esempio al sistema di gestione dell'antigelo di Kattivik) ed attivare qualche sistema di raffreddamente attivo (ventoline) oppure ridurre il carico interno (riduzione del clock, inserimento di delay, disattivazione di qualche processo particolarmente oneroso).
Qualcuno ha fatto esperimenti a proposito?

Ho trovato questo codice sul vecchio forum (qui):

void setup()
{
  Serial.begin(9600);
  ADMUX = 0xC8; // turn on internal reference, right-shift ADC buffer, ADC channel = internal temp sensor
  delay(10);  // wait a sec for the analog reference to stabilize
}

void loop()
{
  Serial.println(averageTemperature()); // so we can debug
  delay(500); // just to slow things down a bit
}

int readTemperature()
{
  ADCSRA |= _BV(ADSC); // start the conversion
  while (bit_is_set(ADCSRA, ADSC)); // ADSC is cleared when the conversion finishes
  return (ADCL | (ADCH << 8)) - 342; // combine bytes & correct for temp offset (approximate)}
}

float averageTemperature()
{
  readTemperature(); // discard first sample (never hurts to be safe)

  float averageTemp; // create a float to hold running average
  for (int i = 1; i < 1000; i++) // start at 1 so we dont divide by 0
    averageTemp += ((readTemperature() - averageTemp)/(float)i); // get next sample, calculate running average

  return averageTemp; // return average temperature reading
}

Appena uploadato, mi da sui 36/37°C. Voglio provare a sperimentare dei carichi di calcolo per vedere se varia la temperatura letta oppure no. Vorrei provare anche provare a leggere il valore dopo uno sleep. Chissà...

cavolo sarebbero un lm37 (50 cent) e un pin analogico risparmiati XD
no dai scherzi a parte non lo sapevo, fai delle prove e poi facci sapere :wink:

superlol:
cavolo sarebbero un lm37 (50 cent) e un pin analogico risparmiati XD
no dai scherzi a parte non lo sapevo, fai delle prove e poi facci sapere :wink:

Non credo, penso che stia leggendo la temperatura interna del chip, o Leo sta arrostendo a 37° alle dieci di sera? :cold_sweat:
Semmai bisogna capire se è "collegabile" ad uno dei pin del chip, in modo da usarlo come sensore di temperatura; ho dubbi, in ogni caso il pin sarebbe molto influenzato dalla temperatura del chip da cui esce.
Penso l'utilità sia proprio quella di controllare la temperature del chip in condizioni critiche per attivare un qualsiasi sistema di raffreddamento esterno, vale la pena di imparare ad usarlo comunque no?
Dicci Leo, dicci... :smiley:

Esatto è la lettura della temperatura interna.
E' approssimata perché quel sensore sbarella di +/- 10° (da datasheet) e non può essere collegato ad un pin esterno dato che l'ADC8 è un pin analogico virtuale che fa riferimento ad un circuito interno al chip. Però... funziona :smiley:

ammazza.. 10°C sono tantissimi :fearful:
conta che su 50°C che immagino raggiungerà il chip è un errore del 20%

mica poco..

comunque ovvio che avevo capito :stuck_out_tongue: 37 gradi anche se ormai è estate è troppo :smiley:

OT:
menniti complimenti per la guida che stai facendo sui PCB, io solitamente per la tecnica a caldo stampo su un foglio normale 2 volte e i risultati non sono buoni ma qualcosa rimane :wink:

superlol:
ammazza.. 10°C sono tantissimi :fearful:
conta che su 50°C che immagino raggiungerà il chip è un errore del 20%
mica poco..
comunque ovvio che avevo capito :stuck_out_tongue: 37 gradi anche se ormai è estate è troppo :smiley:

certo, la mia era una battuta ovvia, se lo consideri un sensore di sicurezza, della tolleranza non deve fregartene nulla (mica ti deve misurare la frebbre quando hai la bua :grin:), basta considerare che lui ti indichi mediamente 5°C meno di quelli reali, qualche altro grado stai tu col software sotto la soglia di sicurezza, e lui fa il suo egregio lavoro.

OT:
menniti complimenti per la guida che stai facendo sui PCB,

Grazie XD

io solitamente per la tecnica a caldo stampo su un foglio normale 2 volte e i risultati non sono buoni ma qualcosa rimane :wink:

sì, la buona intenzione :stuck_out_tongue_closed_eyes:; guarda la carta fotografica per ink-jet/laser a bassa grammatura non costa milioni in più rispetto alla carta standard, ma i risultati sono dieci volte superiori, se poi stampi 100 PCB al giorno forse vale la pena che ti attrezzi, il materasso non ha una capienza infinita in euro, qualcosa puoi anche spendere :wink:
EDIT: comunque appena finisco sblocco il topic e ne riparliamo lì.

Ma perché le cose non vanno mai come devono??
Attivando 'sto circuitino l'Atmega non legge più gli altri pin, anche quelli digitali.
Ho modificato il codice mettendo una semplice lettura di un pulsantino per attivare un carico di codice e far lampeggiare un led ma non funziona. Togliendo invece la lettura della temperatura, il pulsantino funziona....

Qualcun altro può verificare?
Questo è il codice che uso:

int val1=0;
int val2=0;
int change=0;

void setup() {
    delay(3000);
    pinMode(7, INPUT);
    pinMode(6, OUTPUT);
    Serial.begin(9600);
    ADMUX = 0xC8; // turn on internal reference, right-shift ADC buffer, ADC channel = internal temp sensor
    delay(10);  // wait a sec for the analog reference to stabilize
}

void loop() {
    double ar=45650;
    
    Serial.println(averageTemperature()); // so we can debug
    delay(500); // just to slow things down a bit
    val1=digitalRead(7);
    delay(10);
    val2=digitalRead(7);
    if (val1==val2) {
        if (val1!=change) {  
            if (val1==HIGH) { 
                digitalWrite(6, HIGH);
                for (int i=0; i<1000; i++) {
                    ar*=sqrt(ar);
                }
                digitalWrite(6, LOW);
            }
        }
    }
    change=val1;  
}

int readTemperature()
{
  ADCSRA |= _BV(ADSC); // start the conversion
  while (bit_is_set(ADCSRA, ADSC)); // ADSC is cleared when the conversion finishes
  return (ADCL | (ADCH << 8)) - 342; // combine bytes & correct for temp offset (approximate)}
}

float averageTemperature()
{
  readTemperature(); // discard first sample (never hurts to be safe)

  float averageTemp; // create a float to hold running average
  for (int i = 1; i < 1000; i++) // start at 1 so we dont divide by 0
    averageTemp += ((readTemperature() - averageTemp)/(float)i); // get next sample, calculate running average

  return averageTemp; // return average temperature reading
}

Collegate un pulsantino al pin 7 con resistenza di pull-down da 10K ed un led (con resistenza) al pin 6.

menniti:
....
certo, la mia era una battuta ovvia, se lo consideri un sensore di sicurezza, della tolleranza non deve fregartene nulla (mica ti deve misurare la frebbre quando hai la bua :grin:), basta considerare che lui ti indichi mediamente 5°C meno di quelli reali, qualche altro grado stai tu col software sotto la soglia di sicurezza, e lui fa il suo egregio lavoro.
....

anche perchè credo il problema di misurare la febbre sarebbero i pin, per non parlare di misurarla da dietro :sweat_smile:

sì, la buona intenzione :stuck_out_tongue_closed_eyes:; guarda la carta fotografica per ink-jet/laser a bassa grammatura non costa milioni in più rispetto alla carta standard, ma i risultati sono dieci volte superiori, se poi stampi 100 PCB al giorno forse vale la pena che ti attrezzi, il materasso non ha una capienza infinita in euro, qualcosa puoi anche spendere :wink:
EDIT: comunque appena finisco sblocco il topic e ne riparliamo lì.

no qualcosa di decente rimane, la carta fotografica la ho e la uso :wink: 7.5mil della HP 202g/m^2
però mi si fonde sempre e poi toglierla è un casino, una volta ho tenuto temperatura troppo alta e ho ancora la basetta con la carta attaccata :smiley:
comunque certo ne riparliamo di la :wink:

@leo72
cerca di scoprire in che punto misura la temperatura, correggetemi se sbaglio ma il microcontrollore come l'atmega p un microprocessore con convertitori, eeprom, e cose aggiunte giusto? la temperatura maggiore dovrebbe essere sul processore no? e la misura li o sulla eeprom? :smiley:

Non capisco, ora funziona... Forse allora avevo un contatto, eppure ho ricontrollato TUTTO almeno 5 volte, compreso il codice. Misteri dell'elettronica.... boh...

EDIT:
l'accuratezza del codice riportato è di 0,1°C. L'autore effettua la media su 1000 letture prima di restituire la temperatura. Casomai bisognerebbe calibrare la lettura.

leo72:
Non capisco, ora funziona... Forse allora avevo un contatto, eppure ho ricontrollato TUTTO almeno 5 volte, compreso il codice. Misteri dell'elettronica.... boh...

L'elettronica non ne ha di misteri, a questi livelli, semmai gli uomini e i loro cavetti :smiley: . Dimmi una cosa in un pin impostato come INPUT digitalWrite HIGH attiva una pull-up interna con valore che va da un range tra 20K e 50K, ma digitalWrite LOW attiva parimenti una pull-down, che tu sappia, visto che ormai hai imparato a memoria il reference ? :smiley:

Il datasheet non mi pare parli di pull-down.... che stai combinando? :smiley:

PS:
sto giocherellando con questo sensorino di temperatura e con lo sleep. Purtroppo pare che le cose non vadano bene insieme, nel senso che al risveglio del micro messo a "nanna" il sensore mi restituisce sempre 38.0°C spaccati. Non mi pare plausibile.
Eppure riattivo anche l'ADC8... mah...

leo72:
Il datasheet non mi pare parli di pull-down.... che stai combinando? :smiley:

PS:
sto giocherellando con questo sensorino di temperatura e con lo sleep. Purtroppo pare che le cose non vadano bene insieme, nel senso che al risveglio del micro messo a "nanna" il sensore mi restituisce sempre 38.0°C spaccati. Non mi pare plausibile.
Eppure riattivo anche l'ADC8... mah...

assolutamente nulla giuro, le ultime 100 ore le ho passate a scrivere il topic, hai visto quanto roba c'è? ho le dita anchilosate :disappointed_relieved: solo che leggendo il tuo post, in cui hai citato una pull-down mi è venuto in mente un dubbio che avevo da un po' di giorni e ho approfittato.
In verità una novità importante forse ci sarà, ma ci vuole tempo, al momento opportuno certamente te ne parlerò, ma ora è solo un'idea e non mi va di dire cose che poi non faccio... Invece finiti i nanetti devo realizzare un minicircuito sciocchino con una barra di led blu e poi inizio il grosso con i sensori ultrasuoni, lì sarà dura, meno male che con l'elettronica ho le spalle coperte da Astrobeed, che mi aiuta (non so proprio come sdebitarmi :blush:), altrimenti penso sarebbe stata un'impresa. Nelle more devo riprendere le prove per la Guida, testare le programmazioni "dude", fare altre prove serie con tiny, 168 e 8, ho trovato il cavetto Nokia per testare le tecniche seriali, devo fare schema e PCB dell'HVFuse, un circuito che merita molto più di una millefori. Come vedi mi mancava solo il tutorial sui PCB, ma se ti avessi risposto no, non sarei mai riuscito a perdonarmelo, che razza di amico sarei stato? E tu meriti ben altro, quindi, per quanto posso, chiedi e sarai sempre esaudito XD

Ma un po' di tempo libero per la famiglia riesci a trovarlo, poi? O ti portano la cena nella cripta... ehm... laboratorio? XD

PS:
niente da fare. Sleep e sensore di temperatura non vanno d'accordo. Addormentato il micro, al suo risveglio il sensore non funziona più e serve un reset col pulsantino per rimettere a posto le cose. Proverò a chiedere sul forum internazionale se qualcuno ne sa qualcosa.

leo72:
Ma un po' di tempo libero per la famiglia riesci a trovarlo, poi? O ti portano la cena nella cripta... ehm... laboratorio? XD

No, ho risolto così: il lab è a 1km da casa, se sono davvero libero me ne vado lì e faccio il RE XD In genere quando scrivo lo faccio sul PC di casa, quindi tutto tempo dedicato alla famiglia :grin: :grin: :grin:

PS:
niente da fare. Sleep e sensore di temperatura non vanno d'accordo. Addormentato il micro, al suo risveglio il sensore non funziona più e serve un reset col pulsantino per rimettere a posto le cose. Proverò a chiedere sul forum internazionale se qualcuno ne sa qualcosa.

Sembra che resti addormentato, hai provato a NON spegnere l'ADC?

Ho provato tutte le combinazioni.
Pare che una volta che va in sleep, il circuito si sganci e non si riagganci al successivo risveglio: difatti le letture che mi da sono una sfilza di 36 oppure 37 oppure 38°, a seconda.

leo72:
EDIT:
l'accuratezza del codice riportato è di 0,1°C. L'autore effettua la media su 1000 letture prima di restituire la temperatura. Casomai bisognerebbe calibrare la lettura.

Puoi leggere anche 1000000 di volte un sensore, ma non è possibile migliorare la precisione semplicemente usando letture multiple quando l'errore è dato dalla tolleranza del sensore.
La precisione si migliora tramite calibrazione, cioè devi avere dei valori campione da comparare con le letture del sensore e tramite questi impostare una tabella di correzione, fatto questo basta una sola lettura del sensore per avere il valore corretto, al limite qualche lettura consecutiva per implementare un semplice filtro per il rumore.
Il sensore interno dei 328 è molto impreciso, ma va comunque bene per lo scopo a cui è destinato, la precisione di 0.1° è praticamente impossibile da ottenere perché oltre all'errore assoluto, che è compensabile, c'è l'errore di linearità che sicuramente non è inferiore a 1-2% anche se sul data sheet non è dichiarato.
In teoria è possibile crearsi una tabella di compensazione anche per la linearità, ma sarebbe molto grossa, probabilmente almeno un valore per ogni grado centigrado, e assolutamente inutile.
Da notare anche questo passaggio del data sheet:

The internal 1.1V voltage reference must also be selected for the ADC voltage reference source in the temperature sensor measurement.
When the temperature sensor is enabled, the ADC converter can be used in single conversion mode to measure the voltage over the temperature sensor.

Tutte cose che Wiring non permette di fare direttamente, occorre programmare manualmente i registri dell'ADC.
Se si utilizza la lettura del sensore interno non è possibile leggere i normali canali ADC, questo non è un reale problema dato che quel sensore è sufficiente leggerlo ogni tanto, p.e. ogni 30 secondi, però è necessario scriversi una funzione dedicata che prima setta l'ADC come serve, legge il sensore, rimette l'ADC nel modo normale di Arduino.

Forse in questo passaggio di Astrobeed c'è la chiave per risolvere il problema, prova a rimettere l'ADC "a posto" prima di mandare il micro in sleep, al risveglio riattivi la lettura del sensore. Cosa succede?

La risposta me l'ha data un tizio sul forum internazionale che mi ha fatto notare come io disattivassi manualmente l'ADC (ADCSRA &= ~(1<<ADEN)) senza poi riattivarlo.

Il codice funzionante è il seguente:

#include <avr/sleep.h> 
#define WakeUpPin 2    

void wakingUp() {        // awake from sleeping

}


void setup() {
    pinMode(WakeUpPin, INPUT);
    attachInterrupt(0, wakingUp, RISING);   // interrupt 0 
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // set sleep mode: max. power save
    sleep_enable();                         // sleep mode ready to use
    delay(3000);
    ADMUX = 0xC8; // activate interal temperature sensor, using 1.1V ref. voltage
    delay(10);  
    Serial.begin(9600);
}


void loop() {
    double ar;
    byte i;
    
    for (i=0; i<10; i++) {
        Serial.println(averageTemperature()); // print the temperature
        delay(500);
    }
    Serial.println("Go sleeping...");
    Go_sleeping(); //got into sleep mode
}


//activate the sleep mode
void Go_sleeping() {
    attachInterrupt(0, wakingUp, RISING); // riattiva l'interrupt
    ADCSRA &= ~(1 << ADEN); //shut down the ADC
    sleep_mode(); //go sleeping
    sleep_disable(); // deactivate the sleep mode
    ADCSRA |= (1 << ADEN); //power up the ADC
    detachInterrupt(WakeUpPin);  // deactivate interrupt
    ADMUX = 0xC8; // activate interal temperature sensor, using 1.1V ref. voltage
    delay(100); 

    Serial.println("I'm waking up..."); 
}


int readTemperature() {
    ADCSRA |= _BV(ADSC); // start the conversion
    while (bit_is_set(ADCSRA, ADSC)); // ADSC is cleared when the conversion finishes
    return (ADCL | (ADCH << 8)) - 342; // combine bytes & correct for temp offset (approximate)
}


float averageTemperature() {
    readTemperature(); // discard first sample (never hurts to be safe)

    float averageTemp; // create a float to hold running average
    for (int i = 1; i < 1000; i++) {// start at 1 so we dont divide by 0
        averageTemp += ((readTemperature() - averageTemp)/(float)i); // get next sample, calculate running average
    }
    return averageTemp; // return average temperature reading
}

Basta un pulsantino collegato al pin 2 di Arduino (interrupt 0) con una resistenza di pull-down da 10K e vedere come, al risveglio del micro, l'ADC faccia il suo dovere dando le letture variabili in base alla temperatura letta dal sensore.
Tornando al discorso di astrobeed, effettivamente il suo appunto non fa una piega. Anche a me non tornava il fatto che facendo 1000 letture si eliminasse l'errore: mi son fidato perché ho visto che altri sul forum utilizzavano questo sistema per "diluire" la tolleranza del sensore.
Ma ad esser precisi sul datasheet c'è proprio una precisazione su questa cosa:

However, due to the process variation the
temperature sensor output voltage varies from one chip to another. To be capable of achieving
more accurate results the temperature measurement can be calibrated in the application soft-
ware. The software calibration requires that a calibration value is measured and stored in a
register or EEPROM for each chip, as a part of the production test. The software calibration can
be done utilizing the formula:
T = { [(ADCH << 8) | ADCL] - TOS} / k
where ADCn are the ADC data registers, k is a fixed coefficient and TOS is the temperature sen-
sor offset value determined and stored into EEPROM as a part of the production test.

Resta da capire se TOS sia salvato di fabbrica da qualche parte nel micro oppure se qualcuno interessato all'uso del sensore deve calcolarsi questo valore e salvarlo in EEPROM. Se fosse salvato di fabbrica nella EEPROM, allora sarebbe un pasticcio dato che i miei micro li ho brasati diverse volte con avrdude e la EEPROM non contiene più nulla di originale (mi ricordo che il micro originale dell'Arduino aveva qualcosa salvato negli ultimi byte della EEPROM ma non so se erano valori casuali oppure no).

leo72:
Resta da capire se TOS sia salvato di fabbrica da qualche parte nel micro oppure se qualcuno interessato all'uso del sensore deve calcolarsi questo valore e salvarlo in EEPROM.

In effetti il data sheet su questo punto è abbastanza ambiguo.
La nota può essere interpretata sia come valore immesso da Atmel sul micro dopo la produzione, e sarebbe comunque un valore preso da un piccolo campione del lotto di produzione che viene usato per i test, oppure è un valore da trovare in proprio e memorizzare sulla EEPROM.
Però se tale valore venisse realmente rilevato da Atmel ci sarebbe anche scritto in quali locazioni della EEPROM si trova, sul data sheet non dice nulla in merito, quindi ritengo logico che il valore sia da trovare a cura dell'utente finale.
Su tutti gli Atmega vergini che ho preso non ho mai trovato nessun valore prememorizzato nella EEPROM, risulta sempre 0xff in tutte le celle.