Progetti - PIC

 

1 LED - 5 funzioni


Può capitare di avere bisogno di un indicatore per una grandezza di cui non è indispensabile conoscere il valore, bensì se esso è all' interno di un certo range o al disotto di un dato limite.

In questi casi un display a caratteri (che deve essere letto) sarebbe meno efficace di qualche LED (che è immediatamente apprezzabile). 

In passato era stato realizzato un circuito con i classici comparatori, genere LM311 o LM339, e un operazionale quadruplo, genere LM324 che forniva su un LED bicolore le seguenti indicazioni:

  • LED verde fisso - valore bassa
  • LED verde lampeggiante - valore in salita
  • LED lampeggiante verde/rosso - valore medio
  • LED rosso lampeggiate - valore alto
  • LED rosso fisso - valore eccessivo

In questo modo, con un solo punto su cui concentrare l' attenzione, è possibile visualizzare 5 diverse situazioni di una tensione che può arrivare da un partitore o da uno shunt o da un qualsiasi sensore o punto del circuito.
 
Nella pratica, questo genere di indicatore è sempre risultato efficace, nonostante la sua semplicità, perchè è di immediata lettura e permette all' utilizzatore una rapida valutazione. Le situazioni di lampeggio, poi, attirano l' attenzione molto più di una indicazione numerica da leggere ed interpretare. 
Dato che all'ingresso abbiamo una tensione, possiamo discriminare anche lo stato di carica di batterie, i livelli di tensioni in arrivo da sensori di pressione o corrente, ma anche come indicatore di limiti di velocità, sulla tensione in uscita di convertitori F/V e ogni altra applicazione dove occorre individuare a prima vista lo stato di un segnale.

Con lo sviluppo attuale dei microcontroller, dotati di convertitore AD, una revisione del circuito non poteva che passare dal tutto-analogico al tutto-digitale, con il vantaggio di un numero molto minore di componenti e la possibilità di variare i punti di commutazione senza aver bisogno di calcolare partitori e disporre di resistori di valori poco comuni.


Il microcontroller analogico-digitale

Un caso pratico si può verificare con un dissipatore di calore per semiconduttori, del quale occorre sapere se la temperatura supera un dato valore, per poter, ad esempio, agire sulle regolazioni o inserire un sistema di ventilazione.

Data la necessità di valutare una tensione analogica, utilizziamo un microcontroller dotato di modulo ADC, modulo che è disponibile anche sui minuscoli PIC della serie 10F.
In particolare, lo troviamo in 10F220/22 , chip analoghi che si differenziano solamente per la quantità di memoria disponibile.

Possiamo, ovviamente, utilizzare qualsiasi altro microcontroller con ADC, ma, dato che servono solamente due pin per il comando del LED e uno per l' ingresso della tensione da monitorare, i PIC10F a 6 pin (4 I/O) sono più che adeguati, oltre ad avere un costo minimo e ad occupare uno spazio quanto mai ridotto (nella versione SOT23-6).

Il circuito elettrico è, ovviamente, extra semplice:

IC1 è un comune 78L05 per fornire una tensione stabilizzata al PIC, indispensabile dato che il suo ADC usa la Vdd come Vref per la conversione.

In questo modo il circuito è alimentabile a partire da 7V circa, fino a oltre 24V. Se è già disponibile una tensione di 5V con poche decine di milliampere, IC1 e C3 possono essere omessi (ma C2 no).

C1 100nF
C2 2.2uF-10uF
C3 10uF-100uF
R1/2 220ohm

IC1 (o una Vdd ben stabilizzata) è indispensabile: anche se il PIC è alimentabile di per sè a partire da 2V e non richiede una particolare stabilità della Vdd, serve comunque una tensione di alimentazione precisa e di buona qualità, dato che essa è la Vref per la lettura AD, altrimenti avremo difficoltà ad interpretare i risultati della conversione. 

Il modulo ADC dei PIC10F22x è a 8 bit e, in una applicazione semplificata come questa, la precisione della tensione di riferimento fornita da un lineare a tre terminali è sufficiente per la conversione. Però, se necessitasse una conversione a 10 bit 0 12 bit, sarebbe indispensabile un diverso microcontroller, dotato di ingresso per una Vref esterna, fornita da un riferimento di tensione di precisione (LM4040 e simili), oltre ad una Vdd a basso rumore.
  
