Progetti - PIC

 

Trasmettere a distanza più segnali.


Passiamo il sorgente ad altri PIC (+ un addendum al ricevitore 7 segmenti).


Terza ed ultima puntata sull' argomento. 

Lo scopo di queste pagine è essenzialmente uno: far comprendere che, in moltissimi casi, è possibile spaziare su molti più chip di quelli con cui si ha a che fare comunemente.
In particolare per i principianti che, all' inizio, copiano as-is una realizzazione vista sul WEB. Cosa corretta: si impara dal lavoro di chi è più avanti, ma, dato che questo ha la possibilità di essere molto datato, si finisce per usare sempre gli stessi chip altrettanto datati se non decisamente obsoleti (16F84, 12F508, 16F876/77, 16F628, ecc), andando a spendere più di quello che è il costo di un componente recente e perdendo la possibilità di sperimentare, o anche solo conoscere, le molteplici prestazioni e funzioni che questo offre rispetto ai vecchi prodotti.

Il fatto di trasportare programmi da un chip ad un altro dello stesso costruttore non è niente di magico, per le ragioni che saranno indicate; ma se queste ragioni non sono conosciute finisce per mancare lo stimolo all'aggiornamento, che è essenziale in una materia come quella dei microprocessori e microcontroller, in continua evoluzione.


Non abbiamo i PIC indicati nei sorgenti...

... ma ne abbiamo altri. Possiamo adattare il firmware senza troppi problemi?

La risposta è: "probabilmente sì".

Le chiavi della traslazione del sorgente da un chip ad un altro stanno essenzialmente in questo:

  1. famiglia di appartenenza del chip
  2. risorse integrate (essenzialmente funzioni analogiche)
  3. mappa della RAM

Da punto 1 dipende il set di istruzioni usate.
Possiamo dire che, per i PIC a 8 bit, si tratta di set di istruzioni crescenti, ma omogenei, in 4 gradini:

  • Baseline
  • Midrange
  • Enhanced Midrange
  • PIC18F

ovvero, in linea di massima, ogni famiglia contiene tutte le istruzioni della precedente e le amplia aggiungendo altri opcode. 

Certamente EnhancedMidrange e PIC18F possono disporre di istruzioni che non esistono nelle altre famiglie e questo potrebbe complicare le cose se dobbiamo portare un programma scritto per questi sui PIC minori (Baseline e Midrange). Ma non è un ostacolo la direzione inversa: nei set di istruzioni dei PIC maggiori sono comprese tutte le istruzioni di quelli minori; quindi, portare un programma da un Baselie a un PIC18F non è impossibile, anzi.

Ci sono, ovviamente, degli ostacolo, come ad esempio le istruzioni OPTION e TRIS che esistono solo nei Baseline, ma nelle altre famiglie la sostituzione con i corretti opcodes è immediata: dato che i due registri sono mappati in RAM, basterà un normale movwf.  Se opcodes inadeguati vengono inseriti nel sorgente, l' Assembler MPASM ne segnala la non congruità e in alcuni casi li può sostituire direttamente (ad esempio return con retlw 0 per i Baselien). 
Quindi la prima regola è:

  • E' possibile spostare con semplicità un sorgente scritto per un chip con un certo set di istruzioni verso un altro chip con un set di istruzioni superiore.

L'inverso può essere possibile, ma richiede di sostituire le istruzioni mancanti o con una variazione della logica degli algoritmi di cui fanno aprte o con diverse altre istruzioni.

Dal punto 2 dipendono le azioni che dobbiamo mettere in atto per arrivare a disporre pienamente degli I/O digitali.  Ricordiamo che nella filosofia di base di Microchip c'è l' idea di minimo consumo al default del POR, per cui:

  • tutti gli I/O configurabili come analogici, sono definiti in questo modo
  • tutti gli altri sono definiti come ingressi digitali
  • tutti i moduli non indispensabili sono spenti

Ne deriva la necessità di individuare quali siano le funzioni che impediscono l' accesso ai pin come semplici I/O digitali e le le manovre necessarie per ottenere questo. Solitamente basta uno sguardo alle primissime pagine del foglio dati per identificare immediatamente la presenza di analogiche, ovvero dei comparatori e dell' ADC.

Possono poi esserci altre differenze hardware caratteristiche di singoli chip, tra cui si possono ricordare:

  • la necessità di un oscillatore esterno (vecchi chip come 16F84, 16F876/77, ecc.).
  • l' impossibilità di usare il pin MCLR come input, sempre per vecchi. PIC
  • la gestione di interrupt
  • la possibilità di usare Timer 0 a 16 bit

La necessità dell'oscillatore esterno riduce di 2 unità il numero dei pin disponibili come I/O, dato che in gran parte dele applicazioni l'oscillatore interno dei chip meno "antichi" è più che adeguato.
Altrettanto la funzione di I/O sul pin MCLR.
Per quanto riguarda gli interrupt, è ben difficile che si possa spostare un programma scritto con una gestione interrupt su un processore che ne sia privo: la cosa, al minimo, richiede la riscrittura completa della logica di funzionamento.
Per quanto riguarda l'ultimo punto, va precisato che si tratta essenzialmente di funzioni dei PIC18F o degli Enhanced Midrange, nei quali, però, i default fanno si che la posizione iniziale al Power On ne permetta l' uso in legacy, ovvero in un modo del tutto compatibile con le versioni meno dotate; ad esempio, il Timer0, pur potendo operare a 16bit, per default funziona a 8 bit e quanto scritto per altri Timer0 che non hanno questa opzione è adatto senza modifiche (però sparisce il registro OPTION_REG, sostituito da uno specifico, dedicato al controllo del timer).

Esistono poi delle trappole di vario genere; tanto per citarne alcune:

  • la funzione open drain per RA4, presente su vecchi modelli obsoleti
  • l'oscillatore interno che per default, in vari chip recenti, è a frequenze diverse da 4MHz
  • la diversa destinazione di alcuni pin per usi speciali, come i port per USB, che rende i chip non compatibili con il pinout degli altri con lo stesso package.
  • diversità nella label riservate per la definizione del config iniziale che generano errori nella compilazione
  • la presenza di weak pull-up abilitati o disabilitati a seconda dei chip

Per quanto riguarda periferiche non analogiche, la filosofia di Microchip è quella di una "legacy" con i modelli meno dotati e dell' onnipresente principio del minimo consumo, il che comporta la disabilitazione per default di queste funzioni; se ne abbiamo bisogno, occorre "accendere" il modulo richiesto e configurarlo. Altrimenti è come se non ci fosse.
Questo vale in generale per CCP, MSSP, VREF, ecc, come pure per la presenza di EEPROM, per gli interrupt o altre particolarità specifiche della struttura di una data famiglia di chip.
Quindi, davanti ad un chip con un numero elevato di moduli e un foglio dati da 400 pagine non è il caso di scoraggiarsi: le funzioni, al di là delle analogiche (comparatori e ADC) è generalmente disabilitata per default e se non la usiamo è come se non fosse presente.

In generale vale il seguente principio:

  • Il programma scritto per un chip di una famiglia può essere trasferito ad chip appartenente ad una superiore senza troppi problemi. Il contrario però può non essere possibile.

Ad esempio, se ho un programma che impiega interrupt a due livelli di priorità, potrò farlo girare solo su PIC18F, dato che le altre famiglie non hanno questa funzione. Se ho un programma che usa interrupt ad un livello, potrò adattarlo a tutte le famiglie, esclusi i Baseline che non gestiscono interrupt. Se ho un programma che non usa interrupt potrà con grandi probabilità essere fatto girare su tutti i chip.
Così, ovviamente, non potrò fare cose impossibili, come spostare programmi che usano ADC o moduli di comunicazione seriale su chip che non ne dispongono e così via per tutti i vari USB o LIN o Ethernet o LCD, che sono moduli specifici solo di alcuni chip specializzati.   

