VISUALIZZA IL NUMERO 5 SU DUE 7SEGMENT DISPLAY

Costruire un programma che visualizzi sulla Development Board EasyPic4 con micro PIC16F887 il numero 54 sui primi 2 display a 7 segmenti (DIS0 e DIS1).

Soluzione:

Nella Development Board EasyPic4 la porta A viene utilizzata per selezionare quale display a 7 segmenti attivare. Ad esempio:
- se pongo a 1 il primo bit (RA0) della porta A (
PORTA=0b00000001) verrà utilizzato il primo display a destra, 
- se pongo a 1 il secondo bit (RA1) della porta A (
PORTA=0b00000010) verrà utilizzato il secondo display  e cosi via ...
I segmenti del display sono collegati alla porta D secondo lo schema sottostante.

Essendo tutti i 4 display collegati alla stessa porta D segue che appena imposto la seconda cifra (il 5 nel nostro problema) la precedente (il 4) viene sovrascritta e perduta. Come posso ovviare ? Potrei sfruttare i fenomeni di persistenza dell'immagine sulla retina e il transitorio di spegnimento dei led del display a 7 segmenti! Un programma che esegue un loop che non fa altro che accendere in sequenza ciascun display con una frequenza molto elevata potrebbe creare i presupposti necessari affinché all'occhio sembri che tutti i display siano sempre accesi (in realtà lo sono solo per un istante molto breve) uno alla volta. Un tempo di attesa adeguato  tra l'attivazione di un display e il successivo (capace quindi di sfruttare i fenomeni di persistenza dell'immagine sulla retina e il transitorio di spegnimento dei led sui display) è un millisecondo.

Questa tecnica si chiama Multiplexing. Tale tecnica è concettualmente molto semplice e si basa sul fenomeno della persistenza della visione: si accende un unico display per volta, ad intervalli di tempo talmente brevi da non poter essere percepiti dall’occhio umano: accendiamo prima un display, lo lasciamo acceso per pochi millisecondi, lo spegniamo e accendiamo il successivo e così via.

Se carichiamo sul PIC questo programma vedremo infatti apparire il numero 54 senza alcun sfarfallio.

/* --------------------------------------------------------------
 * Nome progetto:
     7Seg2_Static (Mostra 54 sul display a 7Segmenti)
 * Configurazione:
     MCU:             P16F887A
     Dev.Board:       EasyPIC4
     Oscillator:      HS, 08.0000 MHz
     SW:              mikroC v7.0
-------------------------------------------------------------- */
// array con la codifica per i DISPLAY a 7 segmenti
// --------------------------------------------------------------
//
//  Valore in  Segmenti  deci-     Valore in   Segmenti  deci-
//  display    .GFEDCBA  male      display     .GFEDCBA  male
//   ----------------------------    ----------------------------
//      0        00111111   63         5         01101101  109
//      1        00000110    6         6         01111101  125 
//      2        01011011   91         7         00000111    7
//      3        01001111   79         8         01111111  127
//      4        01100110  102         9         01101111  111
//
// --------------------------------------------------------------
void main()
{
    PORTA = 0; // disattivo tutti i display
    TRISA = 0; // tutti i bit della porta A sono di output
    PORTD = 0; // spengo tutti i segmenti del display
    TRISD = 0; // tutti i bit della porta D sono di output
    while (1)
    {
       PORTA = 0b00000001;   // accendo il 1° display a destra
       PORTD = 0x66;         // mando la mask per il 4 sulla PORTAD
       Delay_ms(1);          // attesa di un millisecondo

       PORTA   = 0b00000010; // accendo il 2° display a destra
       PORTD   = 0x6D;       // mando la mask per il 5 sulla PORTAD
       Delay_ms(1);          // attesa di un millisecondo
    }
}

Questa soluzione non è proponibile quando il valore visualizzato è frutto di una lunga elaborazione. Infatti l'attesa tra l'ottenimento del risultato e la sua visualizzazione, in un loop infinito, potrebbe comportare un tempo superiore al transitorio di spegnimento dei led sul display a 7 segmenti con conseguente sfarfallio delle cifre.