Il LED è un bicolore a tre pin, con un elemento rosso ed uno verde; in dipendenza dal tipo usato, occorre variare le resistenze R1 e R2 per ottenere la luminosità voluta, ovviamente non superando i 25mA limite della corrente erogabile dai pin del microcontroller.

Il LED indica all' utilizzatore lo stato della temperatura raggiunta, passando dal verde al giallo al rosso con l' aumentare della temperatura stessa, la cui situazione è di lettura immediata. Sono state fissate le seguenti condizioni:

Temperatura LED Situazione
T<40°C Verde Temperatura bassa
40°C<T<50°C Verde/Giallo lampeggiante Temperatura in salita
50°C<T<60°C Giallo Temperatura media
60°C<T<70°C Giallo/Rosso lampeggiante Temperatura alta
70°C<T Rosso Sovratemperatura

Il "giallo" è il coloro che appare facendo commutare verde e rosso con un duty cycle del 50% circa.
"giallo/rosso lampeggiante" è ottenuto mantenendo acceso il LED rosso e commutando il verde; così pure il "verde/giallo lampeggiante" è ottenuto mantenendo acceso il verde e commutando il rosso.
Il "giallo lampeggiante" è ottenuto commutando contemporaneamente rosso e verde.
Si potranno con facilità ottenere altri effetti, combinando i tempi di accensione e spegnimento dei due LED.

Il funzionamento è semplice: il microcontroller legge la tensione da valutare e, in base ai limiti impostati, comanda l'accensione dei LED.
Possiamo anche impiegare una uscita per un relay oppure utilizzare un microcontroller con un numero maggiore di I/O per comandare una barra di LED e così via.


Il programma

Ovviamente, dato il tipo di chip usato, che è un Baseline con risorse minimali, il programma è in Assembly ed è pure extra semplice.

Il flow chart del programma, anche nel caso di un semplice programma come questo, è un elemento importante per il programmatore, dato che la sua stesura permette di avere una immagine chiara di cosa si vuole ottenere e consente di trasformare il percorso logico in istruzioni in modo molto più semplice che se non lo si fosse disegnato.

Il programma "attivo" consiste essenzialmente in un loop che ricicla alla cadenza di circa 1/4 di secondo le seguenti operazioni:

  • lettura dell' ADC
  • valutazione del risultato secondo la tabella vista prima
    comando dei LED
  • temporizzazione

La temporizzazione determina la velocità di lampeggio. Variandola, si otterranno cadenze diverse. Dato che è una subroutine, può essere sostituita con semplicità .

Nel nostro caso, la tensione da misurare arriva da un economico sensore attivo, MCP9701 di Microchip:

      

In particolare, l' uscita proporzionale alla temperatura consiste in una tensione che varia di 19.5 mV/°C.

Il componente è disponibile nel classico contenitore TO-92, ma anche in SOT23 e in SC70 per SMD. 

Può valutare da -40°C a +150°C, con una accuratezza di ±2°C tra 0 e 70°C.

E' previsto per una connessione diretta con l' ingresso analogico del microcontroller e non richiede alcun circuito di condizionamento o linearizzazioni particolari nel campo di letture previsto.

Ovviamente è possibile impiegare altri sensori analoghi, come MCP9700 o LM35, adeguando i valori a cui si effettua il passaggio di stato dei LED.

Osserviamo che la risoluzione di uno step del valore in uscita del convertitore AD a 8 bit, con 5V di tensione di riferimento è:

Vstep = Vref / step = 5 / 256 = 0.019531V

ovvero proprio i 19.5mV previsti dal costruttore. Questo semplificare grandemente il software, dato che non servono particolari tarature o calcoli complicati.

MCP9701 ha un offset a 0°C pari a 400mV, il che gli permette di misurare anche temperature al di sotto dello 0°C.
Quindi, la tensione ad una data temperatura superiore a 0°C è pari a: 

Vt = .400 + (0.0195 * T)

Ad esempio, quella a 50°C sarà data da:

Vout50 = (19.5 x 50) + 400 = 975 + 400 = 1375 mV

Possiamo facilmente stilare una tabella che indica il rapporto tra la temperatura e la tensione in uscita dal sensore:

Temperatura Tensione
30°C 0.985V
40°C 1.18V
50°C 1.375V
60°C 1.57V
70°C 1.765V

Ma, in pratica, per quanto detto prima, non ci interessa neppure sapere il valore della tensione, in quanto possiamo effettuare la valutazione direttamente in base al valore a 8 bit risultante dalla conversione AD:

Temperatura Tensione ADC
dec hex
30°C 0.985V 50 32
40°C 1.18V 60 3C
50°C 1.375V 70 46
60°C 1.57V 80 50
70°C 1.765V 90 5A

I valori sono arrotondati, dato che nell' applicazione non importa una precisione maggiore, ottenibile comunque con algoritmi di correzione un poco complicati (bitwise) e descritti nelle Application elencate al fondo di queste pagine.

Vediamo ora come trasformare il flowchart in istruzioni.

All' inizio trova posto la solita testata introduttiva-esplicativa, che è di aiuto per comprendere lo scopo del programma, oltre a tratteggiare le connessioni tra chip e resto dell' hardware.

;********************************************************************
;--------------------------------------------------------------------
;
; Titolo        : Indicatore di temperatura per dissipatori.
;                 PIC10F220/222 + sensore MCP9701
; Versione      : V0.0
; Ref. hardware : 110T4
; Autore        : afg
;
;--------------------------------------------------------------------
;********************************************************************
;
; Impiego pin :
; ----------------
; 10F220/2 @ 8 pin DIP         6 pin SOT-23
;
;      |¯¯\/¯¯|                  *¯¯¯¯¯¯|
; NC  -|1    8|- GP3        GP0 -|1    6|- GP3
; Vdd -|2    7|- Vss        Vss -|2    5|- Vdd
; GP2 -|3    6|- NC         GP1 -|3    4|- GP2
; GP1 -|4    5|- GP0             |______|
;      |______|      
;
;                   DIP SOT
; NC                 1   -    -
; Vdd                2   5    Vdd
; GP2/T0CKI/FOSC4    3   4    Out LED G
; GP1/AN1/ICSPCLK    4   3    Out LED R
; GP0/AN0/ICSPDAT    5   1    Analog In 
; NC                 6   -    -
; Vss                7   2    Vss
; GP3/MCLR/VPP       8   6    MCLR
;
;
;********************************************************************
;##################################################################

Ora selezioniamo il processore. 
Siccome PIC10F220 e 10F222 si differenziano solamente per la quantità di memoria disponibile, la cosa più pratica è quella di creare un sorgente adatto per entrambi.  La selezione del processore nella barra di comando di MPLAB garantisce il funzionamento dell' automatismo, gestito con #ifdef che seleziona gli include adeguati.

;--------------------------------------------------------------------

 #ifdef __10F220

    list p=10F220  ,   r = DEC
    #include "p10f220.inc"
 #endif

 #ifdef __10F222

    list p=10F222  ,   r = DEC
    #include "p10f222.inc"
 #endif

In sostanza, se in MPLAB si è scelto nella creazione del progetto o attraverso il comando Configure/Select Device il PIC10F220

la struttura #ifdef farà si che il compilatore esegua solamente le righe evidenziate:

;--------------------------------------------------------------------

 #ifdef __10F220

    list p=10F220  ,   r = DEC
    #include "p10f220.inc"
 #endif

 
#ifdef __10F222

    list p=10F222  ,   r = DEC
    #include "p10f222.inc"
 #endif

Nel caso in cui fosse selezionato il 10F222:

;--------------------------------------------------------------------
#ifdef __10F220

    list p=10F220  ,   r = DEC
    #include "p10f220.inc"
 #endif


 #ifdef __10F222

    list p=10F222  ,   r = DEC
    #include "p10f222.inc"
 #endif

Da notare che la definizione del processore appare nella lista dei simboli (file .lst risultante dalla compilazione) preceduto da una doppia sottolineatura __ , che, nella convenzione di Microchip, indica una label riservata dell' ambiente di compilazione.

In questo semplice modo si potrà scrivere un solo sorgente automaticamente adattabile a due processori differenti.

Da notare che stabiliamo il riferimento generale per i valori numerici alla radice decimale, r = DEC,  che è più "naturale" rispetto al default esadecimale.

