Creative Commons BY-NC-ND 2.5Questo sito e tutto il suo contenuto sono distribuiti sotto la licenza Creative Commons Attribuzione - Non Commerciale - Non opere derivate 2.5 Italia e con le condizioni d'uso definite nel disclaimer: siete pregati di leggere entrambi questi documenti prima di usufruire dei contenuti di questo sito. Per alcuni contenuti è necessaria una registrazione gratuita: non è necessario pagare e non è necessario accumulare punteggi per accedere agli articoli e scaricare i sorgenti. Basta solo essere onesti. Se volete che questo sito continui a rimanere attivo, a contribuire ogni giorno alla diffusione della cultura libera, non copiate il materiale per ripubblicarlo in altri luoghi : chi fa questo è solo un miserabile e un perdente. Se volete partecipare su settorezero e rendere le vostre idee, i vostri progetti, fruibili da tutti senza limitazioni, come dovrebbe essere in un paese civile e acculturato, potete farlo tranquillamente.

Corso programmazione PICMicro in C – Lezione 11 (Parte 2/2) – Il convertitore Analogico Digitale – Esempi pratici – Termostato con isteresi con LM35

Autore: Giovanni Bernardo | Data pubblicazione: 15 marzo 2010
Categorie: PICmicro 10/12/16 Robotica e Automazione Sensori

In questa seconda parte della lezione sul convertitore A/D faremo ben 3 esempi pratici per sfruttarne a fondo le potenzialità e capire sia come funzionano gli strumenti più costosi che si trovano in commercio, sia come utilizzare tali funzioni a nostro vantaggio permettendoci di ottenere dei semplici sistemi di visualizzazione e controllo di valori analogici.

I primi 2 esempi saranno molto semplici e sfrutteremo unicamente un trimmer per variare la tensione in ingresso ad un pin del modulo A/D e visualizzarne il valore su una barra a led o su un display LCD.

Il terzo esempio più che un esempio è un vero e proprio progetto in quanto ci permetterà di avere una buona base da cui partire per poter realizzare un ottimo termostato completo di:

  • Impostazione soglie di intervento alta e bassa
  • Ritardo di intervento
  • Isteresi
  • Visualizzazione del valore medio di temperatura
  • Segnalazione e regolazione dei parametri tramite display LCD
  • Ritenzione delle impostazioni su eeprom interna

Chi sa di cosa sto parlando sa anche che un prodotto commerciale con tali caratteristiche è abbastanza costoso e non di facile realizzazione per un hobbysta alle prime armi. I codici sorgente possono essere scaricati dagli utenti registrati in fondo all’articolo e consiglio di scaricarli e seguirli man mano che do la spiegazione del funzionamento nell’articolo.

Accendere una serie di led in base alla tensione in ingresso

In questo esempio sfrutteremo un trimmer per pilotare un ingresso del convertitore A/D. Avremo sul pin, quindi, una tensione variabile da 0 a VDD (tensione di alimentazione del picmicro): alimentando il pic a 5 volt avremo quindi una tensione variabile da 0 a 5 volt. Sfruttando tutti e 10 i bit di conversione, avremo che ogni bit sul convertitore rappresenterà 5V/1024bit = 0,00488 V/Bit, ovvero 4,88mV/Bit come già spiegato nella prima parte di questa lezione. Fin qui, nulla di nuovo.

Supponiamo, ora, di voler rappresentare il nostro valore in maniera “grafica” riportandolo su una barra composta da 8 led, un po’ come fa un moderno Vu-Meter o uno dei tanti sensori di livello.

Implementando una scala lineare, ogni led sarà acceso a passi di 5v/8led = 0,625V/led = 625mV/led. Accenderemo, cioè, il primo led se la tensione rientra nel range 0-625mV, il secondo led si accenderà nel range 626-1250mV e così via, fino a 5V per i quali tutti e 8 i led saranno accesi.

Anzichè una “barra” si potrà anche accendere un “punto”, questa modifica è semplicissima e vedremo come farla.

Questa è, ad esempio, la funzione che svolgono i classici integrati LM3914 e LM3915 con i quali tanto ci siamo divertiti anni fa a fare i Vu-Meter.

All’uscita del convertitore A/D sappiamo di non avere un valore espresso in millivolt ma un valore intero variabile tra 0 e 1023 e rappresentativo della tensione. Nella fattispecie sappiamo che, alimentando il pic a 5Volt e utilizzando la tensione di alimentazione come riferimento, ogni bit varrà 4,88mV, per cui, ragionando in termini interi di valori del convertitore A/D (il che ci semplifica enormemente le cose) i led dovranno accendersi a passi di 625mv / 4,88 mv/bit = 128bit. Quindi il primo led sarà acceso nel range 0-128, il secondo nel range 129-256 ecc.

In questo video potete vedere il progetto in funzione:

Vediamo quindi come fare. Il circuito che realizzeremo è il seguente:

Gli schemi che mostrerò presenteranno disegnate solo le parti essenziali. Tutta la parte relativa al reset, alimentazione del picmicro, quarzo e connettore ICSP saranno tralasciati. Chi utilizza la Freedom 2 ha già tutto a disposizione e non deve fare nulla se non abilitare la stringa a led e l’ingresso analogico settando gli appositi jumper. Fate riferimento alla documentazione di Freedom II.

Per questo esempio, e quelli che seguono, anche se utilizzeremo nella pratica una sola porta come analogica, setterò per semplicità come analogiche tutte le porte a disposizione, sarete voi, per le vostre applicazioni poi a decidere quali utilizzare scegliendo i valori da impostare nella tabella presente sul datasheet del pic che avete a disposizione.

Come detto nella prima parte, dovremo settare come ingressi le porte da usare come analogiche, sappiamo che questo si fa agendo sui registri TRIStato. Sul pic16F877A le porte analogiche sono distribuite sui banchi A ed E, del banco A la sola porta RA4 non ha funzione analogica, mentre come sapete RA6 e RA7 non ci sono:

TRISA=0b00101111; // RA4 non è analogico, RA6 e RA7 non esistono
TRISE=0b00000111; // le porte RE3,4,5,6,7 non esistono

Settiamo quindi il registro ADCON0 accendendo il modulo A/D, settando la frequenza a 32Tosc (stiamo lavorando con un quarzo da 20MHz e, se avete letto la prima parte di questa lezione, sapete quanto è importante questa impostazione) e selezionando la porta da cui effettuare la lettura, che nel nostro esempio sarà AN1 (collocata su RA1):

ADCON0=0b10001001;

Quando in un’applicazione vogliamo effettuare letture da vari ingressi analogici, basterà cambiare nelle routine unicamente i bit CHS2:CHS0 di ADCON0 rimanendo invariati gli altri, questo può essere fatto o cambiando tutto il valore del registro, impostandolo mano a mano, oppure sfruttando una maschera per cambiare soltanto quei 3 bit. In pratica si realizza una sequenza del genere:

  • Prima impostazione di ADCON0 (fatta per leggere da una specifica porta)
  • Avvio la conversione (ADGO=1)
  • Terminata la conversione eseguo la lettura e salvo il valore letto in Variabile1
  • Cambio ADCON0 per poter leggere da un’altra porta
  • Avvio la conversione (ADGO=1)
  • Terminata la conversione eseguo la lettura e salvo il valore letto in Variabile2
  • Continuo così per tutte le altre porte che voglio leggere
  • Ritorno all’inizio

Settiamo quindi il registro ADCON1, impostando la giustificazione del risultato a destra e le porte scelte come analogiche (tutte nel nostro esempio):

ADCON1=0b10000000;

Nel main, quindi, andremo ad effettuare la lettura del valore e accendere la serie di led in base al valore letto. Diamo innanzitutto il ritardo di 20μS come spiegato nella prima parte, per poter caricare il condensatore di campionamento. Avviamo la conversione e cicliamo di continuo fino a che il bit ADGO non torna a zero indicandoci che la conversione è terminata.

Andiamo quindi ad effettuare la lettura dei registri ADRESH e ADRESL come già spiegato riportando il valore ottenuto in una variabile a 16bit.

Ora, in base al valore ottenuto, accendiamo i led:

Impostando PORTD a 1, si accenderà il solo led presente su RD0 (bit 0 della porta, valore 20), impostandolo a 3 si accenderanno i led presenti su RD0 e RD1 (bit 0 e 1 di portD: 20 + 21), impostandolo a 7 si accenderano i led presenti su RD0, RD1 e RD2 (20 + 21 + 22) e così via, dando l’effetto di una “barra”.

Si capisce che, se invece della barra, vogliamo visualizzare un “punto”, anzichè sommare i valori dei bit ad ogni passo, basterà attivare unicamente il singolo bit (per il secondo led, ad esempio, anzichè attivare, oltre al bit 1, anche il bit 0, attiveremo soltanto il bit 1 e quindi daremo PORTD=2. Daremo PORTD=4 per il terzo led e così via). Nel codice di esempio ho riportato entrambi i valori (per barra e punto).

Come vedete è davvero molto, molto semplice e, ovviamente, al posto del trimmer ci potrebbe essere un sensore di livello.

Utilizzando sensori di livello, o collegando un segnale analogico qualsiasi all’ingresso del picmicro, se questo supera i 5 volt, dobbiamo ridurlo facendo uso di partitori di tensione, se i livelli non sono sufficienti (pochi millivolt in ingresso) o non ci forniscono una buona “dinamica” in grado di sfruttare i 5mv di risoluzione del convertitore A/D, ci sarà bisogno di amplificatori operazionali. In ognuno di questi casi dovremo fare ovviamente degli aggiustamenti al codice per poter rappresentare il valore effettivamente letto.

Riportare il valore letto dal convertitore A/D su un display LCD

In quest’altro esempio faremo la stessa cosa, ma visualizzeremo il valore su un display LCD riportando sia il valore letto direttamente dal convertitore A/D che il valore espresso in mV. Lo schema sarà il seguente:

Questa volta, per semplificarmi le cose, non terrò conto che un bit vale 4,88mV ma utilizzerò il valore intero: 5mV tenendo conto che, per la mia applicazione, è un’approssimazione ragionevole.

In ogni applicazione vi troverete a dover fare degli scontri con valori numerici: spesso per semplificarsi le cose, si preferisce approssimare utilizzando valori interi che non causano particolari problemi al momento della stesura del codice, altre volte abbiamo la necessità si scrivere codici complicatissimi perchè ci vuole una certa precisione ecc.: tutto sta al risultato che dobbiamo ottenere, al tempo a disposizione e all’economicità dell’applicazione.

Le operazioni saranno le stesse dell’esempio precedente, con l’unica differenza che mostreremo i valori sul display. Nella prima riga mostreremo il valore letto dal convertitore A/D:

LCD_GOTO(1,11);
LCD_PUTUN(valore);
LCD_PUTS("   ");

L’ultima riga che scrive 3 spazi ha questa funzione: quando passiamo dallo scivere un valore con un certo numero di cifre, ad un valore con un numero di cifre più basso, rimarranno impresse sul display le cifre rimanenti dal numero precedente, che non vogliamo visualizzare, quindi in coda ad ogni numero stampiamo 3 spazi che servono al caso limite in cui si passa da un numero a 4 cifre a un numero ad 1 cifra. Questa operazione si poteva fare in mille modi diversi, io l’ho fatta nella maniera più sbrigativa.