La soluzione alternativa, che supera questo inconveniente, è quella che sfrutta gli interrupt.

GESTIONE INTERRUPT:  Prima di vedere la soluzione con gli interrupt vediamo come questi vengono gestiti nel PIC16F887.

Il PIC16F887 ha 3 timer/contatori completamente indipendenti identificati con le sigle TMR0, TMR1 and TMR2. La figura sottostante illustra il ruolo dei bit di configurazione che controllano i timer. Questi bit sono contenuti nel registro OPTION_REG.

Il TMR0 è un semplice contatore ad 8 bit. Il suo conteggio viene incrementato automaticamente di 1 (essendo ad 8 bit va da 0 a 255) ad ogni ciclo di istruzioni. Il ciclo di istruzioni in un PICMicro è pari alla frequenza di clock divisa per 4: ciò equivale a dire che una singola istruzione assembler viene eseguita in 4 cicli di clock. Indicando con Fosc la frequenza di clock (la frequenza del quarzo o dell’oscillatore in genere), la frequenza di un ciclo di istruzioni è quindi pari a Fosc/4.

Quindi il TMR0 si incrementa di 1 ogni 4 colpi di clock, ovvero con una frequenza di Fosc/4. Se stiamo utilizzando un quarzo da 20Mhz, la frequenza di esecuzione delle istruzioni è pari a 20/4 = 5MHz. Poichè la frequenza è l’inverso del tempo (periodo) segue che ogni istruzione verrà eseguita nel tempo di 1/5 = 0,2 μS (microsecondi).

Quando il TMR0 va in overflow (cioè passa dal valore 255 al valore zero), è possibile fargli generare l'Interrupt su overflow del TMR0 (indicato con TMR0IF) che possiamo intercettare e sfruttare per attivare o disattivare determinate funzioni. Un interrupt è una sorta di “campanello” che ci permette di fermare momentaneamente l’esecuzione del programma principale per eseguire altre funzioni.

Utilizzando un quarzo da 20Mhz, abbiamo che il TMR0 va in overflow dopo 256*0,2μS = 51,2μS (ho utilizzato il valore 256 e non 255 perché devo conteggiare anche lo zero). Tale tempo, per la stragrande maggioranza delle applicazioni, è troppo basso. Generalmente abbiamo bisogno di tempi più “palpabili” per poter lavorare in tranquillità, o per ottenere temporizzazioni ben definite. Per tale motivo i PICMicro hanno a bordo un’utile dispositivo chiamato Prescaler.

Il Prescaler altro non è che un divisore di frequenza: ci permette di dividere la frequenza (la velocità) del nostro ciclo di istruzioni (Fosc/4) in valori più piccoli, facendoci ottenere tempi di esecuzione più alti e quindi più facilmente gestibili o in ogni caso impostabili sui valori che desideriamo. Ovviamente il prescaler non influisce sulla velocità di esecuzione delle istruzioni: le istruzioni continueranno ad essere eseguite ad una velocità di Fosc/4. Esso influisce unicamente sull’incremento del TMR0.
Il prescaler può essere assegnato o al Timer0 o al Watchdog Timer.

Supponiamo di voler generare l'interrupt di overflow dopo un tempo ben preciso. Ad esempio un interrupt ogni millisecondo, ovvero ogni 1000μS. In questi casi si ricorre ad un trucchetto estremamente semplice: basta non far partire il TMR0 dal valore 0 ma da un altro valore che indicheremo con la sigla PreloadTMR0. Vediamo come calcolare il valore di partenza di TMR0 più adeguato ai nostri scopi:

La formula che fornisce il tempo trascorso in N° cicli istruzione è il seguente

dove:

Fosc = Frequenza del quarzo
PS=Valore del prescaler (uno dei valori: 2, 4, 8, 16, 32, 64, 128, 256)
(4*PS/FOSC) = tempo necessario affinché il TMR0 si incrementi di un'unità