Passiamo ora alla Configuration Word , che è semplice, date le limitate risorse disponibili nel chip. In particolare:

;####################################################################
;
;====================================================================
;=                      CONFIGURAZIONE                              =
;====================================================================


 __config _CP_OFF & _MCLRE_ON & _IOFSCS_4MHZ & _MCPU_ON & _WDT_OFF
  •  _MCPU_ON  abilita un pull up interno sul pin MCLR, evitando la necessità di cablarne uno esterno
  •  _MCLRE_ON  abilita GP3 come MCLR
  •  _IOFSCS_4MHZ fissa il clock a 4MHz con l' oscillatore interno
  •  _WDT_OFF e _CP_OFF  disabilitano rispettivamente il Watchdog e la protezione

Osserviamo che questo chip consente di:

  • avere un clock interno a 4MHz, condizione indispensabile dato il bassissimo numero di pin: se ne venissero dedicati 2 ad un oscillatore esterno ne rimarrebbero solamente altri due disponibili come I/O. Tra l' altro il clock può essere accessibile dall' esterno attraverso uno dei pin; qui questa opzione non è abilitata dato che servono tutti gli I/O disponibili.
  • predisporre il pin MCLR sia come reset esterno che come I/O. Qui lo lasciamo alla funzione MCLR, per la quale non occorre neppure aggiungere una resistenza esterna di pull-up, dato che con _MCPU_ON abilitiamo quella integrata. Un componente risparmiato.

Assegniamo ora i valori limite dei gradini relativi alle varie modalità di funzionamento

;********************************************************************
;*                   ASSEGNAZIONI LOCALI                            *
;********************************************************************     

; Uscita LMCP9701 19.5 mV/°C + 400mV
;             temp     Vout    ADCdec  ADChex 

k1 equ .60  ; 40°C -> 1.180V ->  60 -> 3Ch
k2 equ .70  ; 50°C -> 1.375V ->  70 -> 46h
k3 equ .80  ; 60°C -> 1.570V ->  80 -> 50h
k4 equ .90  ; 70°C -> 1.765V ->  90 -> 5Ah
k5 equ .100 
; 80°C -> 1.960V -> 100 -> 64h

Se si usano altri sensori (MCP9700, LM35, ecc) o altri step di temperatura, basterà variare di conseguenza questi valori.

Definiamo ora l'impiego dei GPIO e della memoria RAM.
In particolare, il comando dei LED in uscita si riferisce, come simbolo, direttamente alla shadow utilizzata per evitare il problema R-M-W.
Così nella RAM si deve riservare una locazione per questa shadow.
Usare in un caso così semplice una shadow di I/O non è strettamente necessario: essendo il carico costituito solamente da LED, il problema R-M-W non si presenta, ma è comunque opportuno utilizzare per principio la corretta procedura di accesso all' I/O dei PIC privi di registro LAT.

;====================================================================
;                 DEFINIZIONE DI IMPIEGO DEI PORT
;====================================================================
;sGPIO map
; | 3   | 2   | 1   |  0  |
; |-----|-----|-----|-----|
; | in  | LEDG| LEDR| AN0 |

;
#define  LED_R GP1         ; posizione LEDR in GPIO
#define  LED_G GP2         ;     "     LEDG  "  "

#define  LEDR sGPIO,LED_R  ; LED R tra pin e Vss
#define  LEDG sGPIO,LED_G  ; LED G tra pin e Vss
;#define GPIO,GP0          ; AN0
;#define GPIO,GP3          ; MCLR

In RAM sono riservate anche due locazioni per i contatori richiesti dalla routine di temporizzazione.

;####################################################################
;====================================================================
;= MEMORIA RAM =
;====================================================================
; RAM senza banchi

 #ifdef __10F222
;Zona di 24 bytes
;----------------

   CBLOCK 0x09            ; area RAM da 0x08 a 0x1F
  sGPIO                   ; shadow I/O
  d1                      ; contatori per Delay
  d2
   ENDC
 #else                    ; 10F220 - meno RAM
;Zona di 16 bytes
;----------------

   CBLOCK 0x10            ; area RAM da 0x10 a 0x1F
  sGPIO                   ; shadow I/O
  d1                      ; contatori per Delay
  d2
   ENDC
 #endif