Il punto 3 riguarda la mappatura della RAM, che può iniziare in posizioni diverse a seconda del componente, ma vedremo che si tratta di un problema facilmente risolvibile.
A riguardo della memoria, va considerato che se nei Baseline esistono forti limitazioni per le chiamate goto e call, dovute alla struttura del Program Counter e delle istruzioni codificate su soli 12 bit, nei Midrange queste limitazioni sono decisamente minori e molto lievi nei 18F, dove non ci sono pagine in memoria.
Anche la situazione degli SFR può creare situazioni di difficoltà all' utilizzatore, dato che,  per le famiglie superiori ai Baseline, è comune avere la zona RAM frammentata in più banchi (anche 32 negli Enhanced Midrange) il che mette in difficoltà il programmatore Assembly con la continua richiesta di cambio dei banchi.

Per quanto riguarda Baseline e Midrange, possiamo riportare un esempio dei mappa delle risorse.
Ecco quelle di un Baseline (12F505) minimale e di un Midrange (16F628):

Se consideriamo gli Enhanced Midrange o i 18F abbiamo una disponibilità di risorse quanto mai maggiore. Ecco, ad esempio, quelle di 16f1503:

Dove non vengano usate funzioni particolari, va però detto che la filosofia generale dei PIC a 8 bit pone in banco 0 i registri dei PORTx, che devono essere usati in continuazione nel programma, mentre in banco 1 si trovano i registri TRISx di direzione, il cui uso è meno intenso, limitandosi generalmente alla sola fase di inizializzazione della situazione degli I/O. Per gli altri SFR, anche se è normale che i registri primari, come STATUS e FSR siano accessibili allo stesso modo da tutti i banchi, è opportuno dare una occhiata alle tabelle della mappa della memoria onde evitare di  prendere abbagli e di incorrere in bug difficili da diagnosticare.

Ci sarebbe ancora moltissimo da dire, anche perchè il numero dei modelli di PIC prodotti è elevato e vengono aggiunte risorse e strutture sempre nuove; la casistica è molto ampia e diventa necessaria una buona conoscenza dei vari chip nel momento in cui si intendono usare risorse non comuni. Però, in sostanza, possiamo dire che:

  • meno risorse usa il programma da spostare, meno sarà problematica la sua migrazione da un chip ad un altro.

In particolare, l'uso delle pseudo macro dell' Assembler MPASM (banksel, pagesel, bankisel) consente di scrivere sorgenti portabili facilmente. Il contrario, no.
Ad esempio, la commutazione dei banchi, in Baseline e Midrange avviene con uno o due bit dello STATUS, ma negli Enhanced Midrange e nei PIC18 questi bit non esistono più. Se si è usata una manipolazione diretta di questi bit, magari con le solite macro aggiunte (Bank0 e simili), occorrerà modificare manualmente tutti i punti dove queste sono presenti. Se, invece, è stato usato il banksel, MPASM provvede a compilarlo con i giusti opcodes per ogni singolo processore; così, in un Baseline banksel 1 porterà a 1 il bit RP0, per un Enhanced scriverà 1 in BSR: il codice è immediatamente portabile senza modifiche.


I nostri RX e TX.

Abbiamo visto che il sorgente per i Baseline impiegati nella trasmissione sul cavo è stato scritto specificamente per impiegare il minimo di risorse, sia come registri che come struttura logica e funzionale.

Per svolgere il suo lavoro non usa interrupt (dato che i Baseline non ne hanno...), non usa periferiche speciali (i Baseline sono chip piuttosto "poveri"), non usa istruzioni particolari (i Baseline hanno il set minimo), usa una quantità minima di RAM e di memoria, tale da non mandare in crisi anche il chip più misero; non usa EEPROM, nè altro di particolare.
L' unica periferica chiamata nel ricevitore è Timer0 (ma se ne potrebbe anche fare a meno), che esiste praticamente identico in tutti i chip.

Uniche particolarità sono l' uso del pin MCLR come ingresso e l' oscillatore interno.

Possiamo allora affermare subito che passare il sorgente ad altri Baseline è del tutto automatico. Abbiamo già visto come i sorgenti siano compilabili direttamente per vari chip.


Baseline.

Passare i sorgenti ad altri Baseline è del tutto immediato, tanto che è stato semplice scrivere qualcosa di adatto a più di un processore nello stesso sorgente.
Se si usano chip con più di 8 pin, basterà adattare i collegamenti di I/O in modo da replicare la situazione del GPIO per non avere necessità di modificare la logica di funzionamento del programma. Ovviamente sarà necessario adattare la definizione del processore e verificare se non ci sono situazioni "strane" su I/O e memoria, ma dovrebbe sempre trattarsi di modifiche minimali, dato che i componenti della famiglia Baseline sono piuttosto uniformi.


Midrange - l'esempio del noto (e vetusto) 16F84A...

Anche passare i sorgenti da Baseline a Midrange non è un problema, in quanti questi sono i "fratelli maggiori" dei primi e ne comprendono tutte le funzioni. Quindi non capita di non disporre di una risorsa prevista dal programma.