Supponiamo che il timer si incrementi di una unità ogni 6,4 μS (4*PS/FOSC) ciò significa che un tempo di 1000 μS lo raggiunge dopo:

1000/6,4 = 156,25 cicli

Teniamo però conto del valore intero: 156 (i cicli sono numeri naturali per cui non possiamo usare il decimale!). Quindi se dopo 156 cicli otteniamo un intervallo di un millisecondo ci basta far partire il TMR0 da 100 = 256-156 per ottenere un interrupt dopo 1 mS. Una volta generato l’interrupt reimposteremo di nuovo il TMR0 a 100 e così ad ogni interrupt. Chiaramente, avendo tralasciato dei decimali, il tempo non sarà esattamente di 1000 μS.

Il tempo reale è desumibile dalla formula:

dove PreloadTMR0 è il valore iniziale da dare al TMR0 (valore intero: privo dei decimali!). Il preloadTMR0, dopo alcune semplificazioni, può essere così determinato:


dove:

Td = tempo desiderato

 

SISTEMA INTERRUPT DEL PIC 16F887

Analizziamo ora i registri associati alla gestione degli interrupt. Speciali bit abilitano o disabilitano un determinato interrupt. Tali bit sono riconoscibili poichè il loro nome termina per IE (Interrupt enable). Per ogni bit abbiamo anche un bit che indica se quel particolare interrupt si è verificato o meno. Il loro nome termina con la sigla IF (interrupt flag).

Tutto si basa su un semplice ed efficiente principio: quando una richiesta di interrupt arriva il bit IF viene posto a 1. Se il bit IE associato è a zero l'interrupt verrà completamente ignorato altrimenti no. Se ci sono più interrupt abilitati è necessario che la routine di interrupt determini quale siano da considerarsi attivi analizzando i bit flag IF. I bit flag non vengono automaticamente azzerati ma dovranno essere resettati mediante la routine di interrupt. Se non resettiamo un interrupt questo si ripeterà immediatamente quando ritorniamo al main anche se non ci sono ulteriori richieste in sospeso.

Tutti i riferimenti relativi agli interrupt tipici del PIC16F887 sono qui sotto mostrati.
Per abilitare un interrupt quando la port B cambia di stato è necessario abilitare il singolo bit separatamente mediante il registro IOCB che funge da IE bit.
 


Vediamo ora in dettaglio i registri coinvolti:

RBPU - abilita le resistenze di Pull-up per la porta B
Abilita (0) oppure disabilita (1) le resistenze di pull-up sulla porta B. Le resistenze di pull-up servono a fare in modo che un pin configurato come ingresso non rimanga “appeso” ovvero non rimanga senza segnali applicati ad esso (condizione che può portare a malfunzionamenti). Generalmente sui pin configurati come ingresso andremo sempre ad inserire una resistenza di pull-up che mantiene il pin a valore logico alto (up) {vedi note in fondo}. Le porte B dei PIC hanno questa caratteristica: possiamo quindi evitare di mettere tali resistenze all’esterno del PIC.



INTEDG - è il bit che definisce il fronte di riferimento (di salita/di discesa) per l'interrupt  sul pin RB0/INT.
E' possibile attivare un interrupt esterno sul pin 0 della porta B RB0/INT (bit INTE  sul registro INTCON). Se questo bit è posto a 1 l’interrupt sul pin 0 della porta B avviene sul fronte di salita del segnale altrimenti su quello di discesa. Quindi se poniamo questo flag:
- sul valore 1: avremo che l’interrupt sarà generato sul fronte di salita del segnale applicato ad RB0/INT,
- sul valore a zero: l’interrupt scatterà sul fronte di discesa del segnale.
Tale impostazione non c’entra assolutamente nulla col Timer0, ma fa comunque parte del registro delle opzioni.