Sulla seconda riga del display mostreremo il valore in Volts facendo le opportune operazioni matematiche del caso:

tensione=valore*5; // ottengo il valore espresso in millivolts tenendo conto che 1bit=5mV
LCD_GOTO(2,11);
LCD_PUTUN(tensione/1000);// parte intera dei volts
LCD_PUTS(".");
LCD_PUTUN(tensione%1000);// parte decimale
LCD_PUTS("V   ");

Moltiplicando il valore per 5 otteniamo il valore espresso in millivolt per quanto detto prima. Volendo, però, mostrare il valore in Volts, divido quindi per mille, stampando prima la parte intera (ricordo che operando su numeri interi, in C, il risultato è ancora un numero intero), quindi il punto, e infine i decimali con l’apposito operatore % che mi fornisce il resto di una divisione. Stampo infine il simbolo di Volt seguito dai 3 spazi.

Sempre per la questione delle approssimazioni, e per avvicinarmi di più al valore di 4,88 mv/bit potevo anche moltiplicare per 48 o 49 e poi dividere per 10000 (non voglio operare con valori FLOAT: il codice sarebbe complicatissimo e ci sarebbe uno spreco di memoria che per questa applicazione è inutile). Oppure ancora, potevo moltiplicare per 488 e poi dividere per 100000 e così via. Ma, per quest’ultima operazione in particolare la routine display utilizzata mostra valori sballati, non chiedetemi perchè, siate bravi voi a capirlo oppure accontentatevi dell’approssimazione.

Vediamo che, a causa dell’approssimazione utilizzata, il valore massimo di tensione visualizzato è leggermente superiore alla reale tensione di alimentazione, VDD, del picmicro e usata come riferimento. Se vogliamo semplificarci le cose, possiamo anche utilizzare dei riferimenti di tensione esterni da scegliere in maniera tale che il valore in mV di ogni singolo bit sia un valore il più intero possibile.

Termostato con regolazione separata soglie di intervento alta e bassa, con ritardo ed isteresi

Premetto che qui stiamo per affrontare una cosa abbastanza complicata e sapendo che tale argomento potrebbe non risultare semplice per molti, ho cercato quindi di semplificare quanto più mi è possibile. Realizzeremo un termostato con due soglie di temperatura: bassa e alta. Effettueremo una misurazione di temperatura e scatterà un intervento se scendiamo al di sotto della temperatura bassa e un’altro intervento se la temperatura sarà superiore alla soglia alta.

Si può immaginare questo temostato come operante in casa: se fa troppo freddo accendiamo il riscaldamento, se fa troppo caldo accendiamo il condizionatore, oppure ancora in un’acquario con pesci tropicali: il superamento della soglia bassa attiva il riscaldamento, il superamento della soglia massima attiva invece un allarme, un cicalino (una funzione di sicurezza in più che generalmente negli acquari non è prevista).

Per la misurazione di temperatura sfrutteremo un sensore analogico molto diffuso: l’ LM35 prodotto dalla National  Semiconductor (potete scaricarne il Datasheet in fondo all’articolo) e del quale analizziamo ora le caratteristiche.

  • Il sensore di temperatura LM35

Formato TO92

Abbiamo scelto l’LM35 perchè è uno dei sensori di temperatura più famosi, lo si trova a buon mercato, è semplicissimo da collegare in quanto ha solo 3 terminali: 2 per l’alimentazione Vcc e GND e uno con l’uscita analogica; l’uscita, poi, è lineare: fornisce 10mV per ogni grado centigrado (avremo quindi 0mV a 0°C e 1000mV a 100°C). Viene distribuito in vari package, il più comune è il TO92 (quello uguale ai piccoli transistor col corpo plastico a mezzaluna); in tale package è in grado di misurare da -40 a +110°C, invece nel package metallico TO46 è in grado di misurare da -50 a +150°C.

Avendo il nostro convertitore A/D una risoluzione di 5mV è facile capire che potremo apprezzare massimo il mezzo grado (se 10mV=1°C, 5mV=0,5°C), per cui non visualizzeremo mai temperature del tipo 20,8 o 20,4 ma sempre 20,0 … 20,5 … 21,0 ecc. L’accuratezza di tale sonda, comunque, è di 0,5°C per cui tutto il sistema va bene così.

Da notare inoltre che sto specificando grado centigrado in quanto altri sensori sono tarati in gradi Fahrenheit, altri ancora in Kelvin (e ci tengo a precisare: si dice Kelvin NON gradi Kelvin e il simbolo si scrive K e NON °K, come purtroppo anche su alcuni datasheet è indicato), come l’LM335.

Come si può vedere dal datasheet, tale sensore è anche in grado di misurare temperature negative; per poter fare questo, però, ha bisogno di un riferimento di tensione negativo , e quindi abbiamo bisogno di una tensione di alimentazione duale (il riferimento negativo andrà applicato al pin di uscita tramite una resistenza):

Oppure ancora, per la misura di temperature negative può essere utilizzata un’altra configurazione, che prevede un’unica alimentazione ma una seconda uscita che fornisce il riferimento negativo mediante la caduta di tensione di due diodi di tipo comune:

Sappiamo però che all’ingresso del convertitore A/D non possiamo applicare tensioni negative e comunque non ci vogliamo complicare le cose anche perchè tale termostato abbiamo deciso di utilizzarlo in casa, luogo in cui non misureremo mai temperature sotto lo zero (ci mancherebbe!). Pertanto, il sensore, così come lo utilizzeremo, nella sua maniera più semplice, sarà soltanto in grado di misurare temperature positive (a partire però da +2°C e non da 0°C):

In tale configurazione, quindi, l’LM35 non è adatto a fare un termometro da auto!

  • Problematiche da collegamento

Sul datasheet ci sono alcune note molto importanti da non sottovalutare nel momento in cui decidiamo di realizzare una sonda di temperatura remota. Viene difatti specificato che, specialmente utilizzando il package plastico (TO92), la principale fonte di calore per la misurazione proviene dai pin di collegamento, pertanto, nel caso in cui l’LM35 deve monitorare la temperatura di una superficie, i pin e una relativa piccola parte dei cavi di collegamento di essi, devono trovarsi alla stessa temperatura della superficie da monitorare e sulla quale abbiamo appoggiato la superficie piatta della sonda; questo può essere realizzato utilizzando delle apposite resine. Ovviamente tale problema non sussiste nel caso in cui l’LM35 venga utilizzato per monitorare la temperatura ambiente in quanto sia i pin che il corpo si trovano in aria libera e quindi alla stessa temperatura.

La soluzione migliore per realizzare delle sonde (specialmente per determinare temperature di liquidi, per i quali la sonda dovrà lavorare immersa in essi) è utilizzare il package metallico TO46. Nel caso in cui l’LM35 in tale formato dovrà essere utilizzata per fare una sonda da immersione, si dovrà inoltre provvedere ad un’accurato isolamento dei pin di contatto e della superficie metallica dal liquido da controllare, per prevenire fenomeni di corrosione. La sonda nel formato TO46, inoltre, può anche essere saldata direttamente alla superficie da controllare migliorando di molto le prestazioni.

Altro problema è derivato dall’uso di terminali di collegamento molto lunghi che possono introdurre una capacità della linea superiore a 50pF. In questi casi il datasheet consiglia di mettere una resistenza di 200Ω in serie all’uscita o di disaccopiare l’uscita tramite un circuito RC:

C’è un errore nella figura 3 in quanto la resistenza viene indicata come da 2KΩ mentre nel testo dice che è da 200Ω. Suppongo che il valore corretto sia 200Ω.

In ogni caso è sempre meglio mettere anche un piccolo condensatore da 100nF in parallelo all’alimentazione della sonda qualora si trovi a distanza dal circuito di utilizzo.

C’è inoltre da ricordarsi che stiamo utilizzando una sonda analogica, per cui il segnale in uscita può essere sporcato da eventuali disturbi elettromagnetici causati da apparecchiature nelle vicinanze (relè, luci a neon, linee di corrente ecc).

  • Problematiche da interfacciamento ed utilizzo in campo

Un monitoraggio continuo di una tensione in ingresso al convertitore, non sempre fornisce un segnale stabile, potremmo difatti trovarci nella condizione che il segnale misurato sia a cavallo tra un bit e l’altro, per cui il valore mostrato sul display tenderà a fluttuare causando un effetto davvero molto sgradevole e di sicuro non professionale.

Questo sgradevole effetto avrete anche potuto notarlo nei due esempi precedenti in cui non abbiamo fatto uso di nessuna tecnica per evitarlo, proprio perchè ve ne rendeste conto.

In questa applicazione, per evitare questo fenomeno, effettueremo innanzitutto la misura ogni 200millisecondi e non di continuo, e in più, eseguiremo una serie di 20 misure sulle quali sarà fatta la media e quindi solo allora sarà mostrata sul display. Abbiamo quindi una frequenza di aggiornamento (ideale) della visualizzazione di 0,2 sec/misura x 20misure = 4secondi, che, oltre a fornirci una stima più corretta della temperatura reale, ci eviterà la fastidiosa oscillazione dei valori mostrati sul display.

Abbiamo inoltre anticipato che in questo termostato imposteremo due soglie: una bassa e una alta, superate le quali scatterà un intervento (es.: un pin che comanda un relè, o un led o un suono col cicalino ecc). Prima di decidere se intervenire o meno, però, faremo una serie di verifiche per evitare di intervenire inutilmente, riducendo i consumi e allungando la vita degli elementi di intervento (relè, pompe, celle di peltier ecc).

Innanzitutto, appena si esce al di fuori della soglia impostata, sul display sarà indicata tale condizione (lampeggerà una scritta HIGH o LOW se la temperatura misurata ha superato la soglia alta o è scesa al di sotto della soglia bassa rispettivamente), ma ancora non si interverrà. Verrà quindi conteggiato un tempo, preimpostato da codice a 10 secondi (ma modificabile), allo scadere del quale la temperatura verrà nuovamente verificata: se ci troviamo ancora al di fuori della temperatura impostata + una certa soglia (isteresi), allora si interverrà; questo metodo di operare ci da un certo margine di sicurezza nell’evitare continui interventi magari causati da sbalzi di temperatura momentanei (es.: apertura di una porta nei pressi del sensore se stiamo controllando una temperatura ambiente).

L’impostazione di un’ isteresi serve appunto ad evitare la commutazione continua e ve lo spiego con un banale esempio: supponiamo di avere impostato una temperatura di 20°C, al di sopra della quale vogliamo intervenire azionando, ad esempio, una ventola di raffreddamento. Fino a 20°C non ci sarà commutazione del relè che comanda la ventola. Impostiamo quindi un’isteresi di 0,5°C: diciamo in pratica al nostro circuito di controllo che il relè dovrà scattare a 20,5°C (20°C + isteresi di 0,5°C). Si avrà, quindi che, pur avendo impostato 20°C come soglia di intervento, l’intervento scatterà “un po’ più in alto”, ma dovrà cessare, invece, una volta raggiunta la soglia impostata precisamente: 20°. Questo ci permette, appunto, di evitare commutazioni continue a cavallo della temperatura di soglia che, oltre ad essere dannose (e fatali!) ai dispositivi, sono anche vietate per legge in questo tipo di apparecchiature. In tale termostato, oltre all’impostazione dell’isteresi, come detto prima abbiamo anche aggiunto un certo ritardo di invervento (comunque azzerabile) per avere ancora maggiore sicurezza di intervenire solo se necessario.