Iniziamo allora (purtroppo) con il più noto dei Midrange, il 16F84A (consideriamo questo e non 16F84 dato che esso dovrebbe essere disponibile solo nei musei della storia dell' elettronica. Comunque le differenze sono trascurabili).

Vediamo le caratteristiche del chip: si tratta di un prodotto extra vecchio e quindi assai primitivo rispetto ai Midrange più recenti.
Gli elementi salienti, visibili nelle primissime pagine del foglio dati, sono:

  • è un 18 pin, con gli I/O organizzati in due PORT (PA e PB) rispettivamente a 4 e 8 bit. Quindi le risorse come numero di I/O ci sono in abbondanza.
  • Non ha oscillatore interno e richiede componenti esterni.
  • Il pin MCLR è dedicato e non corrisponde a nessun port
  • Ha il Timer0
  • Non ha nessuna analogica, per cui l' accesso ai pin come I/O digitali è diretto
  • Ha interrupt e EEPROM, ma queste non ci interessano
  • Ha la verifica del on-change pin e un ingresso di interrupt, ma sono funzioni che non usiamo
  • La memoria è di 1K in un unica pagina; non occorrono switch di pagina, nè ci sono le limitazioni dei Baseline
  • La memoria RAM e gli SFR sono su due banchi, ma il banco 1 riguarda solo i registri della EEPROM (che non usiamo) mentre la RAM e gli altri registri sono speculari sulle due pagine; non occorre alcun cambio di pagina.

L' OPTION_REG ha struttura del tutto simile a quella dei Baseline e gli switch per T0CKI, l' assegnazione del prescaler e del suo valore sono nelle stesse posizioni, per cui valgono le stesse inizializzazioni.

16F84A è un Midrange povero, in pratica un Baseline con l' aggiunta dell' interrupt e un set di istruzioni più esteso.

Dunque il passaggio del sorgente è praticamente immediato.


Hardware TX - 16F84A

Data la diversa disposizione dei pin (chissà per quale ragione i 18 pin non sono sovrapponibili ai 20/14/8) e la diversa distribuzione dei port richiedono un diverso schema elettrico:

Usiamo i primi 6 bit di PORTB con le stesse funzioni del GPIO dei Baseline a 8 pin.
PORTA è inutilizzato.
Nulla vieta di utilizzare altri pin in qualsiasi combinazione, ma questa è la più semplice.

Per quanto riguarda l' oscillatore, anche se è possibile utilizzare un RC esterno, meglio usare un cristallo, dato che non è per nulla semplice realizzare un RC che origini 4MHz all' 1% e mantenga questa taratura col variare della temperatura. L' uso di condensatori di precisione NP0 e resistenze a strato metallico è ideale, ma il costo finisce per superare quello di un comune risonatore ceramico.

Questo non è preciso nè stabile come un quarzo, ma nella versione a tre pin è un elemento assai comodo ed economico, contenendo anche i condensatori necessari all' oscillatore e generando una frequenza di precisione e stabilità  più che adeguate per questa applicazione.

La frequenza sarà 4MHz, dato che per questo valore sono calcolate le routines di tempo; nel caso in cui si utilizzino quarzi o risonatori con una frequenza diversa basta modificarle. Ecco un possibile circuito stampato unico, adatto per TUTTI i chip a 18 pin.

Al posto del solito ingombrante cristallo HC49 si potrà usare il risonatore, eliminando i condensatori E$5/E$6.

 


Il software.

Ecco il sorgente, con evidenziate le linee che presentano una differenza, concentrate nella parte iniziale del sorgente, iniziando dalla definizione del processore

; scelta del processore

              LIST p=16F84A
              #include <p16F84A.inc>

Potrebbe essere utile impiegare i weak pull-up che il chip mette a disposizione. La scelta è effettuata con il bit 7 di OPTION_REG :

; Option_Reg - disabilita T0CKI e prescaler a Timer0
        movlw b'01010111'  ; si pullup, presc.256
        movwf OPTION_REG

Questo può essere utile per avere pull-up sui pin di ingresso senza aggiungere resistenze esterne. Se l' opzione non serve, basta portare a 1 il bit 7.

In particolare occorre ricordare che i weak pull-up integrati non sono resistenze, ma MOSFET con una elevata resistenza drain-source (20-100K); solitamente non hanno nessuna contro indicazione; sono ideali per ingressi da pulsanti e open collector o anche logiche CMOS. 

Però è possibile (anche se molto improbabile) che , essendo elementi attivi, si possano creare problemi quando gli ingressi sono pilotati da qualche logica "strana" e quindi ecco la possibilità di disabilitarli. 

 

Da notare che tutti i pin di PORTB hanno un weak pull-up e sono tutti abilitati o disabilitati contemporaneamente, ma diventano attivi solo quelli sui pin configurati in TRISB come ingressi.

La differente struttura dei port ci fa passare da GPIO a PORTB:

;---------------------------------------------
;inizializzazione I/O
        clrf PORTA      ; clear port
        clrf PORTB 
        clrf sGPIO      ; clear
shadow

; Direzione I/O
; I pin non usati sono configurati come uscite per
; evitare la captazione di disturbi.
movlw b'00000000' ; PORTA out
        movwf TRISA
        movlw b'00001111' ; RB0-3 in, altri out
        movwf TRISB

 quindi:

 movf  sGPIO,W    ; set output
      movwf PORTB        ; questo spegne anche il LED

Nessuna modifica è necessaria alle altre righe !

Osserviamo che nel complesso le variazioni riguardano solamente ovvietà, ovvero:

  • la definizione del processore
  • il suo config specifico
  • le assegnazioni degli I/O

Va aggiunta anche la necessità di sostituire le istruzioni OPTION e TRIS il cui uso è limitato ai Baseline.
Non occorre neppure modificare l' inizio RAM, dato che quella di 16F84A parte a 0Ch e quindi 10h è nell' intervallo utile.


Hardware RX - 16F84A

Data la diversa disposizione dei pin e la diversa distribuzione dei port anche qui si richiede un diverso schema elettrico:

L' assegnazione dei pin non è certo ottimale, ma permette una diretta compatibilità con quanto scritto per i Baseline a 8 pin, sempre considerando i primi 6 bit di PORTB come sostituti del GPIO.


Il software RX - 16F84A.

Ecco le differenze rispetto alla versione per Baseline. 

Ovviamente ancora per prima la definizione del processore e config come già visto, mentre la seconda riguarda le assegnazioni degli I/O. Utilizziamo delle assegnazioni apparentemente strane, ma che ricalcano perfettamente la situazione dei Baseline a 8 pin:

;**************************************************************
;==============================================================
; DEFINIZIONE DI IMPIEGO DEI PORT
;==============================================================
;
;PORTB
;
#define D0      PORTB,RB0      ; out dati paralleli
#define D1      PORTB,RB1
#define D2      PORTB,RB2
#define D3      PORTB,RB4
#define serin PORTB,RB3      ; in seriale
#define LED    PORTB,RB5      ; out LED

; PORTA non è usato

Inizializziamo i port:

;---------------------------------------------
;inizializzazione I/O
        clrf PORTA      ; clear port
        clrf PORTB 
        clrf sGPIO      ; clear shadow


; Option_Reg - disabilita T0CKI e prescaler a Timer0
        movlw b'11010111' ; no pullup, presc.256
        movwf OPTION_REG

; Direzione I/O
; I pin non usati sono configurati come uscite per
; evitare la captazione di disturbi.
movlw b'11111111' ; PORTA out
        movwf TRISA
        movlw b'00001000' ; RB3 in, altri out
        movwf TRISB

e

movf  sGPIO,W    ; set output
      movwf PORTB        ; questo spegne anche il LED

Nessuna modifica nelle altre righe ! 

Osserviamo che anche qui le variazioni riguardano gli stessi elementi visti prima.

Non ci sono variazioni nella logica delle istruzioni del programma vero e proprio.


Midrange - 16F628.

Un altro dei must nell' ambito dei "processori d'annata" è il 16F628.

Successore del 16F84A, è quasi altrettanto obsoleto, ma presenta almeno qualche caratteristica più avanzata. Si sempre di un Midrange, ma meno spartano del primo:

  • sempre a 18 pin, con gli I/O organizzati in due PORT (PA e PB) entrambi a 8 bit. 
  • Ha oscillatore interno 
  • Il pin MCLR è configurabile come input
  • Ha il Timer0
  • Ha interrupt e EEPROM, UART, CCP e Vref, oltre ad altri due timer, ma queste funzioni non ci interessano
  • Dispone di comparatore, che andrà disabilitato
  • Ha la verifica del on-change pin e un ingresso di interrupt, ma sono funzioni che non usiamo
  • La memoria è di 2K in due pagine, ma per questa applicazione non occorrono switch di pagina, nè ci sono le limitazioni dei Baseline
  • La memoria RAM e gli SFR sono su 4 banchi; in questo va prestata attenzione, in quanto i registri TRISx stanno in in banco 1 e non in banco 0 come i PORTx..

Anche qui l' OPTION_REG ha la stessa struttura di quello del 16F84A e gli switch per T0CKI, l' assegnazione del prescaler e del suo valore sono nelle stesse posizioni, per cui valgono le stesse inizializzazioni.

Non usando nè interrupt, ne EEPROM, la gestione di queste parti, per default disabilitate, non ci interessa.

Anche se 16F628 è un sostituto più evoluto di 16F84A, il passaggio del sorgente è praticamente immediato, anche se occorre prestare attenzione a due punti.


Hardware TX - 16F628.

La stessa disposizione di 16F84A. Si può usare lo stesso circuito stampato che si è eventualmente realizzato per 16F84A e che è adatto a qualsiasi chip a 18 pin.

Avendo disponibile un oscillatore interno possiamo risparmiare i componenti esterni: nello schema sopra non sono indicati; basterà impostare la scelta nella configurazione.  Altrimenti si può mantenere l' oscillatore ceramico o il quarzo usati in precedenza, sempre adeguando il config. Ne parliamo qualche riga più sotto.
Ugualmente si può anche eliminare la R2 se si disabilita MCLR, sempre dal config.

Però è possibile realizzare uno stesso circuito stampato attorno allo schema indicato per il 16F84A e questo sarà adeguato per TUTTI i chip a 18 pin.


Il software TX - 16F628.

Ecco le differenze rispetto alla versione per Baseline. Ovviamente per prima la definizione del processore:

; scelta del processore

              LIST p=16F628
              #include <p16F628.inc>

La seconda, come per 16F84A riguarda le assegnazioni degli I/O. Se non utilizziamo il pin MCLR, possiamo mantenere le stesse assegnazioni precedentemente usate ericalcare quanto scritto per 16F84A.

Per 16F628 l' assegnazione della RAM deve essere variata:

;*************************************************************
;=============================================================
; Variabili RAM
;=============================================================
;
      CBLOCK 0x20 ; RAM start
        sGPIO          ; buffer temporaneo PORTB
        d1                ; counter per delay
        d2
      ENDC

Altra modifica essenziale è quella del config, che va adeguato alle risorse specifiche del chip

;==============================================================
; CONFIGURAZIONE =
;==============================================================
; Oscillatore interno, no WDT, PWRT on, BOBE on, no CP, n
    __config _HS_OSC & _WDT_OFF & _PWRTE_ON  & _BODEN_ON & _LVP_OFF & _MCLRE_ON & _CP_OFF

Qui ci si presentano alcune scelte:

  • usare l' oscillatore interno come per i Baseline visti in precedenza o quello esterno come per il 16F84A. Dal punto di vista del programma, la scelta è indifferente. Si tratta solo di assegnare la giusta scelta nella riga di configurazione
  • a differenza di 16F84A, il pin MCLR è utilizzabile come ingresso; però può essere utile mantenere la stessa struttura usata per il 16F84A, dato che qui MCLR è alternativo a RA5

Se abbiamo realizzato un circuito stampato per il 16F84A possiamo utilizzare lo stesso, senza alcuna modifica, per tutti i 18 pin. Quindi possiamo continuare ad impiegare l' oscillatore esterno e il pin MCLR, anche se non necessari. In particolare, va osservato che l' oscillatore interno di 16F628 non ha un registro di calibrazione, con il rischio di risultare poco preciso; però, nella nostra applicazione, i tempi di sustain dei bit trasmessi sono 1000 volte (1ms) maggiori del ciclo di istruzione (1us) e non dovrebbero esserci problemi di sincronizzazione anche con oscillatore meno preciso dell' 1%. 
la scelta del modo di oscillatore dipende dalla riga di config.

Analogo discorso per i weak pull-up che questo chip permette di abilitare su PORTB.
La selezione è sempre il bit 7 dell' OPTION_REG  .

Un punto "dolente", causa di disperazione per i super principianti, riguarda le analogiche: 16F628 ha un comparatore e quindi questo ha la precedenza nei default rispetto alla semplice funzione digitale dei pin.
No problem, basta disabilitare:

; Disabilita comparatori
        movlw    0x07              ;disabilita comparatori
        movwf    CMCON

Ma occorre ancora attenzione: come tipico dei PIC non Baseline, i registri TRISx, a differenza di 16F84A, non sono in banco 0, ma in banco 1, per cui:

        banksel  TRISA
        movlw    b'11111111' ; PORTA out
        movwf    TRISA
        movlw    b'11110000' ; PORTB7-4 out, altri in
        movwf    TRISB
        banksel  0

lasciando fare il lavoro"sporco" della commutazione dei banchi a banksel e ricordandosi di riportare l'azione in bank0.

Ultima azione, come per il 16F84A, è l' uso diverso dei PORT, dove PORTB sostituisce GPIO:

 ;---------------------------------------------
Main bcf LED                ; LED 0ff
        bcf   serout        ; serial out = 0
        call  Delay100ms    ; delay 100ms
        movf  PORTB,W       ; salva stato I/O
        movwf sGPIO
        bsf   LED           ; LED on durante la trasmissione

Nessuna modifica nelle righe successive!

Osserviamo che le variazioni riguardano sempre e solo gli elementi prima visti, a cui si aggiunge:

  • la necessità di escludere il comparatore
  • l' adattamento della RAM
  • la necessità di commutare i banchi per accedere a certi SFR.

Hardware RX - 16F628.

Utilizziamo lo stesso schema usato per 16F84A. Il circuito stampato può essere lo stesso utilizzabile per qualsiasi 18 pin:

Disponiamo sempre i collegamenti in modo tale che PORTB sostituisca GPIO. Questo consente di impiegare la stessa logica senza modifiche.

Come sopra, se si usa l' oscillatore interno non servono componenti esterni: basterà impostare la scelta nella configurazione, ma si può usare lo stesso stampato con l' oscillatore esterno installato, sempre adeguando il config iniziale.
Ugualmente si può anche eliminare la R2 se si disabilita MCLR dal config.

PORTA non viene usato.


Il software RX - 16F628.

Ecco le differenze rispetto alla versione per Baseline. 

Valgono le stesse modifiche iniziali già viste per il trasmettitore:

  • la definizione del processore
  • il config
  • l'inizio della RAM
  • le assegnazioni degli I/O.

Utilizziamo delle assegnazioni apparentemente strane, ma che ricalcano perfettamente la situazione dei Baseline a 8 pin:

;**************************************************************
;==============================================================
; DEFINIZIONE DI IMPIEGO DEI PORT
;==============================================================
;
;PORTB
#define D0 PORTB,RB0      ; out dati paralleli
#define D1 PORTB,RB1
#define D2 PORTB,RB2
#define D3 PORTB,RB4
#define serin PORTB,RB3   ; in seriale
#define LED PORTB,RB5     ; out LED

Inizializziamo i port come già visto, eliminando il comparatore e dando la direzione voluta ai pin:

; Disabilita comparatori
        movlw    0x07              ;disabilita comparatori
        movwf    CMCON

; Direzione I/O
        banksel TRISA
        movlw    b'00000000' ; PORTA out
        movwf    TRISA
        movlw    b'00001000' ; PORTB3 in, altri out
        movwf    TRISB
        banksel 0

Nessuna modifica nelle altre righe! 

Il rapporto tra segnali e pin ricalca quello dei Baseline a 8 pin e quindi resta identica la logica.

Osserviamo che le modifiche riguardano sempre e solo gli elementi già visti e non ci sono variazioni nella logica delle istruzioni del programma vero e proprio.


Note.

In effetti sono stati forniti sorgenti adatti contemporaneamente per entrambi i chip, ma non solo. Sono accomunati:

  • 16F84A
  • 16F627
  • 16F628
  • 16F627A
  • 16F628A
  • 16F648A 

con lo stesso sistema di selezione già visto, basato sulla definizione del processore nel progetto. Questo perchè le differenze che i chip presentano per questa applicazione sono limitate solamente alla solita necessità iniziale di definire il modello, la configurazione e dove necessario, disabilitare le analogiche.
Siccome la RAM di 16F84A va da 0Ch a 4Fh e quella degli altri si estende da 20h a 7Fh (banco0), è stato scelto di usare 3 bytes a partire da 20h, area comune a tutti, il che permette di non modificare neppure questa assegnazione.

Una precisazione: con il sistema visto si possono scrivere sorgenti comuni a molti PIC, ma non è il caso di esagerare: se le risorse sono limitate come in questi esempi, sono necessarie anche poche selezioni #ifdef, ma se si accomunano troppi chip differenti o l' applicazione utilizza risorse complesse, il risultato è quello di ottenere un sorgente ben poco leggibile. Qui si sarebbero potuti aggiungere facilmente 16F87, 16F88 (che dispone di ICD), 16F716, ecc., con, però, un aggravio di linee di selezione, anche solo per il tipo di processore o in config.
Quindi, volendo scrivere sorgenti comuni a vari modelli è il caso di accomunare in un gruppo componenti che abbiano risorse e struttura quanto più simili possibile, in modo da minimizzare le selezioni #ifdef.

Nei casi esemplificati, vediamo come abbiano data sheet comune:

  • 12F629/675
  • 16F627/628
  • 16F627A/628A/648A

il che indica una stretta somiglianza dei chip, con differenze speso ridotte alla sola quantità di memoria integrata.
Inoltre le versioni A sono solitamente degli enhancement di versioni più datate ed offrono solitamente prestazioni in più, ma sono utilizzabili in legacy senza problemi. Comunque Microchip provvede documenti di migrazione, ad esempio


Midrange - 12F629/675.

Ci sono dei Midrange a 8 pin, che possono sostituire "direttamente" i 12F5xx originali. Consideriamo due chip abbastanza noti: 12F629 e 12F675.
Si tratta di chip "gemelli" (condividono uno steso foglio dati), con piccole differenze tra loro.
Se il pinout è identico come per tutti i DIP8, troviamo però all' interno una struttura Midrange e non Baseline:

  • 8 pin, con il caratteristico GPIO. 
  • Ha oscillatore interno 
  • Il pin MCLR è configurabile come input
  • Ha il Timer0
  • Ha interrupt e EEPROM, oltre al Timer1
  • Dispone di comparatore, che andrà disabilitato
  • 12F675 dispone anche di ADC, che andrà pure disabilitato
  • La memoria è di 1K in una pagina e quindi non servono pagesel, nè ci sono le limitazioni dei Baseline
  • La RAM, come comune nei Midrange, inizia a 20h
  • La memoria RAM e gli SFR sono su due banchi; in questo va prestata attenzione, in quanto i registri TRISx stanno in banco1 e non in banco0 come i PORTx, come comune nei Midrange.

L' OPTION_REG ha sempre la stessa struttura di quelli finora visti e gli switch per T0CKI, l' assegnazione del prescaler e del suo valore sono nelle stesse posizioni, per cui valgono le stesse inizializzazioni. Però, come in tutti i Midrange, il registro è accessibile sia in lettura che scrittura e non richiede istruzioni speciali, come pure i registri di direzione TRISx.

Non usando nè interrupt, ne EEPROM, la gestione di queste parti, per default disabilitate, non ci interessa.

Dunque il passaggio del sorgente è praticamente immediato, anche se occorre prestare attenzione a due punti.


Hardware TX - 12F629/675.

Usiamo gli stessi identici circuiti visti per i Baseline a 8 pin della puntata I. 


Il software TX - 12F629/675.

Ecco il sorgente, con evidenziate le linee che presentano una differenza dall' originale.

Ovviamente la prima riguarda l' assegnazione del processore; col sistema già visto possiamo avere un unico sorgente per i due chip:

; scelta del processore

  #ifdef  __12F629
              LIST p=12F629
              #include <p12F629.inc>
  #endif
  #ifdef  __12F675
              LIST p=12F675
              #include <p12F675.inc>
  #endif

Altra modifica essenziale è quella del config, che va adeguato alle risorse specifiche del chip:

;===============================================================
; CONFIGURAZIONE =
;===============================================================
; Oscillatore interno, no WDT, PWRT on, BOD on, no CP, no LVP
    __config __CONFIG _CP_OFF & _CPD_OFF & _BODEN_ON & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT

Nessuna variazione rispetto agli originali per Baseline per quanto riguarda l' assegnazione degli I/O, mentre per l'inizio della RAM va modificato:

;***************************************************************
;===============================================================
; Variabili RAM
;===============================================================
;
      CBLOCK 0x20 ; RAM start
        sGPIO          ; buffer temporaneo PORTB
        d1                ; counter per delay
        d2
      ENDC

Osserviamo che il comando per l' oscillatore interno contiene una variabile in più, ovvero quella relativa alla possibilità di avere Fosc/4 in uscita sul pin OSC2; dato che questa non è desiderata, perchè abbiamo bisogno di tutti gli I/O, specifichiamo la scelta

Solito punto "dolente" che riguarda le analogiche: i due chip hanno un comparatore e 12F675 anche un ADC, che hanno la precedenza nei default rispetto alla semplice funzione digitale dei pin.
No problem, basta disabilitarli:

; Direzione I/O
        movlw    0x07              ;disabilita comparatori
        movwf    CMCON
  #ifdef  __12F675            ; disabilita ADC
        banksel ANSEL
        clrf      ANSEL
        banksel 0
  #endif

va ricordato poi che come per  ANSEL, anche i TRISx stanno in Bank 1...

Nessuna modifica nelle altre righe !


Hardware RX - 12F629/675.

Usiamo gli stessi identici circuiti visti per i Baseline a 8 pin della puntata I. 


Il software RX - 12F629/675.

Le linee che presentano una differenza dall' originale sono quelle finora viste.

Ovviamente la prima riguarda l' assegnazione del processore; col sistema già visto possiamo avere un unico sorgente per i due chip. Inoltre, come già visto l'inizio della RAM va modificato.

Nessuna variazione rispetto agli originali per Baseline per quanto riguarda l' assegnazione degli I/O

Altra modifica essenziale è quella del config, che va adeguato alle risorse specifiche del chip e che non stiamo a ripetere. Così pure per le analogiche, che basta basta disabilitare.

Come comune nei Midrange, ricordare che i TRISx e ANSEL stanno in Bank 1, usando  sempre il comodo banksel e ricordandosi di riportare l'azione in Bank 0.

Nessuna modifica nelle altre righe!


18F - 18F13K22.

Per completare il panorama, vediamo anche un PIC18F, ad esempio il 18F13K22, che è un 20 pin. Condivide il foglio dati con 18F14K22 che si differenzia per la maggior quantità di memoria.

Come già detto altrove, il pinout dei chip in package a 8/14/20 pin è sovrapponibile,  però, all' interno, qui troviamo una struttura 18F, con un elevato set di funzioni integrate:

  • Ha oscillatore interno 
  • Il pin MCLR è configurabile come input
  • Ha il Timer0
  • Ha interrupt e EEPROM, oltre ai Timer1/2/3
  • Dispone di comparatore e di ADC, che andranno disabilitati
  • La memoria è enormemente più ampia di quella dei Baseline usati nel progetto iniziale e quindi non ci sono problemi di commutazione di pagina.
  • La RAM inizia a 00h
  • I meccanismi dei 18F fanno si che la memoria programma non sia paginata e quella RAM, nonostante la presenza di banchi, usufruisca con gli SFR di un sistema di accesso (Access RAM) particolare. Non occorre commutazione di banchi.
  • Delle molteplici funzioni che il chip offre non ne usiamo alcuna e la loro presenza non ci interessa; la gestione di queste parti, per default disabilitate, non è richiesta.

Non esiste un OPTION_REG e la gestione di Timer0 avviene attraverso un registro dedicato.

Nonostante si tratti di un componente appartenente ad una famiglia di chip abbastanza diversi da quelli visti in precedenza, il passaggio del sorgente è soggetto praticamente alle stesse azioni viste finora.


Hardware TX-18F.

Possiamo usare uno schema analogo a quello impiegato per i chip a 18 pin, con PORTB al posto di GPIO. Da notare che il pinout dei chip a 20 pin non è sovrapponibile a quello dei chip a 18 pin:

Il circuito va bene per tutti i PIC a 20 pin. 

Viene usato PORTC dato che PORTB è composto da soli 4 bit mentre PORTA contiene i pin per ICSP/ICD.

La presa ICSP consente non solo la programmazione onboard, ma nella maggior parte dei chip a 20 pin svolge anche la funzione di accesso all'in-circuit-debug (ICD), cosa estremamente utile in didattica, sviluppo, test, ecc.

Se ne fate un circuito stampato, questo andrà bene per TUTTI i chip a 20 pin.


Il software - TX.

Nel passaggio da Baseline/Midrange a PIC18F ci troviamo ad effettuare un salto sensibile, dato che il core della famiglia è diverso dalle precedenti.
Si tratta non solo delle solite modifiche alla scelta del processore e al config, ma anche della necessità di considerare un set di istruzioni, sempre "compatibile", ma in alcuni punti diverso, oltre ad una diversa struttura dei registri e delle memorie.

Qui diventa più vera l'affermazione che quante meno risorse il sorgente utilizza, quanto più semplice sarà il passaggio, dato che anche periferiche semplici come Timer0 non dipendono più da un SFR multiuso come OPTION_REG, ma da un registro ad hoc e così via.
In particolare, potremo trovare difficoltà notevoli nella direzione opposta, ovvero nel passaggio del sorgente scritto per 18F a PIC "minori", con la necessità di riscriverne intere sezioni.

Vediamo cosa è necessario nel nostro semplice caso.

La prima azione riguarda l' assegnazione del processore; col sistema già visto possiamo avere un unico sorgente per i due chip che ci interessano:

; scelta del processore

  #ifdef  __18F13K22
              LIST p=
  #endif
  #ifdef  __
  #endif

Nessuna variazione rispetto a quanto visto per i Midrange, anche se qui usaimo PORTC invece di PORTB, mentre per l'inizio della RAM va modificato

;**************************************************************
;==============================================================
; Variabili RAM
;==============================================================
;
      CBLOCK 0x0  ; RAM start
        sGPIO          ; buffer temporaneo PORTB
        d1                ; counter per delay
        d2
      ENDC

Altra modifica essenziale è quella del config, che va adeguato non solo alle risorse specifiche del chip, ma anche alla sintassi prevista per questa famiglia:

;==============================================================
; CONFIGURAZIONE =
;==============================================================
; oscillatore interno (1MHz), no PLL, no WDT, no LVP, no CP, no MCLR
; no debug, PWRT on, BOR on

  CONFIG FOSC = IRC
  CONFIG MCLRE = OFF
  CONFIG WDTEN = OFF
  CONFIG LVP = OFF
  CONFIG BOREN = ON
  CONFIG BORV = 22
  CONFIG WRTD = OFF
  CONFIG CPD = OFF
  CONFIG DEBUG = OFF
  CONFIG PWRTEN = ON
  CONFIG CP0 = OFF
  CONFIG CP1 = OFF
  CONFIG CPB = OFF

L'esclusione delle funzioni che si sovrappongono ai port digitali non diventa più gravosa in seguito alla maggiore quantità di opzioni disponibili; problematiche potranno essere piuttosto le azioni necessarie al corretto utilizzo di queste periferiche.
  In questo senso è da osservare che il chip contiene, oltre a 17 pin configurabili come I/O digitali con slew rate programmabile, un mare di funzioni:

  • Analog-to-Digital Converter (ADC) a 10bit con 12 canali
  • Analog Comparator module doppio
  • Voltage Reference module
  • Programmable weak pull-ups
  • Programmable interrupt-on- change
  • 3 pin per interrupt esterno
  • 4 Timer, di cui 3 a 16 bit e uno a 8
  • oscillatore per Timer1
  • Enhanced Capture/Compare/PWM (ECCP) con 1/2/4 uscite PWM
  • Master Synchronous Serial Port (MSSP) module
  • Enhanced Universal Synchronous Asynchronous Receiver Transmitter module (EUSART)
  • SR Latch (555 Timer) module con supporto per mTouch™ capacitive sensing 
  • Oscillatore interno programmabile d1 31kHz a 16MHz con PLL
  • Oscillatore esterno, 4 modalità
  • interrupt a 2 livelli di priorità
  • set istruzioni esteso
  • moltiplicazione hardware
  • accesso alle tabelle con istruzioni ad hoc
  • EEPROM
  • auto scrittura della Flash

e varie altre cose. Questo porta le pagine del foglio dati a oltre 400, il che farebbe supporre drammatica la consultazione.
Ma la cosa non è così terribile in quanto viene applicato il principio che tutte le funzioni "extra" sono disattivate per default al POR e quindi è come se non ci fossero: l' accesso ai pin come I/O digitali si limita ad una quantità ridotta di operazioni, analoga e perfino minore di quella richiesta per alcuni Baseline e Midrange.

In particolare, nel nostro caso dobbiamo agire solamente sugli ingressi del modulo ADC (abilitati al default) e sullo slew rate, impostato dal default a 1/10; non interessandoci una riduzione dell' EMC, lo riportiamo alla pendenza normale (cosa che comunque non influirebbe sul funzionamento di questa applicazione, dati i tempi molto lunghi delle temporizzazioni degli impulsi).

; no AD
      movlw b'00000000'
      movwf ANSEL
      clrf  ANSELH

;setup PORT
      clrf  TRISA            ; PA tutti out
      clrf  TRISB            ; PB tutti out
      movlw b'00001111' ; PC0-3 in , altri out
      movwf TRISC

; slew rate normale
      clrf  SLR

Non c'è altro da toccare, perchè, come detto, i rimanenti moduli sono già disabilitati, compresi i malefici comparatori (finalmente i progettisti hanno ascoltato il gemito che sale dall' utenza?).
Abilitati ci sarebbero solo i weak pull-up, ma riguardano solo PORTA e PORTB, che non usiamo.