T0CS - è il bit che definisce il clock di riferimento per il TMR0
Possiamo fare in modo che l’incremento del TMR0 sia legato ad una sorgente di clock esterna (questo può essere utile quando dobbiamo ad esempio sviluppare un’applicazione di precisione e ottenere quindi un tempo estremamente preciso). Se vogliamo che il TMR0 si incrementi tramite una sorgente esterna di clock, dobbiamo impostare il bit T0CS ad 1 (in questo caso il clock andrà applicato al pin contrassegnato sul PICMicro con la sigla T0CKI), se invece vogliamo che il TMR0 si incrementi tramite la circuiteria interna del PIC (e quindi tramite il quarzo), allora imposteremo tale bit a zero.
- se vale 0 l'impulso nel PIC16F887 arriva tramite il pin RA4 (T0CKI).
- se vale 1 il TMR0 utilizza il ciclo di clock interno (Fosc/4).

T0SE - è il bit che definisce il fronte di riferimento (di salita/di discesa) per il TMR0.
Il bit T0SE stabilisce come deve avvenire l’incremento del Timer0 ma vale solo nel caso si sfrutti una sorgente esterna.
- se vale 0  l’incremento si avrà nel momento in cui il segnale effettua il passaggio da stato logico basso a stato logico alto.
- se vale 1  l’incremento si avrà nel momento in cui il segnale effettua il passaggio da stato logico alto a stato logico basso.

PSA - Bit di assegnamento del Prescaler
- con 1 il prescaler è assegnato al  WDT.
- con 0 il prescaler viene assegnato al TMR0.

PS2, PS1, PS0 - bit divisore di frequenza
I bit PS0 PS1 e PS2 servono per impostare il valore di divisione della frequenza (il valore del prescaler) come mostrato nella tabella sottostante. Impostando ad esempio questi 3 bit sul valore 101 otterremo un valore di divisione della frequenza del ciclo istruzioni pari a 64. In questa tabella vi sono due colonne: quella sinistra è relativa al valore di divisione che si ottiene quando assegniamo il prescaler al TMR0 mentre quella destra rappresenta il valore di divisione che si ottiene se invece il prescaler è assegnato al Watchdog timer.

PS2 PS1 PS0 TMR0 WDT

0

0

0

1:2

1:1

0

0

1

1:4

1:2

0

1

0

1:8

1:4

0

1

1

1:16

1:8

1

0

0

1:32

1:16

1

0

1

1:64

1:32

1

1

0

1:128

1:64

1

1

1

1:256

1:128

I valori su cui possiamo impostare il prescaler (ovvero il divisore) sono : 2, 4, 8, 16, 32, 64, 128, 256. Come si vede il valore 1 non è presente: in questo caso basta semplicemente non assegnare il prescaler al TMR0.

Il registro INTCON contiene i bit di abilitazione e segnalazione dei vari interrupt gestiti dal PIC.

Gli interrupt sui  PIC16 hanno una sorta di interruttore generale: il bit GIE (Global Interrupt Enable) che consente di mascherare tutte le sorgenti di interrupt, ovvero di non far richiamare l’ISR (Interrupt Service Routine) anche se i bit di abilitazione sono settati. Vi è inoltre un bit di abilitazione per gli interrupt di periferica: PIE (Peripheral Interrupt Enable) che serve per mascherare tutti gli interrupt i cui flag di abilitazione si trovano nei registri PIE.

GIEGlobal Interrupt Enable bit:
Questo bit abilita (valore 1) tutti gli interrupt abilitati nei bit PEIE, T0IE, INTE e RBIE (bit 3 ... 6). Con 0 disabilita tutti gli interrupt

PEIEPeripheral Interrupt Enable bit:
Funziona come GIE ma controlla solo gli interrupt originati dalle periferiche (che vanno attivate tramite il registro PIE1). Questo significa che:
- non ha alcuna influenza su TMR0
-
neppure sul cambiamento di stato della PORTB
-
neanche su RB0/INT1.
Con 1 abilita tutti gli interrupt abilitati in PIE1 e PIE2 ad esclusione dei 3 citati. Vediamo di riassumere la struttura del registro correlato PIE1:

ADIE Abilito (1)/ disabilito (0) l'interrupt del modulo ADC
RCIE Abilito (1)/ disabilito (0) l'interrupt di ricezione del modulo EUSART (Enhanced Universal Synchronous Asynchronous Receiver Transmitter - E' nota anche come Serial Communications Interface ).
TXIE Abilito (1)/ disabilito (0) l'interrupt di trasmissione del modulo EUSART
SSPIE Abilito (1)/ disabilito (0) l'interrupt emesso quando viene completato un trasferimento dati, effettuato in modo sincrono, tramite il modulo di comunicazione seriale MSSP. MSSP (Master Synchronous Serial Port) è il modulo periferico dedicato alle comunicazioni seriali di tipo sincrono, ovvero costituite da una linea dati e da una linea di clock.
CCP1IE Abilito (1)/ disabilito (0) l'interrupt generato dal modulo CCP1 utilizzato nel segnale PWM. Il modulo CCP di un picmicro è in grado di generare un treno continuo di impulsi a modulazione di ampiezza del quale, in ogni momento, possiamo cambiare il duty cicle. Dal modulo CCP potra' essere prelevato il segnale pwm. (vedere questo link)
TMR2IE Abilito (1)/ disabilito (0) l'interrupt emesso quando i registri PR2 e TMR2 hanno lo stesso valore (vedere questo link)
TMR1IE Abilito (1)/ disabilito (0) l'interrupt di overflow di TMR1

T0IETMR0 Overflow Interrupt Enable bit
Abilita l’interrupt sull’overflow di TMR0. Con 1 abilita l’interrupt su TMR0 mentre con 0 lo disabilita.

INTERB0/INT External Interrupt Enable bit
Attiva l’interrupt sul cambiamento di stato del pin RB0/INT (interrupt esterno).  Con 1 abilita l’interrupt esterno su RB0/INT altrimenti lo disabilita

RBIERB Port Change Interrupt Enable bit.
Attiva l’interrupt sul cambiamento di stato della portB, sia da alto a basso che viceversa. Con 1 abilita.

T0IFTMR0 Overflow Interrupt Flag bit
Registro l’overflow su TMRO. Se contiene il valore 1 il registro TMR0 è andato in overflow (il bit deve essere azzerato via software) altrimenti no.

INTFRB0/INT External Interrupt Flag bit
Segnala il cambiamento di stato sul pin RB0/INT pin.Se vale 1 l’interrupt esterno su RB0/INT è avvenuto (il bit deve essere azzerato via software) altrimenti no

RBIF RB Port Change Interrupt Flag bit
Registra il cambiamento di stato della portB. Se vale 1 almeno uno dei pin della portB ha cambiato stato (il bit deve essere azzerato via software).

Ritorniamo al nostro problema: scrivere 54 sugli ultimi due display a 7 segmenti. Utilizzando l'interrupt di overflow sul TMR0 possiamo richiamare ad istanti regolari la funzione che effettua il refresh delle cifre sui 2 display. Analizziamo quindi la soluzione con gli interrupt:

/* --------------------------------------------------------------
 * Nome progetto:
     7Seg2_Static (Mostra 54 sul display a 7Segmenti)
 * Configurazione:
     MCU:             P16F887A
     Dev.Board:       EasyPIC4
     Oscillator:      HS, 08.0000 MHz
     SW:              mikroC v7.0
-------------------------------------------------------------- */
// array con la codifica per i DISPLAY a 7 segmenti
// --------------------------------------------------------------
//
//  Valore in  Segmenti  deci-     Valore in   Segmenti  deci-
//  display    .GFEDCBA  male      display     .GFEDCBA  male
//   ----------------------------    ----------------------------
//      0        00111111   63         5         01101101  109
//      1        00000110    6         6         01111101  125 
//      2        01011011   91         7         00000111    7
//      3        01001111   79         8         01111111  127
//      4        01100110  102         9         01101111  111
//
// --------------------------------------------------------------