Per semplificare l' uso della shadow ed evitare il ripetere di identiche istruzioni che renderebbero pesante la lettura del listato, può essere utile una piccola macro per trasferire la shadow nel registro di I/O.

; local MACRO
; Copy shadow into GPIO

EXEC  MACRO
   movf  sGPIO, W      ; carica shadow in WREG
   movwf GPIO          ; copia nel GPIO
      
ENDM

Possiamo aggiungere alcune altre macro di comando dei LED; non sono indispensabili, ma sono utili per rendere più chiaro possibile il listato:

; accende led Verde
Verde_on  MACRO
   bsf   LEDG
          ENDM
; accende led Rosso
Rosso_on  MACRO
   bsf   LEDR
          ENDM
; spegne led Verde
Verde_of  MACRO
   bcf   LEDG
          ENDM
; spegne led Rosso
Rosso_of  MACRO
   bcf   LEDR
          ENDM
; toggle led Verde
Verde_tg  MACRO
   movlw  LED_G       ; b'00100' toggle green
   xorwf  sGPIO, f
          ENDM
; toggle led Rosso
Rosso_tg  MACRO
   movlw  LED_R       ; b'00010' toggle red
   xorwf  sGPIO, f
          
ENDM

Il lampeggio è effettuato cambiando stato al LED o ai LED interessati. Questo si ottiene con un toggle (inversione dello stato) del valore del bit corrispondente nel registro di I/O. I toggle sono effettuati con la funzione XOR; ricordiamo che XOR con 1 inverte il valore del bit.

Il programma vero e proprio inizia con la classica scrittura del valore di calibrazione dell' oscillatore interno. 
Da comprendere bene che per questi PIC il vettore di reset non punta a 00h, ma all' ultima locazione della Flash, dove il costruttore, in fase di test del chip, scrive il valore di calibrazione dell' oscillatore, sotto forma di un opcode: 
movlw   valore_calibrazione

Quindi la prima istruzione che il PIC esegue dopo il reset non è quella che si trova a 00h, ma questa movlw .
Al clock successivo, il wrap around del program counter porta il suo valore a puntare a 00h, ovvero all' area di istruzioni inserite dall' utente.
Dato che WREG è caricato con il valore adeguato per la calibrazione dell' oscillatore interno, la cosa più semplice è quella di trasferire questo valore al registro OSCCAL.

La linea  andlw 0xFE ha lo scopo di annullare l'eventuale uscita Fosc/4 dove questa è disponibile (se non viene utilizzata, come in questo caso).

;####################################################################
;====================================================================
;= RESET ENTRY =
;====================================================================
; Sicurezza per il valore di calibrazione

RCCAL ORG 0x1FF
     res 1

; Reset Vector
      ORG 0x00

; calibrazione oscillatore interno
    andlw  0xFE         ; clear bit0: no Fosc out
    movwf  OSCCAL

Questa azione non sarebbe indispensabile, dato che l' attività del micro in questa applicazione non necessita di alcuna precisione particolare nel tempo di ciclo, ma anche qui è buona norma non saltare istruzioni che in altre occasioni possono essere indispensabili. Seguire una procedura precisa è indispensabile per non ritrovarsi con problemi le cui cause a volte sono individuabili con difficoltà.

Il programma principale inizia con il setup dell' OPTION_REG e della direzione dei pin.
Da osservare che i Baseline necessitano delle istruzioni particolari OPTION e TRIS, cosa che è obsoleta per i PIC delle famiglie superiori.
Una semi-grafica aiuta a comprendere la funzione di vari bit ed assegnare il giusto valore. Qui l' uso del numero binario è molto più chiaro che non esprimendo il valore in esadecimale o decimale.

;####################################################################
;====================================================================
;=                          MAIN PROGRAM                            =
;====================================================================

MAIN:
; inizializzazioni I/O al reset

; OPTION default '11111111'

   movlw   b'11010111'
           ; 1------- GPWU disabilitato
           ; -1------ GPPU disabilitato
           ; --0----- clock interno
           ; ---1---- done
           ; ----0--- prescaler al timer
           ; -----111 1:256

   OPTION  ; al registro OPTION