Ci si può chiedere come fare a sapere tutto ciò. Niente di più semplice: basta leggersi il foglio dati !
Urca, come una condanna alla fucilazione...

Invece no, perchè le tabelle riportano chiaramente lo stato dei registri al POR e da queste, senza leggersi altro, si ricava immediatamente lo stato. In particolare la tabella 3.2 (pag. 37-38 del foglio dati DS41365E) li raccolgono in un unico blocco, mentre le pagine dedicate ai singoli registri li dettagliano maggiormente. Ad esempio, non esiste più un OPTION_REG e Timer0 è gestito da un opportuno registro:

Però vediamo che anche questo Timer, che nei PIC minori è sempre attivo (free running) qui è comandabile da un bit e per default è spento. Per usarlo dobbiamo accenderlo. Dato che nel TX non serve, lo lasciamo al suo default. Mentre il funzionamento a 16 bit è pure da attivare, dato che al default è disabilitato; questo consente la "legacy" con programmi scritti per PIC che non hanno questa opzione.

Degno di nota é la mancanza di azione su switches di banco per accedere agli SFR, dato che i PIC18F utilizzano una modalità particolare Access RAM, che l' Assembler MPASM compila automaticamente in relazione agli indirizzi richiesti. Un enorme sollievo per il programmatore Assembly che non deve più farcire i sorgenti di banksel.