unsigned short displayattivo;
void interrupt()
{
    if (displayattivo==1)
    {
       PORTD = 0x66;        // imposto la codifica del 4 sulla PORTB
       PORTA = 0b00000001;  // accendo il 1° display e spengo il 2°
       displayattivo = 2;   // imposto il prossimo display da usare  
    }
    else
    {
       PORTD = 0x6D;        // imposto la codifica del 5 sulla PORTB
       PORTA = 0b00000010;  // accendo il 2° display e spengo il 1°
       displayattivo = 1;   // imposto il prossimo display da usare  
    }
    TMR0 = 0;              //  resetto il timer TMR0
    // CONFIGURAZIONE REGISTRO INTCON (Interrupt Config)
    // bit 7 -> GIE,    Gestione Interrupt (1 -> attiva)
    // bit 6 -> PEIE,   Gestione Interrupt di periferica (0 -> disattivato)
    // bit 5 -> TMR0IE, Gestione Interrupt di overflow sul Timer0 (1 -> attivo)
    // bit 4 -> INTE,   Gestione Interrupt su porta RB0/INT (0 -> disattivato)
    // bit 3 -> RBIE,   Gestione Interrupt su porte B (0 -> disattivato)
    // bit 2 -> T0IF -  Flag interrupt su Timer0 (0 -> reset)
    // bit 1 -> INTF -  Flag interrupt su RB0/INT (0 -> reset)
    // bit 0 -> RBIF -  Flag interrupt su porte B (0 -> reset)
    INTCON = 0b00100000; // 0x20; - azzero T0IF e setto TMR0IE
}

void main()
{
    // Impostazione del registro OPTION (pag.55 del datasheet)
    // bit 7 -> Gestione Resistenze di pull-up su porta B (1 -> disattivate)
    // bit 6 -> Non importa
    // bit 5 -> Clock per Timer0 derivato da ciclo di clock interno
    // bit 4 -> Non importa
    // bit 3 -> Prescaler assegnato al Timer0
    // bit 2 -> Prescaler Rate Select bit 0 (1:32)
    // bit 1 -> Prescaler Rate Select bit 0
    // bit 0 -> Prescaler Rate Select bit 0
    OPTION_REG = 0b10000000;  // 0x80 - disabilito le resistenze di pull-up sulla porta B
    PORTA = 0;                // disattivo tutti i display
    TRISA = 0;                // tutti i bit della porta A sono di output
    PORTD = 0;                // spengo tutti i segmenti del display
    TRISD = 0;                // tutti i bit della porta D sono di output
    TMR0 = 0;                 // azzero il timer TMRO
    // CONFIGURAZIONE REGISTRO INTCON (Interrupt Config)
    // bit 7 -> GIE,    Gestione Interrupt (1 -> attiva)
    // bit 6 -> PEIE,   Gestione Interrupt di periferica (0 -> disattivato)
    // bit 5 -> TMR0IE, Gestione Interrupt di overflow sul Timer0 (1 -> attivo)
    // bit 4 -> INTE,   Gestione Interrupt su porta RB0/INT (0 -> disattivato)
    // bit 3 -> RBIE,   Gestione Interrupt su porte B (0 -> disattivato)
    // bit 2 -> T0IF -  Flag interrupt su Timer0 (0 -> reset)
    // bit 1 -> INTF -  Flag interrupt su RB0/INT (0 -> reset)
    // bit 0 -> RBIF -  Flag interrupt su porte B (0 -> reset)
    INTCON=0b10100000;    // 0xA0
    displayattivo = 1;
    // resto in attesa dell'interrupt
}

Nota per me: verificare che funzioni se al posto di OPTION_REG=0x80  metto 0x00 e TRISB=0 (output) - non ho capito perchè devo disabilitare le resistenze di pull-up


Poichè la frequenza di esecuzione che è stata impostata per l'esecuzione del programma qui sopra è di 8Mhz segue che la frequenza di esecuzione delle istruzioni assembler (e quindi di incremento del TMR0) è Fosc/4=8Mhz/4 = 2Mhz. Essendo la frequenza l'inverso della durata basta calcolare 1/2Mhz = 0,5 μS per ottenere il tempo di esecuzione di un'istruzione assembler. Il TMR0 va in overflow ogni 256 cicli di istruzione per cui si verifica un interrupt ogni 256*0,5μS = 128μS. Il prescaler è 1:2 per cui il tempo si raddoppia: 256μS. La funzione Interrupt() oltre a gestire il refresh dei display dovrà:
- azzerare il valore del TMR0
- azzerare il flag che registra l'avvenuto overflow (TMR0IF o T0IF)
- riattivare l'interrupt di overflow ponendo a 1 il bit TMR0IE (o T0IE).

