Continuiamo a salutare...

Dopo aver visto come accendere un LED, continuiamo in questa pagina ad esaminare l'uso di PORTx, per generare segnali digitali.

Accendiamo un solo LED

A volte vogliamo accendere o spegnere un solo LED, non otto come nel precedente esempio. Analogamente non sempre è opportuno configurare tutti gli otto pin di PORTx come uscita: è infatti assolutamente legittimo avere alcun pin come ingresso ed altri come uscita. Osservazione 1

La seconda versione del precedente codice, che utilizza lo stesso hardware già presentato,  mostra come fare, utilizzando la sintassi dei bit fileld che permette di modificare un solo bit, lasciando gli altri invariati

TRISCbits.RC0  = 0; // Set RC0 pin as Output
LATCbits.LATC0 = 1; // Turn on  RC0 pin

In questo caso viene configurato come uscita solo pin RC0 e su di esso viene impostato un valore alto.

Analogamente, per spegnere il LED:

LATCbits.LATC0 = 0; // Turn off RC0 pin

La modalità appena descritta è tipica di XC8 ed utilizzata con praticamente tutti gli SFR associati alle periferiche definiti negli header file distribuiti insieme al compilatore.

In alternativa è ovviamente sempre possibile modificare tutti i pin di una porta con un solo assegnamento. Per esempio per configurare quattro bit come ingresso e quattro come uscita:

TRISC = 0b11110000; // Set R0 -> R3 as output; R4 -> R7 as input

Se, per qualche ragione, non si vuole o non si può utilizzare la sintassi appena mostrata, è possibile utilizzare i normali operatori bitwise per settare o resettare un singolo bit senza modificare gli altri. Per esempio:

LATC = LATC | 0b00000001; // Turn on  RC0 pin (or LATC |= 0b11111110)
LATC = LATC & 0b11111110; // Turn off RC0 pin (or LATC &= 0b11111110)

Da notare che questa seconda modalità NON è utilizzabile con PORTx anche se a volte, apparentemente, funziona. Perché?

L'uso della direttiva #define e delle macro in molti casi rende spesso il codice più leggibile e facile da manutenere. Si veda il secondo codice di esempio, funzionalmente uguale al precedente, ma più semplice da comprendere.

Blink

Una volta acceso un LED, vogliamo anche spegnerlo. Magari facendolo lampeggiare. E' quello che fa il codice in blink.c, che utilizza lo stesso hardware già presentato. Per accendere e spegnere un LED è sufficiente un ciclo infinito simile al seguente:

while (1) {            // Forever
   LATCbits.LATC0 = 1; // Turn on  RC0 pin
   LATCbits.LATC0 = 0; // Turn off RC0 pin
}

In alternativa è possibile usare la negazione bitwise per invertire lo stato dell'uscita ad ogni ripetizione del ciclo.

while (1) {                         // Forever
  LATCbits.LATC0 = ~LATCbits.LATC0; // Reverse led status
}

Eseguendo entrambi i codici mostrati si scopre però che il LED appare sempre acceso... In realtà lampeggia in modo talmente rapido che il nostro occhio non riesce assolutamente a percepire variazioni. Per verificare ciò è possibile, in alternativa:

Per "rallentare" il ciclo occorre, per esempio, inserire la macro __delay_ms(250) che, come dice il nome, inserisce un ritardo di 250 ms. Per funzionare tale macro richiede la inizializzazione della costante _XTAL_FREQ con l'effettiva frequenza di clock del processore. Osservazione 3.

Un approfondimento sull'argomento.

Supercar

Il programma presentato è un classicissimo: un LED acceso su otto che scorre continuamente da destra a sinistra e viceversa. Lo trovate a fondo pagina, in due versioni. Il cuore del circuito è costituito da 8 LED collegati a PORTC: potete utilizzare come riferimento questo circuito (lo stesso della fotografia di apertura di questa pagina), PICdemo oppure ancora PICdemo R2. Osservazione 2

La prima versione, piuttosto banale, non fa altro che mandare a PORTC otto bit che indicano quali LED vogliamo accesi e quali spenti. Di positivo ha il fatto che è semplice cambiare la sequenza di accensione dei LED.

Il secondo codice si basa sull'uso di una coppia di operazioni di scorrimento dei bit:

In pratica i bit in uscita, memorizzati nei latch di PORTC, vengono fatti scorrere di una posizione nel verso indicato dalla "freccia". Inizialmente occorre scrivere, per esempio 0b00000001.

Per approfondire trovate anche gli esercizi.

Il passo successivo: Leggere un ingresso digitale

Osservazioni

  1. Ovviamente ha poco senso "leggere un'uscita" o "scrivere un ingresso", ma queste operazioni non comportano alcun problema elettrico e di altro tipo.
  2. Non sono sempre presenti tutti gli otto pin fisici corrispondenti agli otto bit di PORTx, La scrittura (o la lettura) di tali segnali "inesistenti" non produce alcun problema né in fase di compilazione né di esecuzione. Semplicemente non viene prodotto nessun effetto.
  3. Una modifica di_XTAL_FREQ non modifica la frequenza di clock. Qui una descrizione più dettagliata

Il codice

Esercizi

  1. Collegare due LED rossi, due gialli e due verdi (e relative resistenze) a PORTC e scrivere il codice che permette di gestirli come "semaforo"
  2. Riscrivere il codice "supercar" per gestire un numero maggiore di LED (usando più di una porta)
  3. Scrivere la funzione display_7_segment(unsigned int number) per pilotare un display a sette segmenti a LED (senza decoder hardware, ovviamente!)
  4. Scrivere la funzione write_to_4094(unsigned char number) per pilotare un CD4094 (registro a scorrimento con 8 uscite)


Data di creazione di questa pagina: settembre 2014
Ultima modifica: 20 maggio 2016


Licenza Creative Commons Attribuzione 4.0 Internazionale


Pagina principaleAccessibilitàNote legaliPosta elettronicaXHTML 1.0 StrictCSS 3

Vai in cima