Altra particolarità di questa famiglia è l' accesso al latch dei port:

;inizializzazione I/O
        clrf LATA            ; clear port latch
        clrf LATB
        clrf LATC

che evita il problema R-M-W che affligge Baseline e Midrange. In scrittura useremo LATx, in lettura PORTx.

Ci sono, però, nascosti altre trappole meno visibili. Una riguarda l' oscillatore interno che parte (non si sa in base a quali considerazioni) non a 4MHz, ma a 1MHz. Occorre variare il registro di controllo:

; oscillatore interno a 4MHz
      movlw b'01010000'
      movwf OSCCON

Nessuna modifica nelle righe successive!


Hardware RX-18F

Continuiamo ad usare PORTC:

Il circuito va bene per tutti i PIC a 20 pin. 

Data la sovrabbondanza di I/O il circuito potrà essere usato, adattando le uscite, anche per comandare il display a 7 segmenti o per le estensioni descritte più avanti.


Il software - TX.

Le modifiche al sorgente originale sono le stesse indicate sopra.

Unica differenza sono l' assegnazione degli I/O e la necessità di abilitare Timer0, che dobbiamo accendere:

; timer0 on, 1:256, clock interno
      movlw b'11000111'
      movwf T0CON

Inoltre ci scontriamo con alcune differenze nel set di istruzioni.
Baseline e Midrange hanno una sola forma di shift, a destra o sinistra (rrf e rlf) , che coinvolge il Carry. I PIC18F dispongo di istruzioni di rotazione doppie, una che coinvolge il Carry (rlcf e rrcf) e una che non lo modifica (rlncf e rrncf). Dovremo quindi sostituire l' opcode:

; timer0 on, 1:256, clock interno
      movlw b'11000111'
      movwf T0CON

Occorrono anche alcune modifiche qua e là, per l' esattezza riguardanti gli opcodes:

  • nel set di 18F il rotate è espresso in due modi diversi, a seconda che comprenda il carry o no. Qua non importa, per cui dobbiamo trasformare la    rrf  in   rrcf  . 
  • MPASM non accetta gli pseudo opcodes dei Baseline e dei Midrange, per cui la  skpnz  (skip next line if resut not zero) va sostituita con un  bnz  (branch if not zero), istruzione del set 18F, che però richiede una label in oggetto relativa alla destinazione del branch.
  • inoltre va considerato che le routines di tempo sono scritte usando il simbolo  $  (valore PC corrente). Però nei 18F le istruzioni sono codificate al minimo su 2 bytes (mentre nei Baseline occupano costantemente 1 byte) e questo richiede la duplicazione degli indici.

Non sono, però, necessarie modifiche nel resto delle istruzioni, che sono le stesse da Baseline a 18F . Anche per chi realizza la versione con uscita a 7 segmenti non occorre modificare la struttura della lookup table: anche se i PIC18F dispongono di un modo molto più efficiente e meno critico per realizzare l' accesso a tabelle, il sistema visto funziona senza problemi.