All'avvio il programma dovrà agire sul registro INTCON  per avviare il timer0 ed esattamente:
- attivare tutti gli interrupt ponendo a 1 il bit GIE
- attivare l'interrupt di overflow su TMR0 ponendo a 1 il bit TMR0IE (o T0IE).

Resistenze di pull up

Gli ingressi del PIC sono ad alta impedenza ovvero richiedono (assorbono) una corrente minima per cambiarne lo stato.
Questo presenta un inconveniente: essendo così sensibili gli ingressi lasciati liberi (non collegati) presentano valori casuali causati dai rumori di fondo e non un valore LOW come potremmo erroneamente pensare. Per questa ragione dobbiamo far si che il nostro pin sia sempre connesso o a 5V o a 0V. Nello schema sottostante con il pulsante premuto avremo un valore HIGH sul pin di ingresso, mentre con circuito aperto avremo valori in ingresso oscillanti.
 


Per questa ragione dobbiamo far si che il nostro pin sia sempre connesso o a 5V o a 0V. Potremmo ovviare il problema connettendo il circuito aperto a terra. Ma in questo caso il problema nasce quando chiudiamo il circuito che causa un bel cortocircuito con conseguente danneggiamento del nostro PIC.
 

Per fare questo possiamo utilizzare il successivo schema. Abbiamo introdotto una resistenza da 10K chiamata resistenza di pull up.
Fintatochè il pulsante non è premuto il pin rimane stato HIGH; la corrente che fluisce è bassa per via della resistenza, ma data l'alta impedenza degli ingressi è sufficiente a mantenere alto lo stato. Quando premiamo il pulsante la corrente fluisce verso massa e la tensione prossima a 0V porta il pin in stato LOW. In questo caso non abbiamo corto circuito poichè la resistenza limita la corrente ( I = V/R=5V/10.000ohm= 5mA). L'obiettivo raggiunto dalla resistenza di pull up è quello di togliere le fluttuazioni al pin di input; Il compito della resistenza di pull up è anche quello ridurre la corrente che attraversa il circuito. Utilizzando una resistenza di pull up avremmo uno stato HIGH con il circuito aperto (pulsante non premuto) e LOW con circuito chiuso (pulsante premuto). Questo può inizialmente creare un po' di confusione, ma è solo una convenzione.

In maniera analoga alle resistenze di pull up possiamo utilizzare resistenze di pull down. In questo caso il circuito aperto porterà il pin in stato LOW e il circuito chiuso in stato HIGH

LINK VARI:

http://www.settorezero.com/wordpress/corso-programmazione-picmicro-in-c-lezione-8-pilotare-i-display-a-led-a-7-segmenti-in-modalita-multiplex-su-interrupt-del-timer0-realizziamo-un-contatore-up-down/

http://www.settorezero.com/wordpress/corso-programmazione-picmicro-in-c-lezione-5-timer0-e-prescaler-come-si-impostano-per-generare-interrupt-nei-tempi-che-vogliamo-applicazione-pratica/

http://www.settorezero.com/wordpress/corso-programmazione-picmicro-in-c-lezione-4-cosa-sono-gli-interrupt-concetti-di-base-per-sistemi-operativi-multitasking-su-picmicro/

http://www.robot-italy.com/

http://www.vincenzov.net/tutorial/elettronica-di-base/PIC16F690/interrupt.htm

http://digidownload.libero.it/ing.antoniospataro/Quarta/Quarto anno/PIC/3 Manuale di programmazione per pic16f84 e pic16f876.pdf

http://mbortolotti.blogspot.it/2012/01/resistenze-di-pull-up.html