Per maggiori informazioni su questo argomento potete consultare wikipedia: Isteresi, Termostato

Anche se impostiamo a zero l’isteresi del termostato presentato in questo esempio, ci sarà sempre un’isteresi fissa di 0,5°C non eliminabile e vi spiego perchè. Facciamo l’esempio della temperatura di soglia alta. Abbiamo impostato da codice che la segnalazione interviene solo se la temperatura è maggiore del valore impostato e NON maggiore o uguale. Essendo il nostro sistema (convertitore a 10 bit + sonda LM35) capace di apprezzare al massimo 0,5°C, vuol dire che già la segnalazione di allarme alto avverrà ad una temperatura di 0,5°C più alta di quella impostata, e quindi 20,5°C nel nostro esempio (ripeto: controlliamo una temperatura maggiore e non maggiore o uguale), e questa è una soglia di isteresi fissa che non possiamo eliminare (e a mio avviso non è uno svantaggio ma una nota positiva).

I valori di isteresi e di ritardo di intervento possono essere modificati da codice per poterli adattare al luogo in cui si dovrà intervenire tenendo conto di una moltitudine di parametri (velocità di diffusione/perdita del calore nel mezzo da controllare, eventuali interferenze esterne ecc), ma i più bravi sapranno di certo parametrizzare tali valori rendendone possibile anche la regolazione di questi dal display.

Il ritorno alle condizioni normali (reset degli azionamenti se la temperatura rientra nel range) è anch’esso vincolato al ritardo di azionamento (ma non all’isteresi per quanto detto prima, altrimenti tutto questo ambaradàn non avrebbe più senso!).

Un sistema così fatto (isteresi+ritardo di azionamento+lettura mediata della temperatura) ritengo sia abbastanza professionale ma, prima di poterlo applicare ad un sistema di termoregolazione casalingo, studiatene bene il funzionamento e segnalate eventuali bug, in quanto non garantisco nulla e il codice esposto è solo a titolo di esempio.

Altre caratteristiche di questo termostato sono:

  • Tempo di inutilizzo: se ci troviamo nella modalità SET e rimaniamo per lungo tempo senza far nulla, in automatico si uscirà dalla modalità set senza salvare i parametri.
  • Controllo impostazioni: sarebbe assurdo settare la temperatura minima con un valore superiore a quella massima; se ciò viene fatto, all’uscita della modalità SET saranno ripristinati i valori iniziali.

Potete vedere nel seguente video come funziona il termostato presentato in questo articolo:

  • Descrizione circuito e funzionamento

Lo schema è il seguente:

Utilizzando la Freedom II dovete tener conto di alcune cose: l’alimentazione non può essere data direttamente dal pickit perchè i pulsanti sulle linee RB7 e RB6 interferiscono con le linee di programmazione. Dovrete abilitare la stringa a led insieme all’LCD, per cui non preoccupatevi se i led si accenderanno a casaccio: riflettono le linee dati che vanno al display in quanto si trovano collocati sugli stessi I/O. L’unico led che dovremo tenere in considerazione è il primo, collocato su RD0

I 3 pulsanti sono collegati senza resistenze di pullup: le abiliteremo internamente con l’apposito bit del registro OPTION.

Riguardo al collegamento della sonda: guardate bene sul datasheet la disposizione dei pin dell’LM35.

All’avvio del programma viene preparato il display, mostrando le scritte che saranno sempre presenti, verranno inoltre mostrati dei trattini al posto del valore della temperatura in quanto all’avvio non sono ancora state effettuate le 20 letture da mediare come detto in precedenza.

Abbiamo un interrupt causato dal timer0 ogni millisecondo, è qui che viene gestita la gran parte delle funzioni del temostato. C’è un primo counter che controlla l’avvio della lettura dal modulo A/D:

407
408
409
410
411
412
count_lm35--; // counter per avvio lettura LM35
if (count_lm35==0) // avvio la lettura se il counter è arrivato a zero
   {
   ADGO=1;
   count_lm35=200; // resetto il contatore
   }

Questo fa in modo di effettuare la lettura dalla sonda ogni 200 millisecondi. Alla fine della lettura e conversione, scatterà l’interrupt di fine conversione A/D, che richiamerà l’apposita routine nell’ISR:

447
448
449
450
451
if (ADIF)
{
calcola=1; // abilito, nel main, l'aggiornamento del valore di temperatura
ADIF=0; // resetto il flag di fine conversione A/D
}

In pratica viene settato un flag “calcola” che nel main avvia la routine che fa la somma delle 20 letture, arrivati a 20 letture viene calcolata la media:

if (calcola)
{
valore=ADRESL + (ADRESH<<8);
media+=valore; // sommo il valore
contavalori++; // incremento il numero di valori letti
 
// abbiamo raggiunto il numero di letture impostate?
if (contavalori==(MEANVALUES-1))
{
displayvalue=(media/MEANVALUES);
media=0; // azzero la media
contavalori=0; // azzero il contatore dei valori sommati

Come vedete in tale routine viene incrementata la variabile “contavalori” che ci permette di tenere sott’occhio quanti valori abbiamo sommato. La variabile “MEANVALUES” è definita in settings e l’ho impostata a 20, rappresenta il numero di letture su cui fare la media. Dal confronto col numero di misure sottraggo 1 perchè contavalori è a base zero. Il valore da mostrare sul display è quindi “displayvalue”.

Nell’ISR vengono inoltre avviati altri contatori:

contatore_inutilizzo : il suo avvio è comandato da un flag “start_contatore” impostato solo se ci troviamo in modalità SET. Il contatore viene resettato di continuo ogni volta che ci troviamo in modalità set e si preme un tasto. Se non premiamo tasti, tale contatore giunge a zero, portando all’uscita della modalità SET e ripristinando i valori di SET a quelli iniziali:

418
419
420
421
422
423
424
425
426
427
if (contatore_inutilizzo==0) // son passati X secondi senza che il menù sia stato usato
{
setmode=MODE_NONE; // esco dalla modalità settaggio
save_settings=0; // senza salvare i settaggi
 
// riporto i valori di set a quelli che erano prima delle eventuali modifiche
valore_hi=pre_valore_hi;
valore_low=pre_valore_low;
// il flag e il contatore saranno ripristinati nel main
}

Abbiamo quindi il contatore “contaflash” che ha la funzione di far lampeggiare le scritte “HIGH” e “LOW” nel caso la temperatura misurata sia al di fuori dal range impostato. Come potete vedere dal codice, il lampeggio di una scritta sull’LCD è gestito scrivendo e cancellando ripetutamente la scritta.

Abbiamo quindi il contatore di intervento intv_counter, che giunto a zero fa scattare l’intervento (che in questo esempio è esplicitato mediante l’accensione del LED, ma voi potete anche collegare due relè, uno per l’intervento per temperatura bassa e uno per temperatura alta). L’intervento è realizzato portando a 1 il flag intv_start.

Il flag intv_start viene continuamente confrontato con il flag intv_state (che memorizza lo stato che ha causato l’allarme: temperatura alta, temperatura bassa o nessun intervento). Quando nel main viene intercettato intv_start==1, si controlla lo stato attuale, se lo stato attuale è uguale a quello settato in precedenza, viene acceso il led a segnalare l’intervento, altrimenti il flag viene resettato. Nel caso in cui lo stato precedente fosse “nessun allarme” e dopo il tempo di intervento tale stato è rimasto, il led viene spento (e qui voi dovrete far staccare entrambi i relè).

Il codice è abbastanza lunghetto, solo in main.c è da 452 righe (però compresi gli abbondanti commenti). Ma le funzioni principali ve le ho illustrate qui, il resto potrete capirlo da soli leggendo il codice.

Se trovate utile questo progetto, quantomeno per “spulciare” parti di codice e idee utili, considerate una donazione in quanto ci abbiamo lavorato su davvero per tanto tempo, cercando di realizzare un progetto davvero completo, utile e molto ricco di funzioni professionali.

Downloads

File di supporto alla undicesima lezione del corso di programmazione picmicro in C (967)
LM35 - Precision Centigrade Temperature Sensor (672)
LM335 - Precision Centigrade Temperature Sensor (Kelvin calibrated) (373)

Articoli che potrebbero interessarti

L'articolo ti è piaciuto o ti è stato utile per risolvere un problema? Supporta e mantieni in vita questo sito, ci basta soltanto un caffè o una birra.
Se desiderate che settorezero continui a rimanere gratuito e fruibile da tutti, non copiate il nostro materiale e segnalateci se qualcuno lo fa

Puoi lasciare un commento, o un trackback dal tuo sito.

  1. #1 da Roberto il 15 marzo 2010

    Gianni,
    oltre ai complimenti di rito per l’accoppiata di articoli sui convertitori A/D, avendoci già un po’ sbattuto la testa sull’argomento in precedenza e non avendo ancora potuto guardare il tuo sorgente, faccio alcune osservazioni.

    Secondo me l’allineamento naturale impostato col bit ADFM dovrebbe essere a sinistra e non a destra (anche perchè è quello di default, settato a 0), avendo così gli 8 bit più significativi su ADRSEH e quelli meno significativi (2 bit) in ADRESL. Che è un po’ il contrario di come ragioniamo noi ‘umani’.

    Però il vantaggio è che così facendo si può usare una conversione effettiva a 8bit invece che a 10bit; cioè supponendo di collegare 8 led solo ad ADRESH, vedrò che i led si accendono con scarti di 5v/255, cioè 19mV.

    Quindi si può usare agevolmente una risoluzione effettiva minore (a 8 bit) per quei casi in cui non serve a 10 bit. Altrimenti si tiene conto anche dei 2 bit meno significativi in ADRESL.

    Che dici?

    • #2 da Giovanni Bernardo il 15 marzo 2010

      Si, è un buon sistema pure questo. Secondo me alla fine è più questione di come uno è abituato a ragionare. Poi un sistema o l’altro può essere scelto in base a ciò che si vuole ottenere: se bastano solo 8 bit può essere più comodo un metodo piuttosto che l’altro.

    • #3 da Giovanni Bernardo il 16 marzo 2010

      Ho riflettuto un po’ sulla questione della giustificazione a destra o a sinistra.

      Allora… Io in realtà ho detto che è la giustificazione a destra il metodo più utilizzato perchè, a parte che ci vuole un’operazione in meno per trovare il risultato a 10bit, è la metodica normalmente utilizzata per memorizzare i risultati anche in altri tipi di processore.

      La giustificazione a sinistra prevede un’operazione aggiuntiva per trovare il risultato a 10 bit: tutta la parte alta (8bit) sta nel registro alto e la parte bassa sarà invece costituita da solo 2 bit e saranno i bit più significativi del registro basso, per cui volendo trovare il risultato a 10 bit si dovrà fare:
      (ADRESL>>6) + (ADRESH<<2)
      mentre con la giustificazione a destra:
      ADRESL + (ADRESH<<8)
      cioè uno spostamento in meno (anche se in realtà il numero di bit spostati in entrambi i casi è sempre 8, quindi non so adesso se a livello assembly tutte e due le operazioni richiedono lo stesso lavoro).

      C'è però da dire un fatto: la giustificazione a destra è comoda quando non ci interessano i 2 bit alti, in quanto ci prendiamo solo ADRESL (opzione valida magari con sensori che arrivano a fornire fino a circa 1,3V che in bit equivale a 255, e quindi non vanno oltre).

      Conviene invece usare la giustificazione a sinistra quando, al contrario, non ci interessano i due bit bassi e vogliamo solo gli 8 bit alti: in questo caso ci prendiamo solo ADRESH, e questo è valido per sensori che magari partono da 15mV (bit0+bit1), oppure per controlli di livello nei quali proprio non ci serve a nulla prendere la parte bassa.

      Che ne dici? Aggiungo queste considerazioni alla prima parte?

  2. #4 da Enrico il 16 marzo 2010

    Grazie Giovanni per la spiegazione del vu meter!
    E’ possibile usare anche più led volendo? dipende da quanti output ho giusto?

    • #5 da Giovanni Bernardo il 16 marzo 2010

      Se vuoi fare le cose semplici si, dipende dal numero di uscite che hai, se invece ti vuoi sbizzarrire e non avere limiti si possono utilizzare i SIPO tipo 74HC4094 o 74LS164 ma …. è un’altra storia ;) Se vedo riscontri positivi magari metterò un tutorial pure sull’utilizzo dei SIPO

    • #6 da Giovanni Bernardo il 17 marzo 2010

      Oppure altro sistema ancora è quello di utilizzare gli I/O expander come il PCF8575 che si pilotano in I2C

  3. #7 da bmx88 il 19 marzo 2010

    Ciao , io utilizzo per la conversione AD in ingresso un partitore resistivo
    quindi
    Vmisurato=Vreale(v1/(v1+v2))=Vreale*K
    che non è per forza un intero

    Quando scrivo la tensione sull’LCD
    non posso usare questo codice

    tensione=valore*k*5; // nel caso 1bit=5mv
    LCD_GOTO(2,11);
    LCD_PUTUN(tensione/1000);// parte intera dei volts
    LCD_PUTS(“.”);
    LCD_PUTUN(tensione%1000);// parte decimale
    LCD_PUTS(“V “);

    perche tensione non è un intero(lo definisco float)
    come posso fare a separare la parte decimale dalla parte intera?
    Grazie
    Pasquale

    • #8 da Giovanni Bernardo il 19 marzo 2010

      Definiscilo come intero, moltiplicalo per 10, 100, 1000 insomma quanto ti basta per eliminare la virgola e poi usi il sistema classico, in cui andrai a dividere per la potenza di 10 che hai usato per moltiplicare

  4. #9 da Marcustv il 23 marzo 2010

    Come mai per riuscire a compilare il programma ho dovuto inserire i files con estensione .C e .H nella cartella include del compilatore eccetto il main.c .
    Quindi ho dovuto modificarlo mettendo al posto delle virgolette (“) i segni di maggiore e minore sui files che avevo precedentemente spostato.
    Es: “lcd.c” ho dovuto modificarlo in all’interno del file main.c.
    Solo in questa maniera sono riuscito a compilare il tutto.

  5. #11 da Marcustv il 24 marzo 2010

    Forse mi sono spiegato male.
    Se nella cartella del progetto lascio tutti i files che ho scaricato dal sito (cosi come sono in origine) non riesco a compilarli.
    Infatti, ottengo una serie di errori di compilazione, nonostante nel progetto abbia detto al compilatore di includere anche le librerie richieste incluse nella cartella del progetto.
    Se invece sposto tali librerie e le metto nella cartella include del compilatore, e nel file main.c modifico le virgolette (“) e al loro posto metto i segni di maggiore e minore in maniera tale da indicare al compilatore di cercarle nella cartella include, il tutto funziona senza problemi.
    Sbaglio forse qualche cosa nella creazione del progetto ?

    • #12 da Giovanni Bernardo il 24 marzo 2010

      nonostante nel progetto abbia detto al compilatore di includere anche le librerie richieste incluse nella cartella del progetto.

      Allora mi sono spiegato male pure io e quindi lo ripeto ancora una volta, nonostante l’abbia pure scritto svariate volte: quando vai a creare il progetto, devi includere SOLO “main.c” e non tutto.

  6. #13 da Marcustv il 24 marzo 2010

    Grazie …. ora provo

  7. #14 da Marcustv il 24 marzo 2010

    Funziona ….
    Pensavo di dover fare come nel C18 dove le librerie devono venir incluse nel progetto di MPLAB se non inserite nella cartella INCLUDE

    • #15 da Giovanni Bernardo il 24 marzo 2010

      Se nel main e nelle altre funzioni hai gli “include”, allora nel progetto includi solo il main, dal momento che gli altri file verranno richiamati appunto dalle istruzioni include. Se togli tutti gli include nei codici, allora nel progetto devi includere tutto.

      Se usi gli include, includendo solo il main nel progetto, si usano le virgolette se i file da includere stanno nello stesso percorso del main, si usano invece i segni di maggiore e minore se i file da includere stanno nella cartella include del compilatore.

  8. #16 da MayTs il 22 aprile 2010

    scusami, la resistenza R1 indicata con valore 3K3 che valore ha?

  9. #18 da Peppazzz91 il 2 maggio 2010

    Salve a tutti, sono un nuovo utente.
    vorrei fare i complimenti a Giovanni per gli articoli, e vorrei fare una domanda:
    è possibile utilizzare l’adc del pic per leggere una frequenza, compararla con una di riferimento, e dare un qualche output che dica di quanto la frequenza letta è “distante” da quella di riferimento?
    non so se mi sono spiegato bene, quello che vorrei fare è un accordatore digitale, che non fa altro che leggere un segnale (da uno strumento), compararlo con una frequenza prestabilita e dire di quanto il segnale in ingresso è + alto o basso.

    • #19 da Giovanni Bernardo il 2 maggio 2010

      Esempi di frequenzimetri con il pic se ne trovano tanti in giro: puoi anche fare direttamente un frequenzimetro ma non sfruttando l’ADC ma i timers.

      Per usare l’ADC con una frequenza dovresti far passare il segnale in una rete RC e quindi misurare una tensione che sarà proporzionale alla frequenza. Dal momento che quest’ultima cosa è abbastanza complicata, secondo me sarebbe meglio costruire proprio un frequenzimetro.

      In giro ho trovato parecchia roba interessante, tra cui questo:

      http://www.gigillo74.altervista.org/index.php?id=freq13

  10. #20 da Peppazzz91 il 3 maggio 2010

    quindi, se ho ben capito, basterebbe amplificare il segnale in ingresso fino a farlo diventare un onda quadra, creare (non so se esiste, conta che come basi ho 4 anni di elettronica analogica (per conto mio) e stò facendo il terzo anno di itis (quindi un anno scarso di elettronica digitale e di programmazione in c++)) una funzione che conti il numero di impulsi ricevuti in un tempo prestabilito e divida il n° di impulsi per il tempo (e così ottengo la frequenza del segnale). in seguito basterebbe confrontarla con i valori prestabiliti (le frequenze delle note) e dare in uscita da differenza tra i 2 valori.
    giusto?

    • #21 da Giovanni Bernardo il 3 maggio 2010

      Perchè devi “amplificare il segnale in ingresso fino a farlo diventare un’onda quadra” ? Il segnale va amplificato certamente se è troppo basso per essere applicato al pic, difatti quello schema del frequenzimetro porta appunto un transistor nello stadio di ingresso proprio per tale motivo, ma non si amplifica per farlo diventare un’onda quadra. La frequenza viene appunto misurata contando un certo numero di oscillazioni in un certo tempo, indipendentemente se l’onda è quadra o meno: deve cioè variare tra un valore alto e un valore basso. Mi spiego: se il segnale oscilla tra 5 e 4,5 volt, il pic non misurerà nessuna oscillazione (in maniera diretta). Se varia tra 5 e 0 volt allora si. Quindi in dipendenza dal segnale che metti in ingresso potresti o non potresti avere bisogno di uno stadio di ingresso che ti amplifica il segnale per poterlo far contare.
      Incrementando un contatore in base al numero di impulsi ricevuti e misurando anche il tempo ecco che viene fuori un valore di frequenza che puoi anche mostrare su un display.

  11. #22 da Peppazzz91 il 3 maggio 2010

    il problema è che i segnali generati da uno strumento (in genere) non sono molto costanti, infatti alcuni accordatori di fascia bassa funzionano per i primi 2 secondi e poi smettono perchè il segnale in ingresso scende al di sotto della soglia del livello logico 1.
    il segnale in uscita dai pickup di una chitarra normalmente ha un ampiezza di 100mV nel momento in cui la corda viene colpita, ma poi scende immediatamente a poche decine di mV.
    quindio credo che l’unico modo per ottenere un accordatore efficiente sia quello di comprimere il segnale in maniera tale da renderlo quasi costante (parlo di ampiezza), e amplificandolo fino a farlo diventare un onda quadra il risultato è un segnale molto compresso (difatti i distorsori per chitarra, che comprimono moltissimo il segnale, lavorano su questo principio).

    • #23 da Giovanni Bernardo il 3 maggio 2010

      Ho capito. Beh questa è un’applicazione abbastanza particolare… Non ho idea di come si potrebbe realizzare. Qui bisogna capirne parecchio di elettronica analogica… Però se può essere di spunto ti dico un’altra cosa. Nelle gare di robotica una delle cose che fa prendere maggior punteggio è la rilevazione di una sorgente sonora che emette una nota ad una determinata frequenza. A tale scopo viene utilizzato un integrato: NE567. l’NE567 è un “tone decoder” : tramite una resistenza e un condensatore, da calcolare, gli imposti una frequenza che lui deve “agganciare”, collegandoci uno stadio con un microfono, lui “ascolta” i toni circostanti, se “sente” una nota con la frequenza impostata, manda un’uscita bassa… Non so se questa cosa potrebbe esserti utile… magari si… magari no… magari ci puoi lavorare su per tirare fuori qualcosa adatto al tuo scopo.
      Qui c’è una pagina che illustra i calcoli da fare:

      http://ospitiweb.indire.it/~sori0001/besta/esperienze/ne567.html

    • #24 da Giovanni Bernardo il 3 maggio 2010

      Qui anche c’è il progetto di un robottino da gara che fa utilizzo proprio di tale sistema per rilevare le sorgenti sonore a frequenza nota:
      http://stor.altervista.org/firstbot/page12/page12.htm

  12. #25 da Peppazzz91 il 3 maggio 2010

    vado per ipotesi (dato che ancora non so quali siano i limiti dei pic):
    se si potesse sostituire il filtro RC con un generatore di clock esterno credo che il pic potrebbe generare una frequenza variabile da (per esempio) 20 a 20k Hz , registrare il valore della frequenza in uscita (il clock per il 567) nel momento in cui l’ingresso del pic (per esempio RA0) collegato all’uscita di questo 567 va a 0.
    in questo modo saprei la frequenza esatta del segnale in ingresso.
    in seguito confrontarla con la freq. nota e dare l’output sul display.
    e ora la domanda da un milione di euri:
    esiste una funzione tale da far generare ad un pic una frequenza variabile controllata?
    comunque grazie per gli spunti

    • #26 da Giovanni Bernardo il 4 maggio 2010

      Beh certo che si può… Un’onda quadra alto non è che una serie di segnali alternati alto/basso, intervallati da pause.. Generare un’onda quadra con un pic, a frequenza variabile è abbastanza semplice. E’ far funzionare il tutto insieme che è un po difficile.

  13. #27 da Peppazzz91 il 4 maggio 2010

    beh, se non è difficile non c’è gusto :p
    non vedo l’ora che arrivino i pic

  14. #28 da PaoloPic il 24 giugno 2010

    Caro Giovanni,
    innanzitutto complimenti per gli ottimi articoli che hai pubblicato, veramente molto utili!
    Credo comunque di aver trovato un èpiccolo problemino sul listato del termostato, quando fai la media scrivi :
    ……………………………………………….
    media+=valore; // sommo il valore
    contavalori++; // incremento il numero di valori letti

    // abbiamo raggiunto il numero di letture impostate?
    if (contavalori==(MEANVALUES-1))
    ………………………………………………
    Dal confronto col numero di misure sottraggo 1 perchè contavalori è a base zero.

    Però hai incrementato “contavalori” PRIMA del confronto, quindi secondo me non devi sottrarre uno a MEANVALUES…..

    Ancora complimenti per l’ aiuto che stai dando a tutti noi

    • #29 da Giovanni Bernardo il 25 giugno 2010

      Uhm fammi pensare…:

      partenza->contavalori=0->media=1°valore->contavalori=1->confronto->media=1 e 2°valore->contavalori=2->confronto…ecc ecc

      quindi hai ragione tu, dopo il 1°valore contavalori=1, quindi bisogna togliere il -1 oppure portare l’incremento di contavalori dopo il confronto.

  15. #30 da Dany il 25 luglio 2010

    Ciao!…sto seguendo il tuo corso sulla programmazione in C…vorrei sapere, se possibile, dove hai comprato la tua demoboard che vedo nei video…io ne ho una ma è molto scomoda…vorrei poterla reperire…o quantomeno se è possibile avere lo schema e il PCB…attendo tue notizie! =)

  16. #32 da Fidus il 4 settembre 2010

    Ciao Giovanni, volevo dirti che ho risolto tutti i problemi che avevo grazie a te! Ora sto facendo veramente grossi progressi! Però ti volevo chiedere se si potevano realizzare conversioni A/D su due porte distinte e salvare i valori in variabili distinte… come posso riuscire a farlo? Sto realizzando un piccolo circuito con LCD per misurare temperatura e umidità, ho già fatto un menù funzionante, con selezioni multiple, regolazione dei parametri tramite swich, per regolare la soglia di accensione di ventole, motori ecc. Sta andando tutto a meraviglia, solo che ho quel dubbio… Da zero grazie a te guarda cosa sono riuscito a fare… Grazie…

    • #33 da Giovanni Bernardo il 4 settembre 2010

      E’ ovvio che puoi, nella lezione sugli A/D ho spiegato come fare: hai impostato di default di leggere da una porta, effettui la lettura, quindi cambi l’indirizzo della porta da leggere, rifai la nuova lettura e ricominci daccapo.

  17. #34 da nlubello il 5 settembre 2010

    Ciao giovanni,
    Volevo ringraziarti perchè le tue guide sono veramente ben fatte!
    Grazie a te ho imparato a programmare i pic.
    Ho un piccolo problema, sto realizzando un circuito che mi visualizzi il valore dell’adc tramite seriale,
    il PIC che uso è il 16F876A, ho usato tutte le accortezze da te consigliate quali la giustificazione a destra e frequenza di campionamento in base al clock utilizzato ma non mi tornano i conti, mi restituisce sempre 9555.
    La variabile che invio viene azzerata ogni volta che viene inviata e il comando che uso per inviare è il semplice printf(“%d”,&variabile).
    Cosa consigli?

    • #35 da Giovanni Bernardo il 5 settembre 2010

      Ciao e grazie.
      Devi mettere “variabile” senza la & davanti, poi dopo la stampa della variabile aggiungi anche il ritorno a capo altrimenti ti stampa tutto di continuo:

      printf("%d",variabile);
      putch(0x0A); // line feed
      putch(0x0D); // carriage return

    • #36 da nlubello il 5 settembre 2010

      Scusa mi sono perso in un bicchier d’acqua!!
      Stavo inviando solo l’indirizzo della variabile, per forza non cambiava!

  18. #38 da Antonio il 14 settembre 2010

    Salve a tutti,
    innanzitutto complimenti per il sito e le lezioni.
    Inerente all’argomento della conversione A/D interna del pic16F877A con quarzo a 4 mhz (POSSO METTERE ANCHE UN 20) vorrei porvi un quesito.
    Risolto questo dovrei completare la mia tesi.
    Devo campionare la prima tratta in salita di una sinusoide raddrizzata a 100Hz (10msec / 2=5msec) ed in contemporanea ad ogni punto misurato della sinusoide,
    la corrispondente tensione ai capi di una resistenza Rk (che avrà lo stesso andamento ma con tensioni più basse) prendere questi campioni ed inviarli via seriale al PC.
    (un provavalvole semplificato di cui allego schema di principio in fidocadj) .

    [FIDOCAD]
    BE 205 144 213 144 217 139 217 132 0
    LI 193 132 193 122 0
    LI 217 132 217 122 0
    BE 205 110 197 110 193 115 193 122 0
    BE 217 122 217 115 212 110 205 110 0
    LI 195 145 195 150 0
    LI 205 115 205 105 0
    BE 193 132 193 139 198 144 205 144 0
    PP 197 141 200 136 210 136 210 135 200 135 197 141 195 145 0
    LI 200 145 200 143 0
    LI 200 143 205 138 0
    LI 205 138 210 143 0
    LI 210 143 210 145 0
    LI 190 130 195 130 0
    LI 202 130 205 130 0
    RP 200 114 210 115 0
    LI 195 145 200 135 0
    LI -10 70 -10 75 0
    LI 195 150 195 170 0
    LI 160 150 175 150 0
    SA 205 95 0
    MC 195 190 0 0 045
    MC 150 150 0 0 073
    TY 115 140 4 3 0 0 0 * Da uscita
    LI 190 130 175 130 0
    TY 225 125 4 3 0 0 0 * DUT
    MC 210 155 3 0 073
    MC 200 155 3 0 073
    FCJ
    TY 200 155 4 3 0 0 0 * V fil
    TY 200 160 4 3 0 0 0 *
    LI 215 130 210 130 0
    LI 175 190 195 190 0
    SA 195 190 0
    TY 220 130 4 3 0 0 0 * (triodo)
    MC 175 155 1 0 ihram.res
    FCJ
    TY 165 155 4 3 0 0 0 * R2
    TY 160 160 4 3 0 0 0 * 100K
    MC 175 130 1 0 ihram.res
    FCJ
    TY 165 135 4 3 0 0 0 * R1
    TY 165 140 4 3 0 0 0 * 1K
    MC 195 170 1 0 ihram.res
    FCJ
    TY 200 170 4 3 0 0 0 * R3
    TY 200 175 4 3 0 0 0 * 10ohm
    LI 175 145 175 155 0
    SA 175 150 0
    MC 260 145 1 0 ihram.trim
    FCJ
    TY 245 145 4 3 0 0 0 * Tr1
    TY 245 150 4 3 0 0 0 * 2,2K
    MC 260 120 1 0 ihram.res
    FCJ
    TY 265 120 4 3 0 0 0 * R4
    TY 265 125 4 3 0 0 0 * 100K
    LI 260 135 260 145 0
    LI 260 95 190 95 0
    LI 260 95 260 120 0
    LI 260 160 260 190 0
    LI 260 190 195 190 0
    LI 280 155 265 155 0
    LI 175 170 175 190 0
    LI 195 185 195 190 0
    MC 280 155 0 0 073
    SA 195 165 0
    LI 220 165 195 165 0
    MC 220 165 0 0 073
    MC 190 95 1 0 750
    MC 150 95 2 0 ihram.res
    FCJ
    TY 140 75 4 3 0 0 0 * RA
    TY 125 85 4 3 0 0 0 * 2,2K 1/2W o 7W
    LI 175 95 150 95 0
    MC 100 95 0 0 210
    MC 110 105 0 0 210
    MC 110 85 1 0 210
    MC 100 95 1 0 210
    LI 135 95 120 95 0
    SA 110 85 0
    SA 120 95 0
    SA 110 105 0
    SA 100 95 0
    LI 100 95 90 95 0
    LI 90 95 90 100 0
    MC 90 100 0 0 045
    LI 85 60 110 60 0
    LI 110 60 110 85 0
    LI 110 105 110 130 0
    LI 110 130 75 130 0
    LI 40 60 25 60 0
    LI 40 130 25 130 0
    TY 115 145 4 3 0 0 0 * ampli rampa
    TY 290 145 4 3 0 0 0 * Asse X (o conv. AD)
    TY 235 165 4 3 0 0 0 * Asse Y
    TY 220 170 4 3 0 0 0 * (o conv. AD)
    TY 80 80 4 3 0 0 0 * 4×1N4004
    TY 45 50 4 3 0 0 0 * T1=220V/110+110V
    TY 200 95 4 3 0 0 0 * A
    TY 180 80 4 3 0 0 0 * Switch
    TY 185 125 4 3 0 0 0 * G
    TY 190 145 4 3 0 0 0 * K
    TY 180 85 4 3 0 0 0 * anodica
    LI 205 95 205 105 0
    MC 75 60 3 0 750
    LI 75 100 75 65 0
    LI 75 65 80 65 0
    TY 175 75 4 3 0 0 0 * (EMERGENZA)
    MC 40 60 0 0 510
    SA 75 90 0
    TY 100 20 8 6 0 1 0 * Generazione anodica
    EV 65 225 165 320 0
    EV 225 225 325 320 0
    LI 70 260 75 260 0
    LI 80 260 85 260 0
    LI 90 260 95 260 0
    LI 100 260 105 260 0
    LI 110 260 115 260 0
    LI 120 260 125 260 0
    LI 130 260 135 260 0
    LI 140 260 145 260 0
    LI 150 260 155 260 0
    BE 80 260 90 225 95 260 95 260 0
    BE 95 260 105 225 110 260 110 260 0
    BE 110 260 120 225 125 260 125 260 0
    BE 125 260 135 225 140 260 140 260 0
    LI 80 275 90 275 0
    LI 90 275 95 275 0
    LI 95 275 95 280 0
    LI 95 280 110 280 0
    LI 110 280 110 285 0
    LI 110 285 125 285 0
    LI 125 285 125 290 0
    LI 125 290 140 290 0
    LI 140 290 140 295 0
    LI 140 295 155 295 0
    SA 240 290 0
    TY 40 255 8 6 0 0 0 * CH1
    TY 40 270 8 6 0 0 0 * CH2
    LI 75 275 70 275 0
    LI 100 275 105 275 0
    LI 110 275 115 275 0
    LI 120 275 125 275 0
    LI 130 275 135 275 0
    LI 140 275 145 275 0
    LI 150 275 155 275 0
    BE 305 265 290 265 275 270 240 290 0
    BE 305 275 310 275 275 270 240 290 0
    BE 305 255 285 255 270 265 240 290 0
    BE 300 250 285 250 270 260 240 290 0
    LI 240 290 305 290 0
    BE 295 245 280 245 265 260 240 290 0
    TY 215 205 8 6 0 0 0 * oscilloscopio modalità XY
    BE 305 280 305 280 275 275 240 290 0
    TY 160 240 8 6 0 0 0 * 100Hz
    LI 160 245 140 250 0
    LI 80 205 80 225 0
    LI 95 205 95 225 0
    LI 55 210 105 210 0
    LI 100 205 90 215 0
    LI 85 205 75 215 0
    TY 55 200 4 3 0 0 0 * 10msec

    I campioni devono essere 50 per la Va e 50 per la Vk quindi 100 totali da ripetere per 7 volte quante sono le tensioni dei gradini della Vg per un totale di 700 in 70msec.
    Teoricamente, col un mio foglio di calcolo, con un midrange pic tipo 16f877A, otterrei un Tempo totale di sampling (max teorico) di 35uSec che arrotondo a 40uSec a misura.

    Facendo il semplice calcolo 5000uSec/100 = 50 sarei a cavallo ma spulciando in rete sembra che il Tsamp sia teorico.

    Io sto usando un operazionale configurato come inseguitore di tensione per cui il pic vede un impedenza molto bassa (come esponete chiaramente nel corso) per cui è ottimizzato al massimo il tempo di sampling.

    Secondo voi posso continuare in questa strada o devo usare dei convertitori esterni magari via SPI o I2C?

    Per il sincronismo ho usato unNE555 configurato a trigger di Schmitt ad ogni passaggio per lo zero dell’impulso della sinusoide genera in uscita un impulso il quale và ad un contatore binario CD4029 che, con una rete resistiva, crea una rampa positiva a 7 gradini che poi con un operazionale in configurazione non invertente rendo negativa, lo stesso impulso va su RB0 e genera l’interrupt durante il quale faccio le misure.
    L’HW funziona con l’oscilloscopio in modalità XY.
    Ho fatto il sw su PC per acquisire i dati via seriale e visualizzare le curve in questo formato:
    xxxx,yyyy;……(dove x è Va e y Vk).

    Ho sviluppato un codice per il pic non sincronizzato che funziona ma quando l’ho fatto girare sotto interrupt ha cominciato ad andare in tilt.

    Questo è il vecchio sw non sincronizzato per 72 campioni anziché 100 in mikrobasic anziché in C ma posso convertirlo (anche se penso sia di facile lettura):

    program adc2_232

    ‘******************************************************************************
    ‘ microcontroller P16F877A
    ‘ This project is designed to work with PIC 16F877A
    ‘ with minor adjustments, it should work with any other PIC MCU
    ‘ that has ADC module.
    ‘ This code demonstrates how to use library function ADC_read, and library
    ‘ procedures and functions for LCD display (4 bit interface)
    ‘ It sends the ADC conversion through USART.
    ‘******************************************************************************

    dim t as word
    Text as char[20]
    tword as string[5]
    i as byte

    sub procedure end_adc

    lcd_cmd(LCD_CLEAR)
    lcd_out(1,1,”fine campionamenti”)
    lcd_chr(2,9,”E”)
    lcd_chr(2,10,”N”)
    lcd_Out(2,11,”D “)
    delay_ms(2000)
    end sub

    sub procedure setup

    lcd_cmd(LCD_CLEAR)
    lcd_out(1,1,”Inizializzazione”)
    lcd_chr(2,9,”S”)
    lcd_chr(2,10,”T”)
    lcd_Out(2,11,”ART”)
    delay_ms(2000)
    end sub

    sub procedure sec1 ‘campionamento tensione anodica
    t = ADC_read(0)
    lcd_cmd(LCD_CLEAR)
    Text = “Tensione anodica”
    lcd_out(1,1,Text)
    lcd_chr(2,15,”V”)
    wordtostr(t,tword)
    Usart_Write_text(tword)
    lcd_out(2,3,tword)
    Usart_Write(“,”)
    delay_ms(100)
    end sub

    sub procedure sec2 ‘campionamento tensione catodica

    t = ADC_read(1)
    lcd_cmd(LCD_CLEAR)
    Text = “tensione catodica”
    lcd_out(1,1,Text)
    lcd_chr(2,15,”V”)
    wordtostr(t,tword)
    Usart_Write_text(tword)
    lcd_out(2,3,tword)
    Usart_Write(“;”)
    delay_ms(100)
    end sub

    main:
    Usart_Init(9600)
    TRISC=0×00
    PORTB =2
    TRISB =0
    intcon =0
    Lcd_init(PORTD)
    lcd_cmd(LCD_CURSOR_OFF)
    lcd_cmd(LCD_CLEAR)
    lcd_out(1,1,”Tracciacurve per valvole”)
    Text =”A. Durighello”
    lcd_out(2,1, Text)
    OPTION_REG = $80
    ADCON1 = $82
    TRISA = $FF
    Delay_ms(200)
    lcd_cmd(LCD_CLEAR)
    Text = “Letture:”
    lcd_out(2,1,Text)
    setup
    for i = 0 to 35 ‘36×2 campioni x 1 gradino (Va e Vk)
    sec1
    sec2
    next i
    end_adc
    end.

    Questo è ciò che pensavo di fare usando l’interrupt su RB0:

    program adc2_232_intrpt

    ‘Programma tracciacurve per triodi
    ‘di Durighello Antonio

    ‘SEQUENZA:
    ‘accendo il tutto e dopo 15 secondi di attesa per il riscaldamento del filamento della valvola
    ‘attivo il setup dei registri interrupt e adc
    ‘quando arriva l’impulso dello zero crossing su RB0 (interrupt INTE) si attivano le conversioni
    ’si leggono 36 campioni di Va e Vk totale 72 in 5msec all’interno di un ciclo for/next
    ‘con Va[0] a circa tempo zero e Vk[35] a circa Vmax 5msec (si testa il ritardo in uS per ottenere ciò)
    ’si ripristina il flag interrupt INTF per rilevare il nuovo passaggio per lo zero
    ’si disabilita l’interrupt per il tempo di uso della seriale che non lo gradisce ????
    ’si abilita la seriale a 9600 baud o più (vedere se l’invio si completa in 5msec altrimenti salire di velocità)
    ‘invio dati al PC via seriale con protocollo xxxx,yyyy; (Va e Vk)
    ‘il quale gestirà la curva in VB6
    ’si riattiva l’interrupt ????
    ‘il contatore count rileva 7 zero crossing e quindi 7 sequenze di misura avvenute
    ‘quindi termina disattivando GIE interrupt generale

    ‘Start with e push botton on RB1 that set GIE (general interrupt
    ‘when comes a pulse of zero crossing on RBO/INT (interrupt INTE) starting the adc conversion
    ‘I read 36 samples of Va and Vk for a total of 72 on 5msec into for/next cicle
    ‘with Va[0]on 0 in time zero and Vk[35] a Vmax

    dim counter as word
    countstr as string[2]
    anod,katod as word[36]
    a,b as byte
    t as word
    tword as string[5]

    sub procedure interrupt
    If INTCON.INTF = 1 Then ‘ check type of interrupt on RB0 zero crossing
    inc(counter) ‘ increment pulse counter

    ‘fa le prime 36 misure di Va
    for a=0 to 35
    anod[a] = t

    ‘delay_us(20) ‘ritardo da testare per Vk[35] a circa 5msec

    ‘fa le prime 36 misure di Vk
    katod[a]=t
    next a
    End If
    INTCON.INTF = 0 ‘ clear interrupt flag to catch next pulse

    end sub

    sub procedure INT_Setup
    counter = 0 ‘ clear pulse counter
    OPTION_REG.INTEDG = 1 ‘ interrupt on RB0 rising edge
    INTCON = %10010000 ‘ enable external RB0 interrupt
    adcon1=$82 ‘1000.0010 tutti analogici e vref = Vdd
    end sub

    main:
    PORTA = 0
    PORTB = 0
    PORTD = 0

    TRISA = $FF
    TRISB = $FF ‘RB0 e portB as input
    TRISD = $0 ‘port C as out for lcd

    Lcd_init(PORTD)
    lcd_cmd(LCD_CURSOR_OFF)
    lcd_cmd(LCD_CLEAR)
    lcd_out(1,1,”Tracciacurve per valvole”)
    delay_ms(15000) ‘riscaldamento filamento valvola

    INT_Setup ‘ setup registers

    While true
    wordtostr(counter,countstr)
    lcd_out(2,1, countstr)
    wordtostr(t,tword)
    lcd_out(2,10, tword)

    Usart_Init(9600)

    for a=0 to 35
    t = anod[a]
    ‘t = anod[0]

    ‘invia le prime 36 misure di Va con Vg =0V

    wordtostr(t,tword)
    Usart_Write_text(tword)
    Usart_Write(“,”) ’separatore x rispettare protocollo xxxx,yyyy;……

    ‘t = katod[a]

    ‘invia le prime 36 misure di Vk con Vg =0V

    ‘wordtostr(t,tword)
    ‘Usart_Write_text(tword)
    Usart_Write(“;”)
    next a
    Wend
    end.

    Grazie dell’aiuto
    Antonio

  19. #39 da sebastianobaldi il 27 novembre 2010

    Ciao ho caricato il tuo programma con LM35 sul simulatore proteus isis e mi dice che l’ingresso AN2 non è impostato come imput analogico ma funziona cmq.. ho ricontrollato il settings e al set analogico risulta 010 cioè portA2 quindi corretto… ora non posso ancora caricarlo direttamente su un pic per provare.. è proteus che da il warning inutilmente?

  20. #41 da sebastianobaldi il 29 novembre 2010

    Ciao ho realizzato il tuo termostato con LM35 e gli ho aggiunto un timer…(poi se vuoi il programma da inserire te lo passo :) ) io devo operare tra i 40 e i 90° ed ho notato che la sonda rileva circa un 8% in meno della temperatura reale che sui 90° sono parecchi gradi… sai come tararla o via hardware o via software in modo che rilevi la temperatura corretta?
    Tramite i comandi “ADCON0=0b10000001;” ed “ADCON1=0b10001110;” sono settati piu ingressi analogici? posso quindi con 2 LM35 fare la media dei valori registrati?
    Ed ultima cosa…. se metto un quarzo da 4Mhz e setto il prescaler a 1:4 con preload=6 sicche i tick di interup vengano precisamente a 1 mS cosi da rendere piu preciso il timer, da problemi al resto del programma?

    • #42 da Giovanni Bernardo il 30 novembre 2010

      Che curioso, un’altra persona qualche giorno fa mi stava chiedendo la stessa cosa ma per email.
      per leggere due sonde, oltre ad avere settati come analogici entrambi gli ingressi, devi ogni volta eseguire la lettura selezionando l’ingresso relativo nel registro adcon. leggi la prima, leggi la seconda e fai la media.
      Se a 90° non legge bene può darsi che c’è qualche problema di contatto della sonda col recipiente, la lunghezza dei fili e tanti altri problemi ancora.
      Col quarzo da 4MHz dovrebbe funzionare. Dico dovrebbe perchè è ovvio che con 4MHz le istruzioni ci mettono piu tempo ad essere eseguite e quindi se nell’interrupt ci sta parecchia roba che col quarzo da 4MHz non riesce ad essere eseguita, si impasta il programma.

  21. #43 da Franco il 3 gennaio 2011

    Ciao Giovanni
    C’è possibilità di ricevere un esempio per fare dialogare in RS485, 2 o più PIC
    Magari anche in Modbus?

    • #44 da Giovanni Bernardo il 4 gennaio 2011

      L’RS485 funziona uguale all’RS232 con la sola differenza che a seconda del transceiver che vai a usare potrebbe essere necessario un ulteriore pin del pic per occupare la linea, anche se ora la maggior parte degli integrati lo fanno in automatico. Per il modbus non ti so dire niente.

  22. #45 da salvatore salzano il 5 gennaio 2011

    ciao Giovanni, ottimo articolo, complimenti. Lo stavo studiando attentamente e mi è saltato l’occhio su una cosa che non mi è chiara. Nel file settings.h della barra di led dici che attivi la porta AN1 (001) invece mi pare che la configurazione che dai sia adatta a preselezionare la AN2 (010):
    // ADCON0

    ADCON0=0b10001001;

    // bit 0 -> ADON Abilitazione modulo ADC, 1=Acceso , 0=Spento

    // bit 1 -> NON USATO

    Sono io che non ho capito qualcosa o c’è qualche errore di battitura?
    grazie, ciao

  23. #47 da flep il 14 gennaio 2011

    Caro Giovanni,
    se io volessi caricare i programmi da te proposti per il 16F877A su di un 18F4550, funzionerebbe tutto lo stesso o dovrei apportare modifiche al codice?
    Scusa la banalità ma sono veramente agli esordi!!
    Ciao e grazie di tutto.

    filippo

    • #48 da Giovanni Bernardo il 14 gennaio 2011

      Qualcosina si deve adattare. Per i pic18 puoi utilizzare o l’Hitec-C per pic 18 oppure il C18 di Microchip (consigliato quest’ultimo). In particolare la configurazione col C18 non si fa piu con la macro __config ma con le direttive pragma. Poi c’è la questione degli interrupt, che sui pic18 sono a 2 livelli (ho scritto un articolo su questo) e altre cosucce da adattare.

  24. #49 da dvd.tst il 25 gennaio 2011

    Caro Giovanni, non posso fare a meno di genuflettermi dinanzi ai tuoi tutorial, da nessuna altra parte ho trovato tanta chiarezza e semplicita’ nell’esporre. Per come la vedo io, quel che so sui pic lo devo solo a te! Grazie! Sono ben lieto di offrirti qualche caffe’!

  25. #50 da Marco il 14 febbraio 2011

    Ciao Giovanni, congratulazioni per i tuoi tutorial, li trovo davvero molto interessanti e spiegati in maniera superba.
    Sto cercando di realizzare un sensore per misurare la distanza di un oggetto tramite utilizzo di un sistema ottico. Dovrei linearizzare il mio sistema, perchè ho una relazione tra tensione e distanza di tipo non lineare e a me servirebbe invece una tensione tra 0 e 10V direttamente proporzionale allo spostamento. Avevo in mente di utilizzare un micro per convertire la tensione con l’ADC e creare una lookup table e associare a ogni valore digitale un valore di tensione tra 0 e 5V da mandare in uscita. E’ possibile realizzarlo? Come si crea una lookup table?
    Grazie mille

    Marco

    • #51 da Giovanni Bernardo il 15 febbraio 2011

      L’unico sistema ottico che mi viene in mente per misurare le distanze è il laser. Ma suppongo sia complicato da implementare. Non avrai mica pensato di usare gli IR ? Come ben sai gli IR vengono assorbiti dagli oggetti scuri, quindi alla stessa distanza due oggetti di colore diverso li leggerai sempre a distanze diverse. Esistono degli appositi sensori per fare queste cose ma per quanto possano essere precisi, l’IR da sempre questo problema. L’unico sistema economico per fare bene questo lavoro è usare gli ultrasuoni. Una lookup table nient’altro è che un nome fico con cui chiamare un array.

      • #52 da Marco il 17 febbraio 2011

        Ciao Giovanni, grazie della risposta. Si utilizzerö un laser, è per un lavoro di tesi che sto svolgendo all’estero.Dovrei misurare la distanza di una valvola, il mio problema è che fino ad oggi non ho mai programmato un micro e quindi stavo leggendo un po’ i tuoi tutorial che trovo molto interessanti ed utili. Devo misurare una variazione di distanza di 10mm con un passo di 100um, quindi ho 100 campioni da prelevare in fase di calibrazione provenienti dall’ADC. Poi come faccio ad attribuire ad ogni valore dell’ADC un altro valore da mandare in uscita e poi magari costruendo un DAC R-2R ottenere una tensione che sia lineare con lo spostamento?
        Devo memorizzare i valori nella EEPROM o fare una serie di if ? Cosa mi consiglieresti?
        Scusa per il disturbo e grazie mille.
        Marco

  26. #53 da Zerototale il 16 febbraio 2011

    Salve, avrei un problema..

    Ho riadattato il programma per PIC16F876A facendo qualche piccola modifica, solo che sul display non compare nulla. Cosa potrei aver sbagliato? posso inviarti il codice così dai un occhiata? Non vorrei fosse guasto l’LCD e stia impazzendo per nulla..

  27. #54 da Zerototale il 17 febbraio 2011

    Zerototale :
    Salve, avrei un problema..
    Ho riadattato il programma per PIC16F876A facendo qualche piccola modifica, solo che sul display non compare nulla. Cosa potrei aver sbagliato? posso inviarti il codice così dai un occhiata? Non vorrei fosse guasto l’LCD e stia impazzendo per nulla..

    Ho risolto! provando un’altro display con retroilluminazione ha funzionato tutto! Una cosa che ho riscontrato è che quando si va più in basso della soglia bassa e poi si torna alla temperatura normale il led ci sta un pò per spegnersi quasi parametri dovrei modificare per diminuire il ritardo?

  28. #55 da Video Lab il 5 marzo 2011

    Ciao Giovanni !!
    Ormai sono un incubo….
    Questo è un messaggio di grazie, con quello che ho imparato nelle lezioni precedenti sono riuscito a fare un progettino con il PIC16F74 (il fornitore aveva disponibile solo questo) che legge la tensione da un trimmer e la visualizza su una coppia di display a segmenti…. lo sò… non è difficile… ma fino a 1 settimana fa non sapevo che i Pic si potevano programmare anche in C ;-)
    Grazie e buon week-end

  29. #60 da a.screm il 20 aprile 2011

    Ciao Giovanni,
    ho una domanda, forse banale..ho notato che nel primo esempio (lettura tensione con trimmer)
    hai inserito un condensatore da 470 pF.
    Se ho capito bene come funziona l’ ADC il condensatore di campionamento
    dovrebbe essere gia’ presente all’ inteno del PIC.
    Serve forse per filtrare il “rumore” dovuto alla rotazione del trimmer?
    Grazie ai tuoi tutorial sto imparando molto sull’elettronica digitale, ma con quella
    analogica sto remando ancora parecchio..

    Ciao e grazie.
    Alessandro

  30. #62 da Laif il 4 giugno 2011

    Ciao!
    ho fatto questo programma che associa ad ogni valore campionato con un potenziometro da 5K, una frequenza gestita con il timer0
    per avere una scala di note musicali,però non funziona, qualcuno mi può dire dove sbaglio?come lo potrei modificare?
    Grazie

    #include // Include file con le specifiche del nostro micro
    //__CONFIG(0×0D41);
    __CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT); //(imp. da usare con PICKIT 2)
    #include “delay.c”
    //*************************************************************************************************
    void ritardo(void); //serve a creare un ritardo tramite dei cicli a vuoto FOR
    int t,attesa=1000; //stabilisce il numero di cicli che deve fare la funzione”ritardo”
    unsigned int valore=0; //valore che ottengo dal convertitore
    unsigned load; //serve a caricare il timer 0

    //*************************************************************************************************
    // MAIN PROGRAM
    //*************************************************************************************************
    void main(void) {
    TRISA=0b00101111; // RA4 non è analogico, RA6 e RA7 non esistono
    TRISE=0b00000111; // le porte RE3,4,5,6,7 non esistono
    TRISB=0b00001111;
    TRISC=0b00000000;
    TRISD=0b00000000;//uscita

    //INTCON——————————————————————————————
    INTCON=0b10100000;//—————————————————————————-
    ADCON0=0b10001001;
    ADCON1=0b10001110;

    // BLOCCO AD ELABORAZIONE CICLICA —————————————————————
    while(1)
    {
    DelayUs(20);
    ADGO=1;
    while(ADGO)
    {continue;}
    valore=ADRESL + (ADRESH<<8);

    ADGO=1; // avvio la conversione
    while(ADGO)//sta campionando

    valore=ADRESL + (ADRESH<<8); //allineamento a sinistra faccio shiftare

    //Valori da assegnare al TMR0 in base al valore campionato in base al valore campionato.
    // NOTA Freq. Periodo[s]

    //
    for(valore=0;valore85;valore170;valore170;valore340;valore425;valore510;valore595;valore680;valore765;valore850;valore935;valore<1023;valore=1023) // SI4 B4 494 0,002024291
    {OPTION=0b00000101;

    TMR0=98; // TMR0=100;
    load=TMR0;} //(1024/12=85,33333 85×12 1020)
    //**************************************************************************************
    }

    }

    //*************************************************************************************************
    //*************************************************************************************************
    // INTERRUPT SERVICE ROUTINE
    //*************************************************************************************************
    static void interrupt IntRout(void) {
    TMR0 = load;//ricarico il timer
    T0IF = 0; //azzero TOIF
    if(RD2) // cambio lo stato di RD2 per creare la nota.
    {RD0=0;
    }
    else
    {
    RD2=1;
    }
    }

  31. #63 da StefanoViareggio il 5 agosto 2011

    Salve, seguo da molto tempo i suoi corsi sui pic e devo dire che mi hanno aiutato molto.
    Ad oggi mi trovo con due dubbi
    -nell articolo si parla di una resina da mettere sulla sonda lm35 dove posso trovarla? come si chiama di preciso?

    - se metto un led all uscita del pic senza interporci una resistenza questo funziona correttamente con un assorbimento di circa 16 mA. Se invece ci interpongo una resistnza calcolata per far funzionare il led a 3 volt la luminosita secnde tantissimo. E come se l uscita del pi fosse limitata ad una corrente di circa 15 mA e normale ciò?

    • #64 da Giovanni Bernardo il 6 agosto 2011

      Non ho idea di come si chiami la resina nè di dove trovarla, comunque se fa un giro su ebay è probabile che si trovino sonde già incapsulate, io ne ho trovate fatte con le DS18B20 in Cina. La questione del led è anomala… se parla di un led normale (giallo, rosso, verde non ultraluminosi) l’assorbimento sta intorno ai 20mA con un funzionamento di circa 3V per cui la resistenza è necessaria. Non c’è nessuna limitazione di corrente, I pic tirano fuori generalmente intorno ai 40mA

      • #65 da StefanoViareggio il 6 agosto 2011

        Quindi il problema del led è solo un malfunzionamento dovuto al pic. Poiché senza alcuna resistenza l’assorbimento e di 15 mag circa. Con altri pic non dovrei riscontrare lo stesso problema quindi?

        • #66 da Giovanni Bernardo il 7 agosto 2011

          Hai visto sul datasheet quanta corrente portano i pin del pic che stai usando? E poi che tipo di led stai usando, ultraluminoso o normale? Come alimenti il pic? Non è che usi un alimentatore da banco e hai la limitazione di corrente al minimo?

  32. #67 da marco2551 il 9 settembre 2011

    Ciao, intanto tanti complimenti per il blog, per la passione che ci metti e per le guide che scrivi (semplici e alla portata di tutti). Spero continuerai a scrivere guide nonostante tutto !

    Avrei una domanda da farti, ti spiego il problema:
    Seguendo le tue guide ho creato un termostato con il classico LM35, un po di input per settare i parametri e un lcd per mostrare temperatura e altre cose. La retro illuminazione del LCD e comandata tramite PWM da un piccolo transistor (connettore al catodo del LCD e emettitore a massa) cosi da poter decidere l’intensita luminosa. Fino qua nessun problema di programmazione.

    Mi sono accorto che LM35 è parecchio disturbato da questa cosa, nel senso che se unisco l’emettitore del transistor al catodo dell LM35 (entrambi a massa) segna una temperatura sbagliata (circa +10 gradi), se invece utilizzo un coccodrillo e attacco emettitore del transistor direttamente alla massa dell’ alimentatore, LM35 segna una temperatura esatta. La cosa è molto strana, perche sia nella prima che nella seconda configurazione la massa è sempre la stessa.

    Hai qualche idea di quale potrebbe essere il problema ?
    (il pic e lcd sono su un PCB, LM35 e il transistore che regola la luminosita sono su una breadboard)

    • #68 da Giovanni Bernardo il 9 settembre 2011

      La risposta te la sei data da solo:
      LM35 e il transistore che regola la luminosita sono su una breadboard
      metti tutto su una millefori, fa delle buone saldature e vedi che il problema scompare. Metti anche un piccolo condensatore ceramico sull’uscita dell’LM35 e un altro sul positivo di alimentazione, più vicini possibile al sensore.

  33. #70 da Mr Camarium il 19 ottobre 2011

    il codice qui sotto lo ho adattato per il PIC 16f876
    ho aggiunto una riga in più per la cicalina volevo sapere se avevo fatto bene.
    #define XTAL_FREQ 20MHZ
    #include

    __CONFIG (FOSC_HS & WDTE_OFF & PWRTE_ON & BOREN_OFF & LVP_OFF & CPD_OFF & WRT_OFF & DEBUG_OFF & CP_OFF);

    __EEPROM_DATA(0×1E,0×24,0×00,0×00,0×00,0×00,0×00,0×00);

    #include “settings.h”
    #include “delay.c”
    #include “lcd.c”
    #include “eeprom_internal.c”

    void main(void)
    {
    settings();
    LCD_INIT();
    DelayMs(100);
    LCD_CLEAR();
    LCD_GOTO(1,1);
    LCD_PUTS(“Temp:–.-”);
    LCD_GOTO(1,10);
    LCD_PUTCH(0b11011111);
    LCD_PUTS(“C”);
    LCD_GOTO(2,1);
    LCD_PUTS(“TL:”);
    LCD_GOTO(2,9);
    LCD_PUTS(“TH:”);
    calcola=0;
    save_settings=0;
    start_contatore=0;
    started=0;
    flash=0;
    intv_counter=intv_delay;
    intv_state=MODE_NONE;
    REL1=0; // Relè spento
    REL2=0; // Relè spento
    BL=1; // Led Display Acceso
    valore_low=eei_read_byte(0);
    valore_hi=eei_read_byte(1);
    pre_valore_hi=valore_hi;
    pre_valore_low=valore_low;

    while(1)
    {
    if (calcola)
    {
    valore=ADRESL + (ADRESH<<8);
    media+=valore;
    contavalori++;
    if (contavalori==(MEANVALUES-1))
    {
    displayvalue=(media/MEANVALUES);
    media=0;
    contavalori=0;
    LCD_GOTO(1,6);
    LCD_PUTUN((displayvalue*5)/10);
    LCD_PUTS(".");
    LCD_PUTUN((displayvalue*5)%10);
    if (displayvalue<20)
    {
    LCD_GOTO(1,9);
    LCD_PUTS(" ");
    }

    started=1;
    }
    calcola=0;
    }

    if (!BTN_SET && started)
    {
    DelayMs(70);
    if (!BTN_SET && started)
    {
    while (!BTN_SET) {} // per evitare di ciclare di continuo se si tiene premuto il tasto
    setmode++; // cambio la modalità
    if (setmode==3) // le modalità settaggio vanno da 0 a 2
    {
    setmode=0;
    }
    }
    }

    switch (setmode)
    {
    case MODE_NONE:// uscita dal menù

    LCD_GOTO(2,3);
    LCD_PUTS(":");
    LCD_GOTO(2,8);
    LCD_PUTS(" ");
    LCD_GOTO(2,11);
    LCD_PUTS(":");
    LCD_GOTO(2,16);
    LCD_PUTS(" ");

    start_contatore=0; // fermo il contatore di inutilizzo
    contatore_inutilizzo=20000; // resetto il contatore di inutilizzo

    if (save_settings) // devo salvare i dati all'uscita dal menù?
    {
    if (valore_hi(199-hyst)) // 199 corrisponde a 99.5°C
    // il valore non deve superare il massimo meno l’isteresi
    {
    valore_appoggio=(199-hyst);
    }
    }
    }

    // controllo pressione del tasto di decremento
    if (!BTN_DN)
    {
    DelayMs(70);
    if (!BTN_DN)
    {
    contatore_inutilizzo=20000; // resetto il contatore di inutilizzo
    valore_appoggio–;
    if (valore_appoggio<4) // 4 corrisponde a 2 gradi, che è il minimo che l'LM35 può
    // leggere in questa configurazione
    {
    valore_appoggio=4;
    }
    }
    }

    // una volta controllata la pressione dei pulsanti e aggiornato il valore di appoggio
    // devo pure aggiornare il valore reale che stiamo modificando
    if (setmode==MODE_SET_LOW)
    {
    valore_low=valore_appoggio;
    }
    else
    {
    valore_hi=valore_appoggio;
    }

    } // fine controllo pulsanti/modalità settaggio

    valore_appoggio=(valore_low*5)/10;
    LCD_GOTO(2,4);
    if (valore_appoggio<10) {LCD_PUTS(" ");}
    LCD_PUTUN(valore_appoggio); // parte intera
    LCD_PUTS(".");
    LCD_PUTUN((valore_low*5)%10); // parte decimale

    valore_appoggio=(valore_hi*5)/10;
    LCD_GOTO(2,12);
    if (valore_appoggiovalore_hi)
    {

    // segnalazione temperatura maggiore della massima
    if (!flash)
    {
    LCD_GOTO(1,13);
    LCD_PUTS(“HIGH”);
    }

    // se lo stato precedente è diverso da questo,
    // azzero il flag di intervento start e resetto il contatore
    if (intv_state!=MODE_SET_HI)
    {
    intv_counter=intv_delay;
    intv_start=0;
    }

    intv_state=MODE_SET_HI; // setto la modalità di intervento
    }
    else if (displayvalue=valore_low) && (displayvalue<=valore_hi)) // il valore è rimasto nel range
    {
    REL1=0; // resetto l'intervento
    REL2=0; // resetto l'intervento
    CICALINO=0; // resetto cicalino
    }
    break;

    case MODE_SET_LOW:
    if (displayvalue(valore_hi+hyst)) // il valore è rimasto alto
    while(1) // eseguo un ciclo finito
    {
    REL2=1; // intervengo
    DelayUs(200);
    CICALINO=1;
    DelayUs(200);
    CICALINO=0;
    }// Fine ciclo continuo
    break;
    }
    intv_start=0; // resetto il flag di intervento
    }

    // infine, se il bit flash è settato a 1, cancello l’eventuale scritta nella parte destra del display
    // la scritta sarà poi reimpostata dalle altre funzioni, reimpostandola e cancellandola, lampeggia
    if (flash && !setmode)
    {
    LCD_GOTO(1,13);
    LCD_PUTS(” “);
    }
    } // fine ciclo infinito
    } // fine main

    void interrupt ISR(void)
    {

    if (T0IF) // interrupt ogni millisecondo
    {
    TMR0=102; // ricarico il timer0

    // controllo avvio conversione A/D
    count_lm35–; // counter per avvio lettura LM35
    if (count_lm35==0) // avvio la lettura se il counter è arrivato a zero
    {
    GO=1;
    count_lm35=200; // resetto il contatore
    }

    // controllo tempo inutilizzo menù
    if (start_contatore) // devo conteggiare il tempo di inutilizzo?
    {
    contatore_inutilizzo–;
    if (contatore_inutilizzo==0) // son passati X secondi senza che il menù non sia stato usato
    {
    setmode=MODE_NONE; // esco dalla modalità settaggio
    save_settings=0; // senza salvare i settaggi
    // riporto i valori di set a quelli che erano prima delle eventuali modifiche
    valore_hi=pre_valore_hi;
    valore_low=pre_valore_low;
    // il flag e il contatore saranno ripristinati nel main
    }
    }

    // lampeggio allarme
    contaflash–;
    if (contaflash==0)
    {
    contaflash=500;
    flash^=1; // inverto lo stato di flash
    }

    // controllo ritardo intervento
    intv_counter–;
    if (intv_counter==0)
    {
    intv_start=1;
    }

    T0IF=0; // resetto il flag di interrupt su timer0
    }

    if (ADIF)
    {
    calcola=1; // abilito, nel main, l’aggiornamento del valore di temperatura
    ADIF=0; // resetto il flag di fine conversione A/D
    }
    }

  34. #72 da Mr Camarium il 20 ottobre 2011

    quando mi va a generare il hex non mi da problemi volevo sapere se come ho fatto io il cicalino funzionerà non vorrei perdere tempo nel smontare 100 volte il pic.

Devi essere collegato per lasciare un commento.

  1. Ancora nessun trackback
settorezero.com e il logo Zroid™ ©2007÷2012 Giovanni Bernardo - E' vietata la copia e la distribuzione anche parziale dei contenuti di questo sito web senza l'esplicito consenso dell'autore.
I contenuti di settorezero.com sono distribuiti sotto una licenza Creative Commons Attribuzione-Non Commerciale-Non Opere derivate 2.5 Italia a cui vanno aggiunte le condizioni d'uso definite nel disclaimer.
settorezero.com e tutti i suoi contenuti sono tutelati dalla legge sul diritto d'autore per cui i trasgressori sono perseguibili a norma di legge.
Creative Commons BY-NC-ND 2.5
Il tema di questo sito è basato sul tema Fusion per wordpress, realizzato originariamente da digitalnature e fa uso del plugin Wassup per il computo delle statistiche. Per contattare l'autore siete pregati di utilizzare la sezione contatti.
Per essere aggiornato con tutte le novità di settorezero.com seguici anche anche su Facebook Twitter Tumblr Blogspot Youtube.