Enhanced Midrange.

Non presento esempi per questa famiglia, che mescola nuove funzioni, nuove istruzioni e caratteristiche dei PIC18F su una base Midrange (con tutti i suoi difetti), perchè si tratta di chip molto recenti e non ancora finiti nei "must" del web hobbistico.
E, forse, anche perchè non li trovo molto simpatici; sono adatti ad una programmazione C dove le "librerie" e gli automatismi rendono abbastanza trasparenti le asperità dell' hardware, ma lo sono un po' meno per chi vuole usarli in Assembly, dove gli SFR e la RAM sono sparpagliati anche su 32 banchi, la memoria è paginata e, in sostanza, imperano i limiti dei Midrange, anche se sono stati inseriti sistemi per renderli meno ostili (ad esempio l' accesso ai LATx per evitare R-M-W, ecc.), comprese nuove istruzioni (che, però, se usate rendono il sorgente incompatibile con qualsiasi altra famiglia, compresi i 18F...).
Le nuove periferiche sono interessanti, ma l' unica ragione della sperimentazione nei Midrange è da supporre essenzialmente in una drammatica differenza di costo tra il loro core e quello dei 18F; ovvero si tratta di scelte dettate da attenzione ai problemi economici.

Comunque, anche qui, per i semplici programmi che stiamo considerando, non ci sono particolari difficoltà per la migrazione; basterà considerare i punti indicati.
I "fogli dati" esorbitanti le 400 pagine sono scremabili in base ai principi indicati prima.


ACHTUNG - I !

A questo punto dovrebbe parrebbe che la migrazione di un sorgente da un chip ad un' altro sia cosa alquanto semplice.

Va detto però che i programmi in esame sono volutamente semplici per fungere da esempio didattico. Inoltre hanno documentazione e commenti più che esaurienti.

Nella realtà è possibile trovarsi davanti programmi di grande complessità, in cui a prima vista non è facile districarsi. E se sono usate periferiche che possono presentare piccole, ma significative differenze fra i diversi chip.
Però, anche in questi casi, fatte salve le linee essenziali dichiarate all' inizio (ovvero la possibilità della migrazione solo se il sorgente originario non usa funzioni non presenti sul chip di destinazione), è sempre possibile venire a capo della situazione considerando con un po' di attenzione gli elementi chiave indicati.

Attenzione che se il sorgente originale è scritto con la parte opposta della testa, senza forma, senza commenti nè indicazioni utili per capire cosa stia facendo, magari usando assoluti a go-go, allora le cose possono complicarsi alquanto.


Il software.

Nessuno dei sorgenti forniti è stato provato!!!
Sono stati solamente compilati per verificare che non contengano madornali svarioni formali.
Ma non ci sono ragioni per cui, a meno delle solite distrazioni, questi non funzionino.

In effetti, queste pagine non sono è la descrizione di una realizzazione, ma un compito a casa Ovvero: chi è interessato alla realizzazione, usando PIC diversi da quelli proposti all' origine, ha qui alcuni esempi e linee guida per poter traslare il sorgente.
E chi è interessato a sperimentare qualcosa di Assembly, può benissimo provare i sorgenti proposti come esercitazione.

Ovviamente, se ci sono difficoltà, a disposizione (entro limiti ragionevoli...) per trovare eventuali bug in quanto scritto.


Addendum al ricevitore per display a 7 segmenti.

Abbiamo visto (puntata II) che, attraverso la lookup table, otteniamo la conversione del dato a 4 bit in ingresso in una delle 16 possibili combinazioni in uscita.
Per avere maggiore chiarezza sulle possibilità offerte da questo metodo, aggiungiamo alcuni altri esempi. Infatti la tabella non è limitata alla sola gestione di display a 7 segmenti, ma si presta a molte altre azioni.Ad esempio, vogliamo comandare 4 relè, collegati ai 4 bit di uscita del ricevitore a 8 pin. Con un dato a 4 bit possiamo ottenere l' azionamento di ogni singolo relè e di tutte le combinazioni possibili. Nella tabella le X indicano i relè attivati, ad esempio, secondo la seguente logica binaria:

Dato a 4 bit

Bit-relè

3

2

1

0

0

-

-

-

-

1

 

 

 

X

2

 

 

X

 

3

 

 

X

X

4

 

X

 

 

5

 

X

 

X

6

 

X

X

 

7

 

X

X

X

8

X

 

 

 

9

X

 

 

X

A

X

 

X

 

B

X

 

X

X

C

X

X

 

 

D

X

X

 

X

E

X

X

X

 

F

X

X

X

X

Per ottenere questo basterà modificare la lookup table:

; segment data table
segtbl
andlw 0x0F              ; solo nibble basso
           
addwf PCL,f            ; punta PC
                                                ;        RY4|RY3|RY2|RY1

           
retlw b'00000000' ; "0"  - | - | - | -
           
retlw b'00000001' ; "1"  - | - | - |on
           
retlw b'00000010' ; "2"  - | - |on | -
           
retlw b'00000011' ; "3"  - | - |on |on
           
retlw b'00000100' ; "4"  - |on | - | -
           
retlw b'00000101' ; "5"  - |on | - |on
           
retlw b'00000110' ; "6"  - |on |on | -
           
retlw b'00000111' ; "7"  - |on |on |on
           
retlw b'01111111' ; "8"  on| - | - | -
           
retlw b'01101111' ; "9"  on| - | - |on
           
retlw b'01110110' ; "A"  on| - |on | -
           
retlw b'00111000' ; "B"  on| - |on |on
           
retlw b'01110011' ; "C"  on|on | - | -
           
retlw b'01000000' ; "D"  on|on | - |on
           
retlw b'01100011' ; "E"  on|on |on | -
           
retlw b'00000000' ; "F"  on|on |on |on

Osserviamo l' utilità di una forma "grafica" ordinata, il che rende immediata la comparazione tra gli oggetti della lookup table e la tabella vista prima: mantenendo forma nel sorgente si facilita di gran lunga il lavoro.

La corrispondenza tra dato in ingresso e dato in uscita della lookup table è ampio: è possibile un elevato numero di altre combinazioni, come questa:

Dato a 4 bit

Bit-relè

3

2

1

0

0

 

 

 

 

1

 

 

 

X

2

 

 

X

 

3

 

 X

 

 

4

X

 

 

 

5

X

 

 

X

6

X

 

X

 

7

X

X

 

 

8

 

 

 

 

9

 

 

 

 

A

 

 

 

 

B

 

 

 

 

C

X

X

X

X

D

 

 

 

 

E

 

 

 

 

F

 

 

 

 

a cui corrisponde la seguente tabella:

; segment data table
segtbl
andlw 0x0F              ; solo nibble basso
           
addwf PCL,f            ; punta PC
                                                ;        RY4|RY3|RY2|RY1

           
retlw b'00000000' ; "0"  - | - | - | -
           
retlw b'00000001' ; "1"  - | - | - |on
           
retlw b'00000010' ; "2"  - | - |on | -
           
retlw b'00000100' ; "3"  - |on | - | -
           
retlw b'00001000' ; "4"  on| - | - | -
           
retlw b'00001001' ; "5"  on| - | - |on
           
retlw b'00001010' ; "6"  on| - |on | -
           
retlw b'00001100' ; "7"  on|on | - | -
           
retlw b'00000000' ; "8"  - | - | - | -
           
retlw b'00000000' ; "9"  - | - | - | -
           
retlw b'00000000' ; "A"  - | - | - | -
           
retlw b'00000000' ; "B"  - | - | - | -
           
retlw b'00001111' ; "C"  on|on |on |on 
           
retlw b'00000000' ; "D"  - | - | - | -
           
retlw b'00000000' ; "E"  - | - | - | -
           
retlw b'00000000' ; "F"  - | - | - | -

o qualsiasi delle altre combinazioni possibili.
L' elemento comune è costituito esclusivamente dalla necessità di limitare l' ampiezza della tabella al numero di righe che può indirizzare (nel nostro caso, 2^4).

Quindi, la corrispondenza 4 bit in ingresso- 4 bit in uscita è solo una delle possibilità. Con il PIC a 14 pin abbiamo visto che 7 uscite sono prontamente disponibili e il limite è solo quello ribadito prima; possiamo comandare 1, 2, 3, 4, 7 relè, sempre con 16 combinazioni. Ad esempio:

Dato a 4 bit

Bit-relè

7

6

5

4

3

2

1

0

 

 

 

 

 

 

 

1

 

 

 

 

 

 

X

2

 

 

 

 

 

X

 

3

 

 

 

 

X

 

 

4

 

 

 

X

 

 

 

5

 

 

X

 

 

 

 

6

 

X

 

 

 

 

 

7

X

 

 

 

 

 

 

8

X

 

 

 

 

 

X

9

X

 

 

 

 

X

 

A

X

 

 

 

X

 

 

B

X

 

 

X

 

 

 

C

X

 

X

 

 

 

 

D

X

X

 

 

 

 

 

E

 

 

 

 

 

 

 

F

X

X

X

X

X

X

X

a cui corrisponde la seguente tabella:

; segment data table
segtbl
andlw 0x0F              ; solo nibble basso
           
addwf PCL,f            ; punta PC
                                                ;        RY7|RY6|RY5|RY4|RY3|RY2|RY1

           
retlw b'00000000' ; "0"  - | - | - | - | - | - | -
           
retlw b'00000001' ; "1"  - | - | - | - | - | - |on
           
retlw b'00000010' ; "2"  - | - | - | - | - |on | -
           
retlw b'00000100' ; "3"  - | - | - | - |on | - | -
           
retlw b'00001000' ; "4"  - | - | - |on | - | - | -
           
retlw b'00010000' ; "5"  - | - |on | - | - | - | -
           
retlw b'00100000' ; "6"  - |on | - | - | - | - | -
           
retlw b'01000000' ; "7"  on| - | - | - | - | - | -
           
retlw b'01000001' ; "8"  on| - | - | - | - | - |on
           
retlw b'01000010' ; "9"  on| - | - | - | - |on | -
           
retlw b'01000100' ; "A"  on| - | - | - |on | - | -
           
retlw b'01001000' ; "B"  on| - | - |on | - | - | -
           
retlw b'01010000' ; "C"  on| - |on | - | - | - | -
           
retlw b'01100000' ; "D"  on|on | - | - | - | - | -
           
retlw b'00000000' ; "E"  - | - | - | - | - | - | -
           
retlw b'01111111' ; "F"  on|on |on |on |on |on |on

o così:

Dato a 4 bit

Bit-relè

7

6

5

4

3

2

1

0

 

 

 

 

 

 

 

1

 

 

 

 

 

 

X

2

 

 

 

 

 

X

 

3

 

 

 

 

X

 

 

4

 

 

 

X

 

 

 

5

 

 

X

 

 

 

 

6

 

X

 

 

 

 

 

7

X

 

 

 

 

 

 

8

 

 

 

 

 

 

 

9

 

 

 

 

 

 

 

A

 

 

 

 

 

 

 

B

 

 

 

 

 

 

 

C

 

 

 

 

 

 

 

D

X

X

X

X

X

X

X

E

 

 

 

 

 

 

 

F

 

 

 

 

 

 

 

a cui corrisponde la seguente tabella:

; segment data table
segtbl
andlw 0x0F              ; solo nibble basso
           
addwf PCL,f            ; punta PC
                                                ;        RY7|RY6|RY5|RY4|RY3|RY2|RY1

           
retlw b'00000000' ; "0"  - | - | - | - | - | - | -
           
retlw b'00000001' ; "1"  - | - | - | - | - | - |on
           
retlw b'00000010' ; "2"  - | - | - | - | - |on | -
           
retlw b'00000100' ; "3"  - | - | - | - |on | - | -
           
retlw b'00001000' ; "4"  - | - | - |on | - | - | -
           
retlw b'00010000' ; "5"  - | - |on | - | - | - | -
           
retlw b'00100000' ; "6"  - |on | - | - | - | - | -
           
retlw b'01000000' ; "7"  on| - | - | - | - | - | -
           
retlw b'00000000' ; "8"  - | - | - | - | - | - | -
           
retlw b'00000000' ; "9"  - | - | - | - | - | - | -
           
retlw b'00000000' ; "A"  - | - | - | - | - | - | -
           
retlw b'00000000' ; "B"  - | - | - | - | - | - | -
           
retlw b'00000000' ; "C"  - | - | - | - | - | - | -
           
retlw b'01111111' ; "D"  on|on |on |on |on |on |on
           
retlw b'00000000' ; "E"  - | - | - | - | - | - | -
           
retlw b'00000000' ; "F"  - | - | - | - | - | - | -

e qualsiasi altra combinazione nel limite complessivo di 16.

Così, con l' intermediazione di una lookup table adeguata, sarà possibile ottenere una vasta casistica di carichi, come lampade, relè, LED, ecc.
Ad esempio, posiamo comandare 15 uscite, una alla volta, con una posizione di off generale, ma anche 16 uscite, sempre una alla volta, o qualsiasi altra combinazione ammissibile nell’ ambito delle 16 uscite possibili dalla tabella (alimentata da 4 bit).

Dato a 4 bit

Bit-relè

15

14

13

12

11

10

  9

  8

  7

  6

  5

  4

  3

  2

  1

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

X

2

 

 

 

 

 

 

 

 

 

 

 

 

 

X

 

3

 

 

 

 

 

 

 

 

 

 

 

 

X

 

 

4

 

 

 

 

 

 

 

 

 

 

 

X

 

 

 

5

 

 

 

 

 

 

 

 

 

 

X

 

 

 

 

6

 

 

 

 

 

 

 

 

 

X

 

 

 

 

 

7

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

8

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

9

 

 

 

 

 

 

X

 

 

 

 

 

 

 

 

A

 

 

 

 

 

X

 

 

 

 

 

 

 

 

 

B

 

 

 

 

X

 

 

 

 

 

 

 

 

 

 

C

 

 

 

X

 

 

 

 

 

 

 

 

 

 

 

D

 

 

X

 

 

 

 

 

 

 

 

 

 

 

 

E

 

X

 

 

 

 

 

 

 

 

 

 

 

 

 

F

X

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Ovviamente in questo caso si rende necessario un chip che disponga di 20 pin:

Vdd/Vss  2
I/O per i relè 15
serial in 1
LED     1
non utilizzato oppure uscita 16    1

Ad esempio 16F527 o 16F677, ma anche 16F876/877 o 18F2321 o qualsiasi altro PIC con 20 pin o più.

Dovrebbe essere chiaro ora che con la trasmissione di soli 4 bit possiamo azionare ben più di 4 carichi in uscita.

La limitazione principale è quella delle 2^4 combinazioni in uscita, per aumentare le quali occorre aumentare il numero di bit trasmessi.

Per quanto riguarda l' interfaccia, niente di nuovo sotto il sole: soliti open collector/open drain o buffer integrati. Ad esempio, per 7 relè:


Lasciamo alla fantasia o alla necessità dei lettori lo studio di altre applicazioni.


Altre risorse.

 


 

         

Copyright © afg. Tutti i diritti riservati.
Aggiornato il 09/11/17.