; ADCON0 default '11001100'
   movlw   b'01000001' ; ADC abilitato, GP0 = AN0
           ; 0------- ANS1
           ; -1------ ANS0
           ; --00---- 0
           ; ----00-- CH 0
           ; ------0- GO/DONE
           ; -------1 ADC enabled

   movwf   ADCON0

; GPIO
   clrf    GPIO       ; preset GPIO latch a 0
   clrf    sGPIO      ; e anche la shadow
   movlw   b'1001'    ; GP1/2 = out
   tris    GPIO       

La valutazione del risultato della conversione AD è effettuato con una sottrazione rispetto ai valori fissati per le varie gamme.
Va osservato che occorre usare subwf  dato che i Baseline non hanno l'opcode  sublw.
skpc (skinext line on carry set) è una delle pseudo istruzioni supportate dall' Assembler MPASM e che è di lettura più immediata dell' equivalente btfss STATUS, C.

   Verde_of           ; LED off
   Rosso_of      
   EXEC               ; esegue in GPIO     

ml call   ReadAD      ; read ADC

;range evaluation 
   movlw  k1          ; < k1?
   subwf  ADRES, w
   skpc
   goto   sel1
n1 movlw  k2          ; < k2?
   subwf  ADRES, w
   skpc
   goto   sel2
n2 movlw  k3          ; < k3?
   subwf  ADRES, w
   skpc
   goto   sel3
n3 movlw  k4          ; < k4?
   subwf  ADRES, w
   skpc
   goto   sel4
n4 goto   sel5        ; > k4?         

; LED driving
 
sel1: 
   Verde_on          ; T<40°C verde fisso
   Rosso_of
   goto   selxec
sel2:                ; 40<T<50°C lampeggio verde/giallo
   Verde_on          ; verde fisso +
   Rosso_tg          ; toggle rosso
   goto   selxec
sel3:                ; 50<T<60°C giallo fisso
   Verde_on          ; verde + rosso
   Rosso_on
   goto   selxec
sel4:                ; 60<T<70°C lampeggio giallo/rosso
   Rosso_on          ; rosso fisso +
   Verde_tg          ; toggle verde
   goto   selxec
sel5:                ; T>70°C rosso fisso
   Verde_of 
   Rosso_on

selxec EXEC          ; drive LED

   call   Delay025s  ; 250ms delay

   goto   ml         
; loop

Può essere interessante notare come la colorazione del testo, facilmente realizzata da un editor per programmazione, consente una immediata valutazione delle componenti di ogni riga.
Ad esempio, osserviamo come l' impostazione della colorazione (default tipico per i listati PIC) distingua in blu gli opcode, in verde il commento e in nero label e macro.

Aggiungiamo ora un paio di subroutines, una relativa alla conversione AD e l' altra alla generazione del ritardo voluto.

Sempre extra semplice è la gestione del modulo ADC: non occorre tempo di acquisizione tra una lettura AD e la successiva dato che esse sono già ampiamente cadenzate dalla routine di ritardo.
Il ritardo è del solito tipo waste time, dato che i Baseline non hanno interrupt; la struttura è derivata dal sito di Golovchenko e potrà essere variata a volontà per ottenere un lampeggio a frequenza diversa.
Ovviamente si potrà anche usare il Timer0, che in questa applicazione non alcuna altra funzione.

L' indispensabile END termina la compilazione.

;********************************************************************
;====================================================================
;=                            SUBROUTINES                           =
;====================================================================
;********************************************************************
; Read ADC

ReadAD bsf    ADCON0, 1 ; avvia conversione
lpAD   nop
       btfsc  ADCON0, 1 ; wait per fine conversione
       goto   lpAD 
       retlw  0

; Delay = 0.25 seconds
; Clock frequency = 4 MHz
; 0.25 seconds = 250000 cycles

Delay025s:             ;249993 cycles
      movlw   0x4E
      movwf   d1
      movlw   0xC4
      movwf   d2
Delay025s_0:
      decfsz  d1, f
      goto    $+2
      decfsz  d2, f
      goto    Delay025s_0
      goto    $+1     ;3 cycles
      nop
      retlw   0       ;4 cycles (including call)

; ===================================================================
; =                             THE END                             =
;===================================================================

  
END

Da notare che il ritorno dalla subroutine richiede retlw, dato che return non c'è nel set di istruzione dei Baseline. Si potrebbe pensare di introdurre un equate :

