Let's Go PIC terza parte |
|
Articolo pubblicato su www.grix.it
(primo in classifica a settembre 2010)
parte terza: Nuovo corso di programmazione C16 per PIC basato sul sistema di sviluppo Micro-GT PIC versatile IDE
Nell'immagine una bella realizzazione della Micro-GT PIC versatile I.D.E. sviluppata da Luca, affezionato utente di Grix che si e' procurato un esemplare del PCB
Microcontrollore di riferimento.
La famiglia di microcontrollori PIC è molto ampia
e a sua volta suddivisa in sottofamiglie delle quali si indica con un numero la
serie costruttiva, ad esempio 12, 16, 18, 32 ecc.
A seguito di questa prima cifra numerica c'è solitamente una lettera, ad esempio "C" o "F" la prima indicante la tecnologia CMOS e la seconda, di nostro diretto interesse, dato che operiamo in ambito di studio e sviluppo di prototipi, che indica la tecnologia "Flach", ovvero che contiene una area di eeprom in cui potremmo scrivere, cancellare, e riscrivere i programmi diverse migliaia di volte.
Alla lettera citata, segue una altro codice numerico che identifica il tipo di PIC, ad esempio 877, che è poi il prodotto di riferimento per i nostri eperimenti. Ovviamente potete usare un qualunque altro PIC riadattando di volta in volta quello che viene fornito negli esempi di programmazione.
Molti PIC altre a questi tre campi sigla, hanno anche una lettera, la "A" che sta ad indicare la revisione costruttiva del medesimo chip allo scopo di applicare le migliorie tecnologiche che si sono sviluppate nel corso degli anni, ecco che ad esempio potrete trovare un PIC16F877 come il PIC16F877A, che a causa delle tensioni necessarie per la programmazione, l'ampiezza delle aree di memoria e la velocità dell'area flasch o semplicemente del clock esterno, posso essere non pienamente supportati da alcuni programmer. Questa cosa dovrebbe essere risolta nei nuovi sistemi di sviluppo che dovrebbero, come nel caso della nostra Micro-GT PIC versatile IDE essere in grado di riconoscere e di flachare i PIC sia con la "A" che senza la "A".
Il PIC di riferimento per il nostro tutorial è il PIC16F877A , lasciando comunque ampia scelta agli utenti, in funzione di cosa trovano nei cassetti del proprio laboratorio.
Questo PIC per il
momento rappresenta il miglior compromesso performace/costo nonchè semplicità di
utilizzo/difficoltà di atrezzarsi per usarlo.
Bus interni.
Con il termine "Bus" si vuole intendere un insieme di linee parallele di numero dipendente dall'applicazione, atte al collegamento interno, ma in qualche caso anche esteso all'esterno del processore tramite appositi conettori e cavi piatti, in grado di collegare punti diversi, entrambi interni o misti interni/esterni allo scopo di trasferire parallelamente dei dati.
Solitamente un bus (si legge bas) trova origine o terminazione in "registri", ovvero aree di memoria temporanea per un singlo dato di estensione variabile.
In presenza di uno schema a blocchi
dell'architettura interna, i bus sono distinguibili in quanto disegnati con
linea simile a fascia larga e vuota, in qualche punto indicata con fascetta
trasversa con vicino un numero indicante di quante linee è formato il suddetto
bus.
I bus più noti sono:
L'estensione di questi bus corrisponde al numero chiaremente visibile sull'immagine dell'architettura interna.
Registri interni.
Il FLIP/FLOP è una nota configurazione circuitale in elettronica digitale, in grado di memorizzare una volta ricevuto il comando, un bit, e di trattenerlo fino al sopraggiungere del comando di reset.
I FLIP/FLOP possono essere interconessi tra di loro formando delle catene, più o meno lunghe assumendo il nome di registri.
I registri interni del PIC possono essere caricati a intera parola, da non confondere con word intesa come 16 bit, dato che in questo caso si intente la massima estensione del registro, oppure a singoli bit.
Quando di scrive su un registro di un pic lo si fa allo scopo di impostare particolari funzionaità, come ad esempio la velocità e il tipo di clock nel così detto registro dei fuse. La possibilità o meno di intervenire al timer di watchdog, nel medesimo registro.
Si impostano dei bit nel registro ADCON per abilitare o meno certe funzioni sui convertitori analogici digitali, si setta una configurazione di bit nei registri TRIS, come anche si scrive una configurazione nei registri PORT.
Quando si programma in assembly (con assembler si intende il compilatore e non il linguaggio che è appunto l'assembly), è di fondamentale utilizzo il registro di lavoro, indicato con working register, dove transitano gli operandi prima di atrare nell'unita di processo, la ALU (aritmetic logical unit) .
In "C" il workin register ha un ruolo apparentemente secondario dato che è gestito in trasparenza dal codice asemblato dal compilatore. E' già noto, a chi ha letto i precedenti capitoli, che l'unico formato accettabile ad essere trasferito nella memoria del PIC è il .hex che otteremo come risultato della compilazione tramite il compilatore online a Mp-Lab, prodotta dalla HITECH.
Come possimo notare dall'immagine sottostante, da
tutti i pin dello zoccolo textool, chimato anche ZIF (zero force insertion),
sono messi a disposizione per eventuali connessioni da e per il mondo esterno,
che chiameremo il bordo macchina.
Lo schema completo, disponibile in PDF oltre che in formato Eagle, è molto ampio , va quindi stampato in formato A3, ma una volta suddiviso in blocchi funzionali, risulta molto più "focalizzabile" in merito ad ogni argometo trattato.
Fintanto che l'utente non ha buona familiarità con il layout della scheda sarà possibile muoversi agevolmente tra le sue potenzialità solo con gli schemi alla mano. Risulta così un ottimo esercizio per i tecnici in fase di formazione, ad esempio nelle scuole.
La scheda necessita di alcune impostazioni di base, a seconda del PIC interessato. Nel nostro corso tenderemo ad usare il 16F877A e non A, o processori simili a 40 pin, quindi una volta impostata la scheda tenderemo a non spostare o a farlo in maniera minima i jumper e deep switch.
Gli utenti che intendessero usare sempre e solo questo microcontrollore potranno ad esempio non montare il quarzo da 4Mhz dato che questi usa quello da 20.
Per quanto riguarda il connettore ICSP, lascio come utile esercizio al lettore il cercare di volta in volta in quale dei numerosi pin degli streep line maschio disponibili scoprire dove vanno conessi i 5 fili colorati, ovviamnte si segue l'indicazione del software di programmazione come spiegato in precedenza.
connettore TEXTOOL detto anhe ZIF montato sulla Micro-GT PIC versatile I.D.E.
Gli ingressi digitali a bordo della Micro-GT sono tanti e ampiamente configuarbili. Lo schema elettrico è riportato nell'immagine successiva. Concetto base del controllo a microprocessore è che i segnali possono giungere ai pin di I/O sia in logica diretta che in logica negata, spesso con preferenza per la seconda opzione. In fase di Debug, come già accennato nel precedente capitolo di "Let's go pic!" è essenziale impostare a simulatore software, o hardware che sia, la corretta configurazione dei pulsanti o interruttori, ovvero normalmente aperti o normalmente chiusi.
Molte demoboard disponibili in internet non danno la grande potenzialità disponibile nella Micro-GT di poter configurare come pressato=0, mormale=1 oppure viceversa i pulsanti.
Questo è possibile, a gruppi di 4 pulsanti.
Osserviamo lo schema elettrico della sezione di ingressi digitali e focalizziamo l'attenzione sugli streep SV1 e SV2. La configurazione è progettata in modo che le medesime resistenze possa diventare pullup o pulldown a seconda che i jumper siano innestati sugli streep allineati tutti a sinistra o a destra.
Le configurazioni sono:
I pulsanti sono isolabili dallo ZIF tramite l'apertura dei deep switch, e sono prelevabili dalla scheda per essere portati ove sia necessario, anche bordo macchina tramite dei cavi flat innestabili nel corrispondente streep line maschio (ad esempio SV30 e analoghi per gli altri PORT). Analogamente, si potrà collegare il cavo flat a monte del del deep switch, ovvero dal lato ZIF, dando la possibilità di entrare o uscire con segnali verso il relativo PORT del PIC. Questa modalità l'ho indicata come "direct I/O".
Abbiamo quindi massima duttilità di utilizzo.
Nella foto vediamo i 16 streep configurabili "up/down" suddivisi a gruppi di 4. In ogni gruppo di 4 vanno innestati almeno 2 jumper, o allineati a destra o allineati a sinistra per non avere pin flottanti rispetto alla massa.
In alcuni casi dipendenti dal tipo di housing (alloggiamento del controllore, o meglio scatolina da 40, 28, 18 pin ecc) il pulsante di reset risulta spostato in pin diverso dal numero 1. (è indicato con MCLR negato dalla baretta che sovvrasta la scritta, ovvero attivo quando lancia al pin lo zero logico). Per questo motivo è stato inserito il jumper JP3, che in certi casi può anche portare semplicemente un segnale di alimentazione a specifici pin. Le casistiche sono davvero tante quindi il tecnico che utilizza questo sistema di sviluppo dovrà arrangiarsi quando si troverà davanti a un caso particolare. Sappiate che data la grande accessibilità ai pin, una soluzione c'è sempre. Bisogna studiarsi un pò l'hardware.
Hardware delle porte di I/O digitale.
Gli ingressi.
Facciamo una rapida analisi, ma non troppo superficiale del funzionamento delle porte quando configurate come digital I/O.
I Pin da 2 a 7, escluso il PIN 6, del processore di riferimento sono implementati internamente come rappresentato nello schema elettrico sovrastante. Facciamo una veloce analisi:
Il pin 6 del processore 16F877 ha una configurazione Hardware leggermente diversa rispetto ai pin del medesimo PORT A, il cui schema è già stato analizzato. In effetti a questo pin (il 6 nel processore di riferimento ma potrà avere un'altra posizione in modelli diversi) è abbinato al "segnali di clock in entrata per il timer hardware 0", in inglese "timer zero clock input" abbreviato "T0CKI".
Dal punto di vista dell'architettura questo punti di I/O differisce dagli altri per le seguenti cose:
Le uscite.
Le uscite digitali a bordo sono 24 e accessibili sia tramite "direct I/O" esattamente come spiegato per gli ingressi, che in modalità free port, ovvero portabili in campo tramite cavo flat innestato negli streep line predisposti, ad esempio SV18, SV22, SV23, ecc.
Nei casi in cui la simulazine LED on board desse fastidio è possibile isolare la linea agendo nel deep switch S13, relativo al PORTB,C,D. I segnali saranno disponibili in freeport ma il led non si accenderà.
Il PORTE è di solito riservato alle linee di controllo degli LCD, è infatti composto da sole tre linee e verrà spiegato nell'apposito capitolo del tutorial "Let's go PIC".
Nota importante:
benchè i PORT del PIC siano piuttosto robusti, arrivano a circa 20mA, corrente
più che sufficiente al giorno d'oggi per pilotare qualunque cosa, è importante
interfacciarsi comunque tramite transistor o comparatori operazionali, nonchè
optoisolare le sezioni di potenza.
I PORT B, C, D, E, hanno tutti delle caratteristiche aggiuntive o in meno rispetto a quella base, ma nella sostanza funzionanao alla stessa maniera.
Al PORT B è ad esempio abbinata l'importante funzione, abilitabile tramite impostazione del registro... dei pullup interni, che in qualche caso permette di sfruttare il mosfet interno come facente funzione della classica resistenza da 10K che solitamente "appendiamo" al segnale Vcc, o alla massa, al fine di non avere condizioni di segnale flottante prima dell'azione sul pulsante, spesso normalmente aperto (vedi Micro-GT) posto in serie ad essa.
La configurazione più stabile, e quindi da preferisi è, per quanto riguarda gli input digitali è "normale 1 -> comando 0" che si ottiene ad esempio con una resistenza di pullup con in serie un pulsante normalmente aperto. Il segnale prelevato dal centro di questa serie è portato direttamente al pin configuarto come ingresso.
I pin RB0 e RB3 hanno lo schema elettrico interno che vediamo nella figura sovrastante. La prima cosa che salta all'occhio è la presenza del segnale RBPU, attivo basso che come accenato, abilita la funzione di pullup interni (non disponibili nal PORT A). Tali pullup vengono automaticamente disabilitati quando la porta è commutata in uscita. La nota a piede dell'immagine chiarisce che esiste un diodo di ricircolo e di protezione, puntato verso Vdd che garantisce funzionamento. La presenza del TTL buffer, permette di non bruciare il punto di I/O nel momento in cui arrivano tensioni diverse dai 5V, come nel caso della programmazione. (questa questione sarà approfondita, per il momento prendiamola buona così).
RB0/INT è un ingresso che può acquisire un segnale di interrup, ovvero quello che lancia una routine di servizio mettendo per pochi cicli machina in attesa il programma in corso (tecnica della commutazione del contesto) dando l'impressione che siano in esecuzione contemporaneamente due compiti dati da svolgere al microcontrollore. L'abilitazione e la configurazione dell'interrupt ha questa sintassi INTDEG bit(OPTION_REG<6>) suggerita dal manuale di microchip, in realtà vedremo presto cme fare usando il C16.
I pin RB6 e RB7 sono invece delegati alla programmazione in circuit.
Quando si usa la modalità di programmazione seriale in circuito a bassa tensione ICSP tipo LVP e sono abilitati i pull-up interni, bisogna azzerare nel registro TRISB il pin RB3.
E' importante sapere che il PORT B non è il più adatto a funzionare in modalità multiplexig a causa della presenza nell'estensione dei suoi 8 bit di queste funzionalità aggiuntive.
E' più adatto al multiplexing e al polling il PORT C di cui riporto sotto lo schema elettrico relativo, come per A e B ad un solo pin.
Il PORT C contiene anche le porte seriali di comunicazione, e nei pin RB3 e RB4 è possibile abilitare il protocollo di comunicazione I2C.
Vedremo invece che la porta RS232C è collegabile ai pin RX-> RC7 e TX ->RC6.
Il PORT E, che possiede solo 3 punti di connessione, è predisposto per il protocollo PSP, parallel slave port, particolarmente indicato per la comunicazione tra due processori, ad esempio tra il nostro microcontroller e quello a bordo dei display LCD ad esempio a 2 righe per 16 caratteri, secondolo standard Hitachi.
Vedremo al momento opportuno come questo PORT E sia collegato al funzinamento del PORT D che con i suoi 8 bit può implemantare un efficace scambio di dati con le periferiche.
La programmazione inizia da qua.
Come creare un alias.
Quado il programma ha una certa estensione può diventare complesso o perlomeno scomodo usare i nome canonici dei punti di I/O, ad esempio RA2, RC3,RB0 ecc. pensiamo ad esempio a un programma in cui vengano citati un migliaio di volte e con la sequenza imposta dalla logica del programma. Vediamo ad esempio il seguente costrutto if:
if((RA0&&RA1)^RA2){ }
Se lo compilate all'interno di "main(){ }" (il corpo del main è dentro le parentesi graffe) la compilazione va a buon fine e viene creato un .hex, ma francamente è poco leggibile dato che le variabile sono anonime.
Lo stesso costrutto, rivisto secondo gli alias assume il seguente aspetto, palesemente più significativo:
if ((start && no_allarme) ^ bypass_OK) { }
Il programma esegue il corpo dell' IF, ad esempio l'avvio di una macchina industriale, "se" (if = se) (è stato premuto il comando di start "&&" ( and, signica "e anche"), oppurè presente un segnale di consenso prioritario, che bypassa le prime due condizioni, ("oppure" ^ = or logico)
Notevolmente più leggibile !!!
Rimane il problema su come impostare questi alias. La sintassi è la seguente:
#define start RA0
Notiamo che la riga non è chiusa con il terminatore standard dell'ansi C, ovvero il " ; " questo è possbile perchè il costrutto "#" (leggasi "number") seguito dal costrutto "define" abbina la label (etichetta) seguente al punto di I/O, d esempio RA0 che termina la riga di comando.
Nell'immagine sovrastante vediamo il risultato di una compilazione su piattaforma MP-Lab e compilatore Hitech "C16", ovvero l'universal tool suite che è lo strumento ufficiale della casa costruttrice.
Ho compattato le finestre per ragioni di spazio, ma in alto a sinistra abbiamo l'albero del progetto, in basso a sinistra il programma minimale che esegue solo un alias suk pin RA0 il quale assume il nome "start", dato che probabilmente a bordo macchina è il pulsante di avvio, e lo manterrà per tutto il programma.
Nella colonna di destra vediamo la finestra del "sommmario" della compilazione. Ci addentreremo di più nelle pubblicazioni future di "Let's go PIC". Per il momento accenniamo al fatto che ci mostra la gestione delle aree di memoria e, fondamentale, se la compilazione è andata o no a buon fine. Vediamo nel nostro esempio la scritta ***Build successful ! ***, che auguro a tutti di vedere sempre o perlomeno il più frequentemente possibile.
--------------------------------------------------------------------
Esercizio: Creazione dell'alias.
Copia il sorgente qui sotto e incollalo su un file notepad di windows. Salvalo con nome "definizione.c" poi leggi la prima edizione di "Let's go PIC !" e crea un progetto "definizione.mcw". Esegui la compilazione fino ad ottenere il file "definizione.hex"
#include <pic.h>
#define start RA0 //implementa l'alias
void main(){
if((RA0&&RA1)^RA2){
}
}
----------------------------------------------------------------------
Attenzione: Durante lo svolgimento ell'esercizio potrai incontrare dei problemi con le estensioni dei file, in modo particolare quando li crei con notepad anziche con l'editor Hitech integrato in MP-Lab. Risolvi la questione aditando le proprietà della cartella che contiene il file e togliendo l'opzione, in proprietà cartella, nascondi estensione file. Se non fate questo potesre avere l'impressione che un file prova.c abbia in realtà la doppia estensione nascosta prova.c.txt che vi farà impazzire con errori strani di compilazione e conseunete non creazione del file .hex a noi essenziale per flaschare il PIC.
Ricompila il programma definendo RA1 come FTC (che indica una fotocellula) e RA2 con il nome bypass.
Come possimo notare la programmazione che utilizza gli alias è molto più elegante di quella con indirizzi reali, e tutto sommato aggiunge semplicità e leggibilità al codice sorgente. Una volta presa mano non ne potrete più fare a meno.
non proseguite la lettura se prima non siete riusciti a portare a buon fine questo esercizio.
----------------------------------------------------------------------
L'antirimbalzo software.
I contatti meccanici, diversamente di quelli allo stato solido simulati con transistor o mosfet, sono sogetti a inerzie e ancor peggio a reazioni elastiche che si riassumo in "rimbalzi" in fase di chiusura.
Se la lettura di questo segnale di input fosse molto rapida, la curva di elongazione e successive oscillazioni smorzate possono essere interpretat come commutazioni dello stato logico, trasformado l'mmagine del gradino di heviside in un pettine di impulsi rapidi in grado di generare istabilità all'automazione.
Dal punto di vista elettrico la cosa è risolvibile ponendo un piccolo condensatore, qualche decina di picofard, in parallelo al contatto che si porta in chiuso. Questi, avendo funzione di filtro passa basso, cortocircuita a massa le armoniche ad alte frequenza del fenomeno, smorzando o eliminando le elongazioni e le successive oscillazioni di assestamento.
Dopo il transitorio il condensatore si troverà carico alla tensione del segnale logico risultando quindo trasparente. Viene introdotta una incertenzza di stato in fase di apertura che dipenderà dalla velocità di scarica del condensatore, anche se la curva essendo molto rapida potrà assomiliare fortemente a una rampa. Non sarà comunque mai identica al fronte di discesa del gradino in "spegnimento" (transizione ON -> OFF del segnale logico).
La questione dei rimbalzi può essere gestita anche via software eseguendo una sorta di controllo sulla "permaneza alta" del segnale che si è presentato per un tempo breve ma comunque presente dopo il rilevamento della prima presenza.
Ovvero: Chiudo il contatto e ne rilevo la presenza tramirte il costrutto IF, ma non ne consento subito l'effetto. Lascio passare un tempo che stimo essere quello necessario a stabilizzare i rimbalzi, verifico se il segnale è ancora presente.
Se dopo questa sorta di "filtro" il segnale è presente allora lo lascio passare consentendone l'effetto.
il trucco è:
Vediamo l'esempio ed eseguiamo il secondo esercizio.
/**************************************************
* Let's GO PIC: *
* 8 settembre 2010 *
* Acquisizione con antirimbalzo "bozza" *
* piattaforma Micro-GT PIC versatile I.D.E. *
* Marco Gottardo *
**************************************************/
#include<pic.h>
#include<delay.h>
#define pulsante RA0
#define spia RB0
void main(){
TRISA=0xFF;
TRISB=0;
while(1){
if (pulsante==1){
DelayMs(10);
if (pulsante==1){
spia=1;
}
}
}
}
Nell'immagine vediamo l'ambinete di programmazione e la compilazione andata a buon fine. A questo punto sarete molto felici e contenti dato che tutto è segnalato, parole testuali del compilatore, come build successfull !, ....ma...
qualcosa non va. Prima di Leggere il seguito vi invito, a titolo di esercizio complementare al presente, di provare a ragionare su cosa sto cercando si segnalarvi come non trascurabile anomalia.
Il programma è sintatticamente corretto ma ha un grave difetto funzionale. Se avete letto attentamente la parte introduttiva che riguarda l' hardware delle porte di I/O non vi sarà infatti sfuggito il fatto che esse sono implementate (signica eseguite o costruite) tramite dei Flip/Flop e quindi c'è un effetto memoria. Questo effetto memoria è noto in elettronica digitale come "Latch" (tradotto letteralmente chiavistello o serratura). Al lato pratico rende stabile in uscita quello che sarebbe un impulso monostabile in imput.
Testate il programma con RealPic simulator, tenendo presente che nella sezione visual dovete disporre un pulsante abbinato a un pulsante all'indirizzo RA0, impostato come normal -> 0, pressed -> 1 (agite con il tasto destro sul tab di settaggio del box pulsante), mentre in uscita metterete un LED abbinato a RB0.
Vediamo l'esempio ed eseguiamo il terzo esercizio.
/**************************************************
* Let's GO PIC: *
* 9 settembre 2010 *
* Acquisizione con antirimbalzo *
* piattaforma Micro-GT PIC versatile I.D.E. *
* Marco Gottardo *
**************************************************/
#include <pic.h>
#include <delay.h>
#define pulsante RA0
#define spia RB0
void main(){
TRISA=0xFF; //imposta come ingressi tutto il PORT A
TRISB=0; //imposta come uscita tutto il PORT B
while(1){ //inizio del ciclo infinito
if (pulsante==1){ //test della condizione di comando
DelayMs(10);
if (pulsante==1){
spia=1; //accende uscita
}
}
if (pulsante==0){ //test della condizione negata
DelayMs(10);
if (pulsante==0){
spia=0; //spegne uscita
}
}
}
}
Dal sottostante link puoi scaricare uno zip contenente, le librerie delay.h e delay.c, il sorgente definizione.c e due file .hex, il primo serve per capire che se non si mette il comando antagonista ovvero di spegnimento del punto di I/O l bit resta latch-ato (che brutto temine, non usatelo mai). Il secondo è invece la versione completa ovvero il compilato del sorgente sovrastante. Fate questo utile esercizio, caricate prima uno e poi l'altro nel simulatore "RealPIC simulator" come spiegato nel primo tempo del tutorial, e confronatate gli effetti.
UserFiles/ad.noctis/definizione.zip
Giochiamo con le uscite.
Benchè nel paragrafo precedente si siano citate le uscite digitali, dato che alla pressione di un tasto collegato all'ingresso abbiamo acceso il LED collegato a RB0, ciò era molto poco rispetto a cosa si aspetta un lettore un pò più esperto riguardo all'uso delle uscite digitali.
Come precedentemente spiegato, i PORT, quando configurati come uscite tramite la corretta parametrizzazione del registro TRIS, hanno scopi simili, non identici.
Abbiamo detto che alcuni sono più adatti a pilotare gli LCD, altri sono prediposti per certi tipi di segnale, alcuni sono open drain, ecc. ecc. dipenderà fortemente dal modello che useremo.
Abbiamo anche detto che una ventina di milliampere gli possiamo tirare fuori o drenare negli I/O digitali, quindio non dovremmo avere paura di collegare direttamente un display LED, se abbiamo porte disponibili ovviamente, e non sarà uno spreco dato che questo ci permetterà di eliminare il chip di decodifica, cosa che ho preferito non fare nella Micro-GT la quale monta a bordo un decoder BCD-7seg tipo CD4511.
E' di dovere cominciare a prendere confidenza con le uscite con le esperienze classiche ...segue il coro dei veterani che comunque hanno deciso di leggermi....NOOOOOOO !!! SUPERCAR NOOO!!!!!
Ma che ci posso fare io? è un passaggio obbligato, e al dire il vero anche molto richiesto e gettonato sopratutto dai ragazzi nella fascia di età a cui insegno a scuola.
Facciamo così.... dato che insegno da molti anni anche nella formazione aziendale, quindi anche a persone che è già uscita dall'università, accontentiamo prima loro, e poi facciamo contenti i miei ragazzi con il tante ambito SUPERCAR.
Esercizio numero 4.
La scheda Micro-GT, integra un decoder BCD-7segmenti LED pilotata dal circuito integrato CD4511. Questo integrato accetta su 4 linee di ingresso il codice BCD e lo decodifica nelle combinazioni necessarie ad accendere i segmenti del display in maniera corrispondente, ecco ad esempio che se gli presentate la combinazione 0011 lui imposterà le sue linee di uscita in modo compatibile all'accesione del numero 3, se gli proponiamo la combinazione 0100 lui decodifica sulle 7 linee una combinazione tale da accendere il numero 4, e così via per le cifre da 0 a 9. Le altre 6 combinazioni disponibili, infatti 24=16, come previsto dall'algebra combinatoria, sono dette rindondanti, ovvero prive di significato. Gli esperti potranno sfruttare queste combinazione per inviare in un bus condiviso dei segnali di controllo o informazioni "criptatate". o meglio trasparenti al display che le lascerà passare senza accendersi.
Clicca sul link per avere la documentazione tecnica dell'integrato CD4511.
http://www.gtronic.it/energiaingioco/it/scienza/Micro-GT%20PIC_ultimate/CD4511%20e%20equivalenti.pdf
L'esercizio che propongo è abbastanza semplice, ma fortemente applicativo. Nella mia filosofia infatti è basilare la semplicità sopratutto in fase di apprendimento. Non nascondo che per un esperto questi programmini sono sulla soglia del ridicolo, ma come si dice dalle mie parti, nel Veneto, Nessuno nasce imparato... IO PER PRIMO.
schema elettrico della sezione display 7 segmenti della Micro-GT PIC versatile I.D.E.
Lo schema parla molto chiaro, i 4 display sono a catodo comune il quale viene conesso alla massa, dando la possibilità alla corrente di segmento di accendere il medesimo tramite un "interuttore elettronico", realizzato con un BJT di tipo BC337, classico transistor per segnale, NPN come si vede nello schema. Le resistenze R8,R9,R10,R11, limitano la RB al valore sufficiente a fare saturare il componente. In questa condizione la caduta di tensione tra collettore ed emettitore è prossima allo zero (a parte un piccolo residuo pari a circa 0,2V) e si comporta di conseguenza come un interruttore. A monte delle resistenze di base ci sono le 4 conessioni disponibili sia in modalità freeport, ovvero collegando al PORT che vogliamo tramite un cavo flat, oppure semplicemente chiudendo il deepswitch accettando la conessione del bus al PORT che ho scelto in fase di progettazione, e vincoladovi al pilotare via software quello specifico PORT. (vedi schemi elettrici)
Se usiamo il bus conesso di default l'accensione del display avviene solo abilitando le linee del bus agendo sul deep SV26.
Le linee di controllo, ovvero le basi dei transistor, e le line dati che vanno al decodificatore BCD/7 segmenti sono ulteriomente separati su due streep line maschi indicati nella serigrafia con SV19 (linea dati) e SV20 (linea controllo accensione).
Anche i punti decimali, se fossimo interessati ad accenderli sono disponibili nella modalità freeport, quindi tramite cavetto flat e chiudendo nel deep S25 le vie di interesse.
Nota importante: Se sviluppate una demoboard con lo schema che vi ho fornito sopra ricordatevi di conettere le masse alla massa della vostra mainbord, ovvero quella in cui avete il processore, altrimenti non si accende nulla.
La sezione interessata si trova nell'area indicata con il rettangolo rosa nella foto della Micro-GT PIC riportata qui sotto.
sezione del display a 7 segmenti della Micro-GT PIC versatile I.D.E.
testo dell'esercizio.
Alla pressione di un tasto vogliamo accendere a display il numero corrispondente, ad esempio tasto 1 sul display compare 1, tasto 2 sul display compare 2, ecc.
Soluzione
/**********************************************************************
* Let's GO PIC !! 9 settembre 2010 *
* Marco
Gottardo *
* MICRO-GT PIC versatile I.D.E.
*
* programma di selezione
numerica *
* abbina il tasto numero n al display numero n che visualizza n *
**********************************************************************/
// imposta la frequenza del quarzo
#define XTAL_FREQ 20MHZ
#include <pic.h>
//fuse di configurazione
__CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS &
UNPROTECT);
#include <delay.h>
#include "setting.h"
//programma di test dell'interrupt
void main(void){
settings();
while(1){
if(P1==0){
DelayMs(10);//ritardo
if(P1==0){
PORTC=disp1;
PORTB=1;
}
}
if(P2==0){
DelayMs(10);//ritardo
if(P2==0){
PORTC=disp2;
PORTB=2;
}
}
if(P3==0){
DelayMs(10);//ritardo
if(P3==0){
PORTC=disp3;
PORTB=4;
}
}
if(P4==0){
DelayMs(10);//ritardo
if(P4==0){
PORTC=disp4;
PORTB=8;
}
}
}
}
Questo programma contiene già molti punti di discussione. Ad esempio la riga di codice:
__CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS & UNPROTECT);
La incontriamo per la prima volta. Questa imposta il registro dei FUSE che sono settaggi indispensabili per il corretto funzionamento del PIC. La riga inizia con due "underscore" che l'editor unisce dando l'impressione che sia uno, dopodichè ogniuno degli elemnti separati da una "&" corrispondono ad un BIT che abilita o disabilita una funzione, chiamiamola di sistema.
vediamo ad esempio i primi due: HS e WDTDIS. sono rispettivamente l'impostazione dell'ardware interno in modo che possa accetatre un quarzo esterno ad alta velocità, higt speed, e la "DIS" ovevro disabilitazione del "WDT" il famoso watchdog timer. Do solo un breve accenno al fatto che questo timer viene resettato in automatico ogni volta che il contatore di programma passa per la prima riga di codice. Se il timer dovesse scadere prima di un successivo riavvio significa che il processore e quindi ilprogramma è impallato, e quindi non piu in grado di rispondere alle sollecitazioni o stimili sulle sue terminazioni di I/O. In questo caso l'intervento del WDT blocca tutto il sistema per evitare i gravi davvi che una automazione può fare quando è privo di "controllo".
Il registro dei FUSE, il loro approfondimento e uso merita un capitolo specifico del nostro tutorial "Let's go PIC". Appena ho un momento libero ci lavoro un po.
Se questa riga non è inserita nel codice sorgente allora è possibile impostare i fuse direttamente dal software di sviluppo.
dal menu 'configuration' di MP-Lab richiamare 'bits di configurazione'. compare il seguente box di impostazioni.
A questo punto facciamoci una domanda: Perchè impostare i fuse sul codice dato che lopossiamo fare sternamente sul software di sviluppo?
Risposta: Esiste
una startegia software che permette l'iserimento del microcodice, ovvero dell'hex
all'interno del PIC senza utilizzare ne il software di programmazione e sviluppo
(ad esempio MP-Lab), ne una scheda di sviluppo ma semplicemente una sheda
"target" che ovviamente metta almeno a disposizione le porte di cominicazione.
Questa modalità di flachare il PIC non richiede neppure l'alta tensione (i 13,2V che mette a disposizione la Micro-GT) perchè il tutto avviene in modalità bassa tensione, ovvero quella che è già disponibile per alimentare il PIC, guardiamo ad esempio la quinta voce sull'immagine "configuartion bits"sovrastante.
Dedicherò un capitolo del tutorial alla programazzione tramite bootloader. per il moemnto è meglio non deviare troppo dal focus ell'articolo che sono i digital I/O.
Quando il codice diventa molto articolato è bene sfruttare la capacità del "C" di essere suddiviso in moduli esterni successivamente linkati all'interno di un unico file prima di essere assemblato.
La direttiva di #include è utilizzabile oltre che per i file di libreria anche per eventuali moduli esterni del nostro programma, sia essi di intestazione "header" salvati con estensione .h, oppure veri e propri sorgenti contenti dei metodi e funzioni salvati .C
Nella filosofia di programmazione del "C" i file header (.h) contengono i prototipi e le definizioni di eventuali comandi non di libreria.
Ecco il sorgente del modulo esterno setting.h
----------------------------------------------------------------------------------------------
//programma base sviluppato per 16F877A
// chiudere i canali del DIP SW1 da 5 a 8
// aprire i canali del DIP SW1 da 1 a 4
// collegare con cavo flat a 4 conduttori lo streap SW19 con SW22
// gli ingressi del decoder CD4511 corrispondono a:
// A -> RC0
// B -> RC1
// C -> RC2
// D -> RC3
#define A RC0 // -> pin 15
#define B RC1 // -> pin 16
#define C RC2 // -> pin 17
#define D RC3 // -> pin 18
#define digit4 RB0 //pin
33 (LSB) cifra piu a destra
#define digit1 RB1 //pin 34
#define digit2 RB2 //pin 35
#define digit3 RB3 //pin 36 (MSB) cifra piu a sinistra
//pulsanti normal=1,
pressed=0
//usare pull-up da 10Kohm
//SV2 con jumper allineati a destra
//il PORTA viene commutato in ingresso
#define P1 RA0 //comanda
scrittura (1) su digit 1
#define P2 RA1 //comanda scrittura (2) su digit 2
#define P3 RA2 //comanda scrittura (3) su digit 3
#define P4 RA3 //comanda scrittura (4) su digit 4
char disp1=1; //usate nella funzione scriviBUS nel modulo writeBUS
char disp2=2;
char disp3=3;
char disp4=4;
void settings(void){
TRISA=0xFF;
TRISB=0;
TRISC=0;
TRISD=0;
TRISE=0;
}
-------------------------------------------------------------------------------------
Da questo link potete scaricare la soluzione di questo esercizio:
UserFiles/ad.noctis/select_number(11).zip
Seconda versione:
Vogliamo eseguire un ciclo automatico di visualizzazione dei numeri a diplay. Ogni digit viene multiplexato
/*******************************************************************************
* MICRO-GT PIC versatile I.D.E.
*
* programma di selezione
numerica *
* versione sia automatica che
manuale *
* abbina il tasto numero n al display numero n che visualizza n *
*nel funzionamento automatico premendo P5 genera il numero a 1Hz *
*******************************************************************************/
// imposta la frequenza del quarzo
#define XTAL_FREQ 20MHZ
#include <pic.h>
//fuse di configurazione
__CONFIG (HS & WDTDIS & PWRTEN & BORDIS & LVPDIS & DUNPROT & WRTEN & DEBUGDIS &
UNPROTECT);
#include <delay.h>
#include "setting.h"
void main(void){
settings();
while(1){
if(P1==0){
DelayMs(10);//ritardo
if(P1==0){
PORTC=disp1;
PORTB=1;
}
}
if(P2==0){
DelayMs(10);//ritardo
if(P2==0){
PORTC=disp2;
PORTB=2;
}
}
if(P3==0){
DelayMs(10);//ritardo
if(P3==0){
PORTC=disp3;
PORTB=4;
}
}
if(P4==0){
DelayMs(10);//ritardo
if(P4==0){
PORTC=disp4;
PORTB=8;
}
}
if(P5==0){
DelayMs(10);//ritardo
while(P5==0){
//if(P5==0){
PORTC=disp1;
PORTB=1;
DelayMs(200);
PORTC=disp2;
PORTB=2;
DelayMs(200);
PORTC=disp3;
PORTB=4;
DelayMs(200);
PORTC=disp4;
PORTB=8;
DelayMs(200);
//}
}
}
}
}
-------------------------------------------------------------------
il sorgente successivo è il setting.h, specifico per questa versione automatica e per la scheda Micro-GT PIC. per accendere correttamente i display dovete fare in modo che i segnali viaggino correttamente lungo i bus abilitano i deepswitch e settando gli opportuni jumper.
Il da farsi è indicato a commento, ovvero dopo il doppio slach "//" sulle prime righe el file setting .h che vedete qui sotto.
Lasciate pure queste righe di commento all'interno del file. saranno molto utili.
--------------------------------------------------------------------
//programma base
sviluppato per 16F877A
// chiudere i canali del DIP SW1 da 5 a 8
// aprire i canali del DIP SW1 da 1 a 4
// collegare con cavo flat a 4 conduttori lo streap SW19 con SW22
// gli ingressi del decoder CD4511 corrispondono a:
// A -> RC0
// B -> RC1
// C -> RC2
// D -> RC3
#define A RC0 // -> pin 15
#define B RC1 // -> pin 16
#define C RC2 // -> pin 17
#define D RC3 // -> pin 18
#define digit4 RB0 //pin 33 (LSB) cifra piu a destra
#define digit1 RB1 //pin 34
#define digit2 RB2 //pin 35
#define digit3 RB3 //pin 36 (MSB) cifra piu a sinistra
//pulsanti normal=1, pressed=0
//usare pull-up da 10Kohm
//SV2 con jumper allineati a destra
//il PORTA viene commutato in ingresso
#define P1 RA0 //comanda scrittura (1) su digit 1
#define P2 RA1 //comanda scrittura (2) su digit 2
#define P3 RA2 //comanda scrittura (3) su digit 3
#define P4 RA3 //comanda scrittura (4) su digit 4
#define P5 RA4 //comanda ciclo di loop su digit 1-2-3-4
char disp1=1; //usate nella funzione scriviBUS nel modulo writeBUS
char disp2=2;
char disp3=3;
char disp4=4;
void settings(void){
TRISA=0xFF;
TRISB=0;
TRISC=0;
TRISD=0;
TRISE=0;
}
------------------------------------------------------
Questo programma include un secondo file di intestazione che chiamerete writebus.h il cui sorgente è qui sotto. Esso contiene solo la funzione di scrittura sul port e quindi l'ivio dei dati al decodificatore CD4511 della scheda di sviluppo.
--------------------------------------------------------
void scriviBUS(){
if (PORTB==0b0001){
}
if (PORTB==0b0010){
}
if (PORTB==0b0100){
}
if (PORTB==0b1000){
}
PORTC=disp1;
}
------------------------------------------------------
In definitiva la versione automatica della scittura dei numeri sul dislay a 7 segmenti si compone di tre file:
ai quali aggiungo il quarto, il file:
select_number_auto.hex
che troverete nel file zippato scaricabile qua qua:
UserFiles/ad.noctis/select_number_auto.zip
Nella foto un particolare delle morsettiere per il collegamento del motore passo situato proprio sopra al diplay a sette segmenti usato in questi esercizi.
Appendice:
Effetto luci supercar: L'hello world di chi inizia con i PIC.
Come promesso cercherò ora di fare contenti i principianti con qualche variante del classico esercizio "supercar". Chi è già esperto potrà saltare a piè pari questo paragrafo, anche perchè, come ben sappiamo, la programmazione con le routine delay in line è sbagliata di concetto, dato che il processore è messo in attesa che scada un tempo e nel frattempo non è attento a cosa avviene nella sua periferia. Accenniamo, ma approfondiremo in un seccessivo capitolo che nella normalità delle cose il processore deve poter essere "interrotto" dal suo task per poter eseguirne uno priotario con la tecnica detta dell'interrupt.
Credo che un principiante possa sicuramente afferrare il concetto ma non credo sia in grado di sviluppare un programma o anche solamente di gestirene uno già fatto.
Andiamo quindi per gradi ed una volta acquisita l'esperienza necessaria tutto verrà affrontato con maggior serenità.
Programma supercar per principianti:
Microcontrollore 16F877A, siatema di sviluppo Micro-GT PIC versatile I.D.E.
Selezionare il clock a 20Mhz con gli appositi jumper (vedi schemi elettrici).
Abilitare il PORTB eil PORTC agendo sui deepswitch corrispondenti.
Impostare i pulsanti come normalmenti aperti, ovvero normali ->0, pressati ->1. Se realizzate il sistema reale saranno quindi "interruttori normalmente aperti con resistente di pulldown.
Se usate lampade di potenza ricordatevi di pilotare i triac con gli opportuni optoisolatori.
Scaricate il file hex che ho messo a disposizione e testatelo con Realpic simulator (vedere la prima parte di let's go pic per la spiegazione più accurata.
Data la natura didattica di questo semplice programma non mi assumo nessuna responsabile per il suo eventuale uso al di fuori di questo ambito, del sersto ho anche chiaramente dettio che il metodo di programmazione con le routine di delay inline è sbagliato di concetto. Programmi analoghi vanno sviluppati con la tecnica dell'interrupt.
Ecco il codice sorgente:
/*************************************************************************
* Let's GO PIC: gestione digital
I/O *
* sviluppato per Micro-GT PIC versatile I.D.E. *
* 13 settembre 2010: Marco Gottardo *
* Impostare correttamente i jumper sulla demoboard *
* Gli ingressi sono bistabili (interruttori N.A.)
*
*
*
* effetti
disponibili:
*
* car1 -> effetto supercar al PORT B *
* car2 -> effetto superca al PORT C *
* car1_2 -> effetto superca dal PORTB prosegue sul PORTC *
*
*
*************************************************************************/
#include <pic.h>
#include <delay.h>
#define car1
RA0
#define car2 RA1
#define car1_2 RA2
#define stop RA3
void main(){
TRISA=0x3F; //6 bit della porta A configurati come ingressi
TRISB=0; //tutta la porta B in uscita
TRISC=0; //tutta la porta C in uscita
PORTB=0b00000000; //inizializza B la porta tutta spenta
PORTC=0b00000000; //inizializza C la porta tutta spenta
while(1){
if (car1==1){ //effetto supercar al PORT B
PORTC=0b00000000; //azzera il port non in uso
PORTB=0b00000001;
DelayMs(255);
PORTB=0b00000010;
DelayMs(255);
PORTB=0b00000100;
DelayMs(255);
PORTB=0b00001000;
DelayMs(255);
PORTB=0b00010000;
DelayMs(255);
PORTB=0b00100000;
DelayMs(255);
PORTB=0b01000000;
DelayMs(255);
PORTB=0b10000000;
DelayMs(255);
PORTB=0b01000000;
DelayMs(255);
PORTB=0b00100000;
DelayMs(255);
PORTB=0b00010000;
DelayMs(255);
PORTB=0b00001000;
DelayMs(255);
PORTB=0b00000100;
DelayMs(255);
PORTB=0b00000010;
DelayMs(255);
}
if (car2==1){//effetto supercar al PORT C
PORTB=0b00000000; //azzera il port non in uso
PORTC=0b00000001;
DelayMs(255);
PORTC=0b00000010;
DelayMs(255);
PORTC=0b00000100;
DelayMs(255);
PORTC=0b00001000;
DelayMs(255);
PORTC=0b00010000;
DelayMs(255);
PORTC=0b00100000;
DelayMs(255);
PORTC=0b01000000;
DelayMs(255);
PORTC=0b10000000;
DelayMs(255);
PORTC=0b01000000;
DelayMs(255);
PORTC=0b00100000;
DelayMs(255);
PORTC=0b00010000;
DelayMs(255);
PORTC=0b00001000;
DelayMs(255);
PORTC=0b00000100;
DelayMs(255);
PORTC=0b00000010;
DelayMs(255);
}
if (car1_2==1){//effetto lungo dal PORT B prosegue sul PORTC
PORTB=0b00000001;
DelayMs(255);
PORTB=0b00000010;
DelayMs(255);
PORTB=0b00000100;
DelayMs(255);
PORTB=0b00001000;
DelayMs(255);
PORTB=0b00010000;
DelayMs(255);
PORTB=0b00100000;
DelayMs(255);
PORTB=0b01000000;
DelayMs(255);
PORTB=0b10000000;
DelayMs(255);
PORTB=0b00000000; //pulisce portB per continuare su C
PORTC=0b00000001;
DelayMs(255);
PORTC=0b00000010;
DelayMs(255);
PORTC=0b00000100;
DelayMs(255);
PORTC=0b00001000;
DelayMs(255);
PORTC=0b00010000;
DelayMs(255);
PORTC=0b00100000;
DelayMs(255);
PORTC=0b01000000;
DelayMs(255);
PORTC=0b10000000;
DelayMs(255);
PORTC=0b01000000;
DelayMs(255);
PORTC=0b00100000;
DelayMs(255);
PORTC=0b00010000;
DelayMs(255);
PORTC=0b00001000;
DelayMs(255);
PORTC=0b00000100;
DelayMs(255);
PORTC=0b00000010;
DelayMs(255);
PORTC=0b00000001;
DelayMs(255);
PORTC=0b00000000;//pulisce effetto memoria al portC
PORTB=0b10000000;
DelayMs(255);
PORTB=0b01000000;
DelayMs(255);
PORTB=0b00100000;
DelayMs(255);
PORTB=0b00010000;
DelayMs(255);
PORTB=0b00001000;
DelayMs(255);
PORTB=0b00000100;
DelayMs(255);
PORTB=0b00000010;
DelayMs(255);
PORTB=0b00000001;
DelayMs(255);
}
if (car1==0){
PORTB=0b00000000; //pulisce memoria, porta B tutta spenta
}
if (car2==0){
PORTC=0b00000000; //pulisce memoria, porta C tutta spenta
}
}
}
----------------------------------------------------------------------------------------------------------------------------
scarica da questo link il programma completo con il file .hex da provare sul simulature e da flaschare nel PIC.
Contiene anche le librerie delay.h e delay.c da copiare nella directory include edl compilatore.
UserFiles/ad.noctis/File/supercar_MicroGT.zip
-----------------------------------------------------------------------------------------------------------------------------
This opera is licensed under a
Creative Commons Attribution-NonCommercial-ShareAlike 2.5 Italy License.