RETURN = RETLW

per mantenere uniformità di scrittura con altri PIC, ma questo è del tutto inutile: possiamo anche scrivere direttamente return, dato che MPASM esegue ugualmente la compilazione senza errori, operando la sostituzione automatica col giusto opcode (e segnalando l'operazione con un warning). 
Comunque il consiglio è quello di utilizzare il set di istruzioni del chip che si sta impiegando; questo consente di avere una maggiore coscienza di cosa si sta facendo in relazione all' hardware.

Quanto all' accensione dei LED, si potrebbe pensare a gestirli con due PWM in modo da avere un passaggio del colore verde-giallo-rosso uniforme, ma si è visto che nella pratica il passaggio con il lampeggio è molto più efficace per l' operatore che identifica immediatamente con questo un momento di transizione da una certa situazione ad un'altra.
Invece, volendo, un pwm potrà essere applicato allo stato on dei LED, aggiungendo un altro loop di temporizzazione a frequenza maggiore di 100 Hz, allo scopo di ridurre i consumo, dove necessario, dato che i LED bicolori solitamente necessitano di più di 10mA per avere una luminosità soddisfacente.

Ovviamente una struttura del genere può essere usata anche per comandare piccoli relais, opto isolatori o cicalini, creando uscite di allarme o attenzione in relazione al valore misurato. In questo caso è necessario aggiungere una isteresi sufficiente a scongiurare il saltellare dei contatti per variazioni minime attorno ai valori di soglia.


La realizzazione

Data l' estrema semplicità del circuito, la realizzazione può essere a piacere o secondo la necessità dell' applicazione.
Qui un paio di esempi di circuiti stampati (scala 2:1 circa):

La versione SMD è ovviamente la più piccola, ma non di molto, dovendo utilizzare un circuito stampato a singola faccia. 

Però sono usati componenti passivi SMD anche per la versione con il chip in package DIP8 per avere una  piccola superficie del circuito stampa. Il regolatore a tre terminali è comunque in TO92. 

Nella versione in foto, lo zoccolo del chip è sostituito con pin singoli (non sono inseriti quelli relativi ai pin non internamente connessi al chip è nella versione DIP8).

Un connettore a pettine passo 2.54 permette di collegare la schedina con cavi i direttamente su un altro circuito stampato.

Dato il bassissimo numero di componenti necessari, si potrà realizzare il circuito in mille altri modi, anche su una millefori.



Variazioni sul tema

Vediamo una possibile variazione: indicare lo stato di una tensione, ad esempi quella di una batteria da 12V.

Facciamo pervenire all' ingresso analogico la tensione da valutare, attraverso un partitore:

R3 e R4 sono il partitore di ingresso. In questo caso potrebbe avere un valore di 1:4, rendendo possibili tensioni di ingresso fino a 20V.
In questo modo abbiamo Vin = 20V -> Vgp0 = 5V.

Potrebbero essere rispettivamente 6k2 e 2k2 ohm o 11k e 3k9 o altre combinazioni in rapporto 1:4. 

Se è il circuito è collegato alla batteria di un veicolo, si potrà mettere un diodo zener (5V6-1/4W) in parallelo a C1 per evitare che la tensione in ingresso raggiunga un limite pericoloso per microcontroller. Se non si prevede che la tensione in ingresso superi i 20V, lo zener può essere omesso.

Ovviamente il partitore potrà essere adeguato alla tensione che si vuole misurare e la stessa struttura adattata ad altri range di tensione in ingresso.

Stabiliamo le seguenti condizioni del LED:

Tensione LED
Vin < 10.5V Rosso lampeggiante
10.5 < Vin < 11.5V Rosso
11.5 < Vin < 12V Giallo
12 < Vin < 14.5V Verde
14.5V < Vin Rosso/verde lampeggiante

Anche qui i valori indicati sono del tutto adattabili alle gamme che si vogliono valutare. Basta cambiare di conseguenza i valori delle costanti relative. 

Assegniamo allora i valori limite delle varie modalità di funzionamento del LED:

;********************************************************************
;*                   ASSEGNAZIONI LOCALI                            *
;********************************************************************
; Partitore 1:4
;               Vin     ADCdec   ADChex 

k1 equ .134  ; 10.5V ->  134   -> 86h
k2 equ .146  ; 11.5V ->  146   -> 92h
k3 equ .153  ; 12V   ->  153   -> 99h
k4 equ .184  ; 14,5  ->  184   -> B8h

Modifichiamo l' analisi del risultato della conversione per adeguarla alle nuove condizioni.

; LED driving 
sel1: 
   Verde_of          ; Vin < 10.5V Rosso  
   Rosso_tg          ; rosso lampeggiante
   goto   selxec
sel2:                ; 10.5 < Vin < 11.5V 
   Verde_of          ; rosso fisso
   Rosso_on          
   goto   selxec
sel3:                ; 11.5 < Vin < 12V 
   Verde_on          ; giallo fisso
   Rosso_on
   goto   selxec
sel4:                ; 12 < Vin < 14.5V 
   Rosso_of          ; verde fisso
   Verde_on          
   goto   selxec
sel5:                ; Vin > 14.5  rosso/verde lampeggiante
   btfss  sGPIO,GP1  ; se GP1 e 2 sono uguali, differenziali
    goto  a1         ; per usare il ciclo come cadenza per il
   btfss  sGPIO,GP2  ; lampeggio
    goto  lamp
   goto   adj 
a1 btfsc  sGPIO, GP2
    goto  lamp   
adj:                 ; GP1=GP2 - differenzia
   Rosso_on
   Verde_of          
lamp:
   Verde_tg          ; rosso/verde lampeggiante
   Rosso_tg

selxec EXEC          ; drive LED

   call   Delay025s  ; 250ms delay 

   goto   ml         ; close loop

Una leggera complicazione è inserita per ottenere il lampeggio verde/rosso. 

Il problema che si può generare è il seguente: in mancanza di interrupt, per poter sfruttare il ciclo come cadenza del lampeggio con il sistema del toggle, occorre che i due bit di comando dei LED siano differenti in quanto è necessario che la prima entrata nella selezione
 sel5 abbia valori diversi per i due bit che comandano il LED rosso e quello Verde.
Se si passa da sel4  a sel5 , ovvero con una tensione crescente, non c'è problema. In sel4  i due bit di comando dei LED hanno valore diverso, quindi il loro toggle produce un lampeggio alternato.
Un flow chart rende evidente la cosa.

Se si passa direttamente da sel3 a sel5 per un aumento rapido di tensione (il ciclo di acquisizione è molto "lento"), si arriva con i due bit dello steso valore, il cui toggle porterebbe ad un lampeggio del colore giallo e non all' alternanza rosso/verde voluta.

Occorre quindi che all' ingresso della fasesel5  i due bit siano di valore diverso. Se così non fosse, il ciclo dei toggle non permetterebbe il lampeggio rosso/verde.

Non ha alcuna importanza come siano settati la prima volta, perchè i passaggi successivi del ciclo ne invertono lo stato e questo garantisce il lampeggio.

Certamente si possono utilizzare altri percorsi logici per generare il lampeggio, ma quella usata è la più banale e semplice in assoluto.

Ovviamente, se si preferisce una diversa reazione del LED, basta variare le operazioni effettuate ad ogni selezione.

Anche qui si può pensare al collegamento di relais che si inseriscono/disinseriscono a seconda della tensione (sempre ricordando di inserire una minima isteresi nei punti di commutazione). 

Una ulteriore variazione potrebbe essere quella di utilizzare il GP3 come ingresso digitale e selezionare con il valore di tensione applicato due diverse configurazioni del set di intervento e/o del funzionamento dei LED, potendo così usare uno steso chip per due diverse applicazioni.

Come si vede, una semplicissima programmazione in Assembly su un PIC tra i più piccoli disponibili (non solo per le dimensioni, ma anche come risorse) permette risultati sensibili.

Il programma potrà servire come base per realizzare ogni genere di indicatori. Si potranno associare diverse condizioni di accensione dei LED e diverse soglie di intervento, con uscite diverse dal LED bicolore usato.


Documentazione



Passare il sorgente ad un altro PIC.

Possiamo passare il sorgente ad altri PIC?

Certamente sì: vediamo qualche esempio.


 

 

Copyright © afg. Tutti i diritti riservati.
Aggiornato il 22/04/20.