Visualizzazione post con etichetta 18f. Mostra tutti i post
Visualizzazione post con etichetta 18f. Mostra tutti i post

domenica 22 marzo 2015

Studio PIC 18F (18F4431) #8 :: "Comunicare con il PIC via i2c (pic slave, raspberry pi master)"


Vai al precedente POST della serie

Il protocollo i2c (Inter Integrated Circuit), inventato da Philips nel lontano 1982, permette, con solo due connessioni (più la massa), la comunicazione bidirezionale tre due o più dispositivi.
In rete troviamo ovviamente ampia documentazione in merito ma non sempre troviamo chiare indicazioni per implementarlo con successo con i PIC.

In questo articolo vediamo come poter controllare il nostro PIC, via i2c, da qualsiasi altro dispositivo esterno che possa comportarsi da MASTER.
L'i2c infatti prevede, per i dispositivi connessi, due ruoli: il MASTER (padrone) e lo SLAVE (servo).

Entrambi possono ricevere e inviare i dati ma solo il MASTER inizia il dialogo e decide la frequenza di lavoro generando il segnale di sincronismo del BUS.

Il BUS è composto da soli due segnali o linee : la linea di clock (SCL) e quella di dati (SDA).
Sul BUS possono coesistere fino a 127 dispositivi SLAVE in quanto il protocollo prevede di poter assegnare ad ogni dispositivo SLAVE un proprio indirizzo (ADDR): sarà il MASTER a decidere con chi parlare ogni volta che vuole inviare o ricevere dei dati.

E' anche possibile che uno SLAVE possa diventare MASTER occupando il BUS in modo da poter a sua volta dialogare con un altro SLAVE: questa modalità però non è oggetto del presente articolo.

Quindi, riassumendo, il protocollo i2c:
  1. è di tipo sincrono (linea SCL)
  2. permette il colloquio bidirezionale su un'unica linea (linea SDA)
  3. permette il colloquio tra un MASTER e molti SLAVE (ma uno alla volta)
  4. la velocità di scambio dati si esprime indicando la frequenza degli impulsi di clock e può essere: 100KHZ/sec (standard), 400KHZ/sec (fast), 3,4MHZ/sec (high)
Come dispositivo MASTER andrò ad utilizzare il Raspberry Pi configurato come indicato in questo mio precedente post.
Il Raspberry Pi supporta l'i2c con clock a 100KHZ/sec.

Da notare che i resistori di pull-up, necessari per mantenere sempre a livello logico alto i segnali SCL e SDA (in assenza di traffico dati), sono già integrati dal Raspberry Pi e pertanto, e solo in questo caso, possono essere omessi nel circuito.


Implementazione i2c dei PIC 18F

I PIC 18F dispongono internamente di un modulo hardware dedicato ai protocolli seriali sincroni chiamato SSP: Synchronous Serial Port.
Tale modulo consente di implementare, con estrema semplicità, sia l'i2c che lo SPI (che vedremo in futuro).

I registri di cui abbiamo bisogno per implementare uno SLAVE i2c sono:
  • SSPCON: dove impostare la configurazione del modulo SSP e controllare il bit CKP
  • SSPADD: dove impostare l'indirizzo i2c del nostro PIC SLAVE
  • TRISC o TRISD: dove configurare i pin scelti come uscite digitali
  • INTCON: dove abilitare gli interrupt settando i bit GIE e PEIE
  • PIE1: dove abilitare gli interrupt della periferica SPP settando il bit SSPIE
  • PIF1: dove verificare che la fonte dell'interrupt sia la eriferica SPP leggendo e azzerando il bit SSPIF
  • SSPBUF; dove leggere e scrivere i byte da ricevere o da inviare sul BUS
  • SSPSTAT: dove verificare lo stato del modulo SPP e intraprendere il corretto comportamento per portare a termine con successo il dialogo i2c con il MASTER 

Ci sono alcuni punti di attenzione, da tenere presente, quanto utilizziamo il modulo SPP come SLAVE i2c:
  1. versione del PIC 18F
  2. configurazione dei pin i2c
  3. tempo limite operativo durante gli interrupt SSP (timing)
La prima trappola da evitare riguarda il fatto che l'implementazione del modulo SPP è leggermente diversa tra alcuni (più vecchi) 18F (tra cui il mio 4431 e famiglia) e i più recenti 18F..
Tali differenze, riportate nel documento Microchip AN734 (appendice C), riguardano gli stati dei bit del registro SSPSTAT in particolare per le operazioni RA (read address) e NACK.
Quindi è sempre bene verificare il datasheet del particolare modello di PIC che intendiamo utilizzare e leggere il documento AN734.

La seconda trappola riguarda il PIC 4431 che permette di scegliere, tra due porte diverse, i pin che vogliamo impegnare per l'i2c: questi posso essere o la coppia RC4(23) e RC5(24) o la coppia RD2(21) e RD3(22).
E' bene quindi non ignorare il settaggio di tale configurazione tramite il bit SSPMX del registro CONFIG3H: se 0 saranno i pin RD2-RD3; se 1 quelli RC4-RC5.

La terza trappola fa proprio la differenza tra successo e fallimento dato che ad un evento i2c dobbiamo rispondere entro un tempo limite altrimenti la comunicazione non va a buon fine.
E' importante quindi avere ben chiaro di quanti cicli operativi (istruzioni PIC) si dispone per gestire un evento i2c.

Operazioni i2c

L'i2c nasce per permettere di impostare o leggere i registri interni ad un dispositivo.

Tipicamente l'operazione di scrittura richiede prima di specificare quale registro scrivere (o da quale iniziare a scrivere) i byte che seguiranno.
Lo SLAVE deve disporre quindi di un registro indice il cui valore viene indicato dal primo byte ricevuto.

Ovviamente possiamo utilizzare l'i2c anche per trasferimenti seriali con una diversa struttura dei dati; ad esempio questo display OLED si controlla via i2c inviando dei comandi e non specificando dei registri interni.

Ogni byte trasferito richiede nove impulsi di clock: 8 per i bit del dato + 1 per il bit di ACK/NACK.
Il bit di ACK/NACK è impostato dalla controparte: MASTER scrive SLAVE risponde ACK/NACK e viceversa SLAVE scrive e MASTER risponde ACK/NACK.
Lo scopo del nono bit di ACK/NACK è quello di indicare di procedere (ACK) o meno (NACK) con l'invio di altri dati.

La sequenza di WRITE, inviata dal MASTER, è composta dai seguenti comandi: 


La prima riga in azzurro mostra i livelli della linea dati (SDA), la seconda in giallo quelli della linea di clock (SCL) e l'ultima in verde gli eventi di interrupt generati dal modulo SSP del PIC.
Il timing, indicato in basso, ha lo scopo di mostrare di quanto tempo (micro secondi) si dispone prima che venga generato da SSP l'interrupt successivo.

Il primo byte inviato è l'indirizzo dello SLAVE, nel mio caso 0x20, spostato però a sinistra di un bit (0x40) in quanto il bit 0 indica se il MASTER vuole inviare dati allo SLAVE (0=WRITE) o riceverne (1 = READ): quindi 0x40 sta per "scrivo sul dispositivo 0x20", mentre 0x41 sta per "leggo dal dispositivo 0x20".

Il secondo byte indica allo SLAVE il valore da impostare nel registro puntatore: è in pratica l'indce del primo registro delle SLAVE che il MASTER vuole impostare.

I restanti byte sono i valori da impostare nel corrente registro che lo SLAVE determina incrementando il suo registro puntatore per ogni byte ricevuto.
In questo caso il MASTER non vuole scrivere in altri registri oltre al primo e chiude il colloquio con un segnale di STOP.


L'operazione di lettura richiede prima una scrittura in modo che lo SLAVE imposti il registro puntatore al registro dal quale iniziare a leggere
.
La sequenza di READ, inviata dal MASTER, è quindi preceduta da una sequenza di WRITE:


Come visto sopra il MASTER invia una sequenza di scrittura verso lo slave 0x20 di un solo byte dati:l'indice del primo registro da leggere.

Dopo lo STOP il MASTER invia una seconda sequenza stavolta di lettura dello SLAVE 0x20.
Sarà adesso lo SLAVE a scrivere sulla linea dati (SDA) i bit corrispondenti al valore da trasmettere al MASTER.
Lo SLAVE è sempre vincolato dal segnale di clock (SCL) generato dal MASTER che legge lo stato della SDA nei punti indicati dalla freccetta in su.
Come sa lo SLAVE se il MASTER vuole ricevere il valore del successivo registro?
Il MASTER, dopo aver letto tutti gli otto bit dal dato al nono impulso setta SDA a 0 (ACK) se vuole ricevere il successivo valore/registro, a 1 (NACK) se non vuole ricevere ulteriori dati.

Stati del modulo SPP

Di seguito il dettaglio di tutti i possibili stati gestiti dal modulo SPP:
  • S: start
    SPP monitora il BUS e genera questo evento non appena un MASTER impegna il BUS per iniziare una sequenza W o R (anche se destinata ad altro SLAVE)
  • WA: write address
    SPP colleziona i bit indirizzo inviati sul BUS per controllare se destinati a lui; il valore ricevuto è quindi l'indirizzo i2c che verrà comparato da SPP con quanto scritto in SSPADD; solo se uguali SPP genera l'evento WA e tutti i successivi fino allo stop.
  • WD: write data
    SPP genera questo evento per ogni byte ricevuto successivamente all'indirizzo i2c
  • P: stop
    SPP genera questo evento quando un MASTER libera il BUS avendo terminato la sequenza di invio o ricezione
  • RA: read address
    Come per WA solo che il MASTER vuole leggere il valore del corrente registro
  • RW: read data
    Come per WD solo che il MASTER vuole leggere il valore del successivo registro

ACK e NACK

In ricezione dati SSP genera per noi i segnali di ACK, al nono impulso di clock, ogni volta che riesce a caricare il registro SPPBUF con gli 8 bit dati ricevuti.
E' importante far sempre trovare il buffer SPPBUF scarico/libero leggendo il precedente valore ricevuto prima che arrivi del successivo: in caso contrario SPP andrà in errore di "write collision":
  1. generando un segnale di NACK sul BUS
  2. impostando il bit WCOL in SSPCON (che va poi azzerato manualmente per ripristinare il funzionamento di SPP)
In invio dati invece siamo noi che dobbiamo verificare che il MASTER abbia segnalato un ACK o un NACK e questo verificando il bit CKP di SSPCON: se 0 ACK, se 1 NACK.


Mano al codice

Il codice di prova, ben commentato, lo trovate qui.
Si tratta di un esempio d'implementazione i2c slave dove il PIC espone 3 registri:
  • add1 (indirizzo 0x00)
  • add2 (indirizzo 0x01)
  • sum  (indirizzo(0x02)
Scrivendo in 'add1' e in 'add2' due valori si potrà leggere la loro somma tramite il registro 'sum'.


Circuito elettrico

Da notare che il quarzo del PIC è, in questo caso, da 16  MHZ.
VDD deve essere 3.3 volt per garantire la compatibilità con i livelli logici del RaspberryPi.

Attenzione: non interfacciate mai dispositivi a 3.3 volt con altri a 5.0 volt senza adattare i livelli tramite appositi circuiti.
Non prelevate mai la VDD a 3.3 volt direttamente dal Raspberry: rischiate di danneggiarlo seriamente.

Utilizzo

Dalla console del Raspberry Pi:
  1. digitare il comando  "sudo i2cset -y 1 0x20 0x00 0x0A 0x0B i"
    questo imposta entrambi i registri add1=0x0b (10) e add2=0x0B (11)
  2. digitare il comando "sudo i2cget -y 1 0x20 0x00"
    questo ci ritorna il valore di add1 cioè 0x0A (10)
  3. digitare il comando "sudo i2cget -y 1 0x20 0x01"
    questo ci ritorna il valore di add2 cioè 0x0B (11)
  4. digitare il comando "sudo i2cget -y 1 0x20 0x02"
    questo ci ritorna la somma di add1 e add2 ciaoè 0x15 (21)

Partendo da questa semplice base, possiamo realizzare interessanti funzioni, controllabili via i2c, con il nostro PIC 18F.

In un prossimo articolo andrò a realizzare, con il PIC 18F, un controller per servomotori basato su i2c.



Stay tuned!
ap


NB: l'autore non risponde di eventuali danni causati da omissioni, inesattezze o errori eventualmente presenti nell'articolo pubblicato.
Prego, segnalare suggerimenti e migliorie commentando questo post o inviando una email a padnest@gmail.com.

sabato 8 novembre 2014

Studio PIC 18F (18F4431) #7 :: "Comunicare con il PIC via seriale (RS-232)"


Vai al precedente POST della serie

Possiamo scambiare informazioni (dati) con un PIC? Certo che si!
I PIC 18F, in particolare, mettono a disposizione diverse soluzioni hardware per la comunicazione: UART-USART, I2C, SPI, e perfino USB (18F2550 e affini).
La scelta del protocollo dipende in primis dal tipo di dispositivo che deve interfacciarsi con il nostro PIC: un altro micro-controllore, un modulo GPS, un dispositivo MIDI, un PC, il Raspberry PI, il Lego Mindstorm, ecc... ecc...

Direi di procedere in ordine di complessità crescente e quindi di affrontare per prima, in questo articolo, la comunicazione seriale asincrona o UART.
Tale interfaccia:
  1. è di tipo asincrono (bit start/bit stop)
  2. permette colloquio FULL-DUPLEX tramite due linee distinte: una per l'invio (TX) e l'altra per la ricezione (RX)
  3. permette il colloquio tra due soli dispositivi: un master e uno slave (detto TERMINAL).
  4. la velocità di invio dei bit è detta BAUD-RATE e può essere scelta in un range da 300 a 115200 bit al secondo.

Tramite la UART possiamo interagire ad esempio con un PC (se dispone ancora dell'interfaccia RS-232) o con il RaspberryPI.
I fili necessari vanno da un minimo di 3 a un massimo di 5 a seconda che implementiamo o meno i l controllo hardware di flusso: GND, TX, RX di base, CTS, RTS per il controllo di flusso hardware.

Dato che voglio controllare il PIC dal PC avrò bisogno di un dispositivo intermedio per adeguare il livello dei segnali TTL del PIC con quello richiesto dalla RS-232 del PC: ad esempio un Max232 o un Max233

A tale scopo ho realizzato questo semplice modulo:



Ecco il suo schema elettrico:


La linea RX del modulo sarà connessa al pin TX del PIC, mentre la linea TX del modulo al pin RX del PIC: in questo modo i bit trasmessi dal PIC saranno ricevuti dal PC e viceversa.

Implementazione UART del PIC

Il modulo hardware per la gestione UART (o USART) è chiamato EUSART e permette di implementare sia l'interfacciamento asincrono che sincrono, l'autodetect del BAUD-RATE, l'auto wakeup in ricezione dati, ecc...: insomma è un modulo veramente flessibile e potente.

Per i nostri scopi dobbiamo concentrarci sulle specifiche relative alla sola modalità asincrona a 8 bit dati in full-duplex (non trattando al momento il wakeup e l'auto baud rate); i registri da utilizzare sono:

RegistroDescrizioneBit utilizzati
TXSTAConfigurazione e status del modulo TXTX9=0, TXEN=1, SYNC=0, SENDB=0, BRGH=X,
RCSTAConfigurazione e status del modulo RX, attivazione modulo serialeSPEN=1, RX9=0, CREN=1,
BAUDCTLConfigurazione e status del baud rate e del wakeupBRG16=X, WUE=0, ABDEN=0
SPBRGH:SPBRGConfigurazione generatore del baud ratetutti
TXREGScrittura byte da inviaretutti
RCREGLettura byte ricevutotutti
(X=vedere paragrafo sulla configurazione del baud rate)

Per attivare e gestire gli interrupt associati al modulo i registri sono:

RegistroBit utilizzati
INTCONGIE/GIEH, PEIE/GIEL
PIE1TXIE, RCIE
IPR1TXIP, RCIP
PIR1TXIF, RCIF

Configurazione del baud rate

La scelta della velocità di trasmissione/ricezione dei singoli bit può essere libera o vincolata dal dispositivo con il quale ci dobbiamo collegare.
Una volta determinato il BAUD rate dobbiamo far riferimento alle tabelle sul datasheet del PIC per capire quale è la configurazione ideale dei bit BRG16 e BRGH in relazione alla FOSC e all'errore riportato.
Ad esempio: volendo un BAUD rate di 9600 con un FOSC di 8 MHZ riscontro sempre un errore dello 0,16% a prescindere dalla configurazione a 16 o a 8 bit e alla modalità High/Low speed.
Pertanto imposterò BRG16=0 e BRGH=0 calcolando il valore di SPBRG con la formula:

SPBRG = ((FOSC/BAUD)/64) - 1

Quindi: SPBRG = ((8000000/9600)/64) -1 = 12,02083 (arrotondato a 12).
Visto che il valore è inferiore a 256 posso impostare il solo registro SPBRG.


Trasmissione

La trasmissione di uno o più byte avviene tramite la loro scrittura sequenziale del registro TXREG avendo ovviamente l'accortezza di attendere che il byte precedente sia stato preso in carico dal modulo EUSART prima di scrivere quello successivo.
Per fare ciò possiamo utilizzare gli interrupt oppure leggere lo stato del bit TXIF del registo PIR1 tenendo presente che TXIF :

  1. viene settato a 1 quando il TXREG può essere scritto (e quindi non appena abilitiamo la trasmissione settando il bit TXEN del registro TXSTA
  2. non può essere resettato via software: vuol dire che viene settato a 0 direttamente, dopo la scrittura del registro TXREG, dal modulo stesso quando il valore è stato trasferito in un altro registro interno per lo shift dei singoli bit e la  loro trasmissione .
  3. può essere testato solo dopo aver atteso almeno un ulteriore ciclo di clock (nop) dalla scrittura di TXREG


Ricezione 

Quando il modulo ESUART ha ricevuto un byte (gestendo internamente tutta la logica di ricezione) ne trasferisce il valore dal registro interno al registro RCREG settando l'interrupt flag RCIF a 1.
A questo punto, prima che arrivi un altro byte dalla seriale, dobbiamo leggere il registro RCREG in modo da evitare un OVERRUN (bit OERR settato nel registro RCSTA).


Mano al codice

Unendo due precedenti post (il #5 e il #6) realizziamo quindi un PWM controller che sia però comandabile da remoto via RS-232 in modo da poter variare il colore prodotto da un led RGB semplicemente inviando il valore dei singoli colori.
Inoltre aggiungiamo un display LCD dove indicare lo stato dei valori correnti.

Il progetto è scaricabile qui.


Circuito elettrico



Realizzazione pratica




Utilizzo

Nel mio caso, non disponendo della presa seriale sul PC, ho acquistato una comoda interfaccia USB-RS232.
Per inviare i comandi al Pic in esadecimale in modo facile e intuitivo consiglio l'ottimo software gratuito 'Ultra serial port monitor'.
Le immagini che seguono sono invece tratte da un altro programma non gratuito che ho potuto provare prima che scadesse il periodo di valutazione.


1: invio i tre byte alla prima linea: 00 FF 00 (colore verde)
2: vengono ricevuti dal Pic aggiornando il display lcd e lo stato del led rgb

3: invio ora i tre byte alla seconda linea per produrre il colore giallo
4: ricevuti e processati

5: infine invio l'ultima sequenza per ottenere il colore rosso
6: ricevuti e processati anche questi



Stay tuned!
ap

Vai al successivo POST della serie

NB: l'autore non risponde di eventuali danni causati da omissioni, inesattezze o errori eventualmente presenti nell'articolo pubblicato.
Prego, segnalare suggerimenti e migliorie commentando questo post o inviando una email a padnest@gmail.com.

domenica 12 gennaio 2014

Studio PIC 18F (18F4431) #6 :: "Hello World su LCD HD44780"

Vai al precedente POST della serie

Per poter utilizzare un display LCD dobbiamo prima di tutto conoscere qual è il controller che lo pilota.
Esistono diverse tipologie di controller: testuali, grafici, paralleli, seriali...
Iniziamo con quello che è di fatto uno standard per gli LCD testuali: il controller HD44780 sviluppato da Hitachi.
Il controller HD44780 rende estremamente semplice l'interfacciamento (di tipo parallelo) richiedendo un numero limitato di connessioni (e quindi di pin utilizzati).

Frugando nel cassetto ho trovato questo LCD prodotto dalla Powertip: trattasi del modello PC1602-D che permette di visualizzare 16 caratteri su 2 righe:



Di seguito la descrizione dei pin di interfacciamento:

POWERTIP PC 1602-D
PinSimboloDescrizione
1VssPower supply (GND)
2VddPower supply (+)
3VoContrast Adjust
4RSRegister select signal
5R/WData read / write
6EEnable signal
7DB0Data bus line
8DB1Data bus line
9DB2Data bus line
10DB3Data bus line
11DB4Data bus line
12DB5Data bus line
13DB6Data bus line
14DB7Data bus line / BF (busy flag)
15APower supply for LED B/L (+)
16KPower supply for LED B/L ( )

Generalmente tutti gli LDC HD44780 hanno i pin disposti secondo questo schema ma ovviamente verificate il datasheet del vostro display per adattare le connessioni in modo corretto...
I pin 15 e 16 servono per alimentare i led di retro-illuminazione... ma il mio LCD non ne è provvisto e quindi non verranno utilizzati.

Interfacciamento (BUS dati a 4 bit)

Per ridurre al minimo il numero di connessioni necessarie si utilizza solitamente la modalità con BUS dati a 4 bit  (in alternativa a quella con BUS dati a 8 bit) forzando la linea R/W a 0 cioè in sola scrittura (rinunciando pertanto a leggere lo stato del display).
Per evitare la perdita di comandi si utilizzano specifici tempi di delay in modo da essere sicuri che il controller abbia terminato l'esecuzione di un comando prima di inviare il successivo.

Questa configurazione richiede solo 6 linee di segnale: RS, E, DB4, DB5, DB6, DB7.
I rimanenti pin del controller saranno connessi a VSS secondo il seguente schema:


Inizializzazione del display

Dopo aver dato tensione al display questo di configura automaticamente in modalità BUS a 8 bit e quindi è necessario inviare una speciale sequenza di reset per poter cambiare questa configurazione di default.
Tale sequenza di reset è descritta nel datasheet del controller HD44780 e qui di seguito riassunta:
  1. attesa di almeno 40 msec dall'accensione
  2. BUS dati impostato a 0011
  3. strobe su linea E
  4. attesa di almeno 5 msec
  5. strobe su linea E
  6. attesa di almeno 160 usec
  7. strobe su linea E
  8. attesa di almeno 160 usec
  9. BUS dati impostato a 0010
  10. strobe su linea E
  11. attesa di almeno 160 usec
  12. seguono invii dei normali comandi per le configurazioni

Invio dei comandi al controller

Dato che non possiamo controllare lo stato del bit BF (come visto prima R/W è forzato a 0 per risparmiare una linea di controllo) bisogna attendere il tempo indicato per l'esecuzione di ogni comando prima di inviare il successivo (abbondando un po' per sicurezza rispetto a quanto indicato nel datasheet).
Nella modalità a 4 bit i comandi vanno inviati in due parti: prima i bit 7-4 e poi i bit 3-0 (most significant niblle first).
Quando il BUS dati è impostato con il valore da trasmettere bisogna inviare un impulso alto-basso sulla linea E (strobe) in modo che il controller prenda in carico il dato.
In pratica la sequenza corretta di invio di un comando per la modalità con BUS a 4 bit sarà la seguente:
  1. setto il 4 bit alti (DB7-DB4)
  2. strobe su linea  E
  3. setto i 4 bit bassi (DB3-DB0)
  4. strobe su linea E
  5. delay di attesa esecuzione comando

Elenco comandi controller HD44780
Comando Codifica linee Descrizione Tempo max esecuzione
(con fcp=270 kHz)
RS R/W D7 D6 D5 D4 D3 D2 D1 D0
Clear display 0 0 0 0 0 0 0 0 0 1 Pulisce il display e posiziona il cursore in linea 1 colonna 0 (indirizzo 0 della DDRAM) 1.52 ms
Cursor home 0 0 0 0 0 0 0 0 1 0 Posiziona il cursore in linea 1 colonna 0 (indirizzo 0 della DDRAM). Inoltre riporta il display shift in posizione originale. Il contenuto della DDRAM non viene modificato. 1.52 ms
Entry mode set 0 0 0 0 0 0 0 1 I/D S Imposta il modo di inserimento dei caratteri.
I/D = puntatore DDRAM dopo scrittura di un carattere: 0=decrementa, 1=incrementa
S = scroll dello schermo: 0=off, 1=on
37 μs
Display on/off control 0 0 0 0 0 0 1 D C B Imposta lo stato del display e del cursore.
D = display: 0=off, 1=on
C = cursore: 0=off, 1=on
B = lampeggio cursore: 0=off, 1=on
37 μs
Cursor/display shift 0 0 0 0 0 1 S/C R/L 0 0 Sposta il cursore o lo schermo di una posizione.
S/C = modo: 0=cursore, 1=schermo
R/L = direzione: 0=sinistra, 1=destra
37 μs
Function set 0 0 0 0 1 DL N F 0 0 Imposta i parametri di base del display.
DL = bus dati: 0=4 bit (DB4-DB7), 1=8 bit (DB0-DB7)
N = numero linee: 0=una linea, 1=due linee
F = dimensioni font: 0=5x8 (N=0 o 1), 1=5x10 (N ignorato: sempre una linea)
37 μs
Set CGRAM address 0 0 0 1 CGRAM address Inizio scrittura o lettura CGRAM all'indirizzo specificato. 37 μs
Set DDRAM address 0 0 1 DDRAM address Inizio scrittura o lettura DDRAM all'indirizzo specificato. 37 μs
Read busy flag &
address counter
0 1 BF CGRAM/DDRAM address Lettura stato controller.
BF = stato busy flag: 0=inviare nuovo comando, 1=attendere termine esecuzione comando
CGRAM/DDRAM = indirizzo attuale del puntatore alla ram in uso corrente.
0 μs
Write CGRAM or
DDRAM
1 0 Write Data Scrive il dato nella ram in suo corrente (CGRAM o DDRAM). 37 μs
Read from CG/DDRAM 1 1 Read Data Legge il dato dalla ram in uso corrente (CGRAM o DDRAM). 37 μs

La CGRAM è la ram che il controller usa per la generazione di caratteri extra definibili dall'utente: questo argomento verrà approfondito più avanti in un futuro post...
La DDRAM invece è la ram che il controller usa per memorizzare i codici dei caratteri da mostrare sul display) ed lo spazio utile è sempre di 80 bytes (anche se il display ne mostra meno).
I byte della DDRAM sono organizzati nel seguente modo: dall'indirizzo 0x00 a 0x27 troviamo le prime 40 locazioni e da l'indirizzo 0x40 a 0x67 le seconde 40 locazioni.
Come poi vengono organizzate fisicamente per mostrare i caratteri sul display dipende da quante linee un determinato modello può visualizzare: un'ottima spiegazione si trova qui.

Nel caso di un display a 2 linee la seconda linea inizia alla locazione 0x40.

Inviando più comandi di shift con S/C a 1 (scroll di tutto lo schermo) si possono mostrare i caratteri contenuti nelle locazioni 'nascoste' per entrambe le righe.

Scrittura sul display

Per mostrare un carattere sul display bisogna scrivere il codice del carattere sulla DDRAM.
Inviando il comando di scrittura il controller salverà il codice del carattere nella locazione corrente della DDRAM incrementando (o decrementando) il puntatore alla successiva locazione secondo quando configurato dal comando 'Entry mode set'.

In caso di incremento:
  • se il puntatore si trovava alla locazione 0x27 verrà spostato alla locazione 0x40
  • se si trovava alla locazione 0x67 verrà riportato alla locazione 0x00.
In caso di decremento:
  • se il puntatore si trovava alla locazione 0x40 verrà spostato alla locazione 0x27
  • se si trovava alla locazione 0x00 verrà spostato alla locazione 0x67.

Mano al codice

Il progetto ASM lo trovate qui.
Le sub di delay sono tutte calcolate per un FOSC di 8 MHZ: ovviamente se necessario andranno adattate (consiglio questo utile generatore di routine di delay on line: da evitare però i 'goto $').
Utile notare come, in questo esempio, ho utilizzato la lettura delle stringhe dalla memoria programma tramite la nuova e comodissima istruzione TBLRD.
Ogni funzione è ben commentata e non credo richieda ulteriori spiegazioni...

Realizzazione pratica

Una volta connesso il tutto (come da schema sopra indicato) e programmato il PIC (che anche in questo caso va autoalimentato) non rimane che regolare il contrasto, agendo sulla resistenza variabile VR1, fino a vedere scorrere i caratteri nel display.



Risultato






Stay tuned!
ap

Vai al successivo POST della serie

NB: l'autore non risponde di eventuali danni causati da omissioni, inesattezze o errori eventualmente presenti nell'articolo pubblicato.
Prego, segnalare suggerimenti e migliorie commentando questo post o inviando una email a padnest@gmail.com.

lunedì 30 dicembre 2013

Pic18f Language Extension Macros :: macro ASM per scrivere meno codice

Chi ha scaricato i progetti SVN degli ultimi post (#4 o #5) della serie "Studio PIC18f" avrà notato la presenza del file 'pic18f-langext-*.inc' e l'utilizzo di una serie di strane istruzioni che non fanno parte del set della famiglia 18f.
In effetti queste istruzioni non sono altro che delle macro realizzate per semplificare alcune operazioni ridondanti e ridurre cosi le linee di codice da scrivere (e di conseguenza gli errori).

Queste macro sono adesso disponibili come progetto indipendente su https://sourceforge.net/p/padnest/svn/HEAD/tree/pic18f/Padnest_PIC18F_langext.X

Col passare del tempo aggiungerò altre macro e quindi qui troverete le nuove versioni della 'raccolta'.
Spero che arrivino numerosi feed back da parte vostra con utili suggerimenti o proposte in merito...

Per conoscere i dettagli su ogni macro aprite il file 'pic18f-langext-*.inc' e troverete ogni comando ben commentato.
Inoltre nel file 'test.asm' trovate tutti i casi di test che fungono anche da validi esempi di utilizzo.

Detto questo, visto che siamo arrivati alla fine dell'anno 2013, approfitto per fare a tutti voi i miei migliori Auguri per uno spumeggiante nuovo Anno 2014 !!!


Stay tuned!
ap

NB: l'autore non risponde di eventuali danni causati da omissioni, inesattezze o errori eventualmente presenti nell'articolo pubblicato.
Prego, segnalare suggerimenti e migliorie commentando questo post o inviando una email a padnest@gmail.com.

sabato 28 dicembre 2013

Studio PIC 18F (18F4431) #5 :: "PWM RGB led: un arcobaleno di colori"


Vai al precedente POST della serie

Come naturale conseguenza del precedente post, che ha introdotto i primi rudimenti sulla generazione di segnali PWM con i pic18f, questo articolo prosegue e estende il concetto applicandolo ad un led di tipo RGB.
I led RGB, come saprete benissimo, sono 3 led in uno ognuno dedicato ad un singolo colore primario della sintesi additiva: rosso, verde e blu.
Unendo quindi la possibilità di variare l'intensità della luce emessa da un led e la disponibilità di un led in grado di generare i tre colori fondamentali possiamo realizzare un simpatico esperimento con il 4431 e similari.
Intendo utilizzare 3 dei 4 generatori PWM del 4431 associando ad ognuno di essi la gestione dell'intensità di un singolo colore per produrre un effetto arcobaleno con una transizione graduale tra tutte le possibili sfumature.

L'algoritmo "arcobalenico"

Giocherellando con la tavolozza dei colori di 'Gimp' ho verificato che l'effetto si ottiene agendo sull'intensità di una singola componente RGB per volta seguendo questo semplice schema dove 255 rappresenta la massima luminosità e 0 quella minima:
  1. partenza: R=255, G=0, B=0
  2. incremento G: R=255, G=255, B=0
  3. decremento R: R=0, G=255, B=0
  4. incremento B: R=0, G=255, B=255
  5. decremento G: R=0, G=0, B=255
  6. incremento R: R=255, G=0, B=255
  7. decremento B: R=255, G=0, B=0
  8. ora mi ritrovo nella stessa condizione di partenza e quindi ripeto il ciclo dal punto 2
Per rappresentare questi passaggi sono sufficienti 4 bit organizzati nel registro Flags in questo modo:
7 6 5 4 3 2 1 0
X X X X R G B Dir

I bit R, G e B indicano su quale colore agire (=1) mentre il bit Dir indica se l'intensità di quel colore va incrementata (=1) o decrementata (=0).
Quindi proviamo a codificare i passaggi elencati sopra in termini binari:
  1. partenza: settiamo il registro R a 255, G e B a 0
  2. incremento G:  Flags = 0000 0101
  3. decremento R: Flags = 0000 1000
  4. incremento B:  Flags = 0000 0011
  5. decremento G: Flags = 0000 0100
  6. incremento R:  Flags = 0000 1001
  7. decremento B: Flags = 0000 0010

Mano al codice

Scaricate il progetto MPLAB-X qui.

Nel file main.asm il codice è organizzato nei seguenti blocchi:


Blocco interrupt

Qui abbiamo tutta la logica di interpretazione del registro Flags cioè il codice deputato ad aggiornare i segnali PWM dei rispettivi colori in base allo stato dei suoi bit.
Quando il comando impostato in Flags è stato completato (cioè quando il relativo registro del colore ha raggiunto il valore massimo o minimo) l'esecuzione passa alla label int_next che provvede ad impostare il registro Flags con la successiva sequenza da eseguire reperita tramite la tabella get_seq con il classico sistema dell'incremento del PCL (che però nel caso dei pic 18f deve essere doppio).

Blocco main

Qui abbiamo l'inizializzazione dei registri LED_R, LED_G, LED_B, Flags e SeqIndex in modo da impostare il punto di partenza della sequenza dei colori.
Si procede poi con inizializzare il modulo PWM impostando una risoluzione di 8 bit e i tempi opportuni per produrre il passaggio tra i singoli colori.
Si abilitano qui i pin da PWM0 a PWM5 come uscita PWM.
Si continua inizializzando gli interrupt ed in particolare quello del modulo PWM.


Schema elettrico

In questo caso la corrente totale richiesta per pilotare il led RGB supera i 25 mA massimi erogabili dal PICkit2 e quindi è ASSOLUTAMENTE NECESSARIO ALIMENTARE IL CIRCUITO ESTERNAMENTE se non si vuole buttare nel secchio il PICkit2.
Inoltre è indispensabile utilizzare dei transistor per evitare di sovra caricare le porte del PIC: nel mio caso avendo un led RGB con anodo in comune utilizzo degli NPN tipo BC337 per adattare anche il segnale al catodo di ogni singolo led.
Nel caso che disponiate di un led RGB con catodo comune basterà semplicemente utilizzare dei PNP tipo BC327 invertendo tutte le polarità.

Nota: il led RGB in mio possesso ha in realtà una Fv (caduta di tensione) pari a 3,2 volt per G e B e di 2,0 volt per R (max 20mA per tutti) quindi per pignoleria avrei dovuto diversificare il valore delle resistenze R2 e R3 rispetto alla R4.






La BB alimentata esternamente e con la sezione 'di potenza' costituita dai tre NPN


Particolare del PICkit2 che non deve alimentare il circuito (filo rosso non connesso alla BB)


Risultato





Stay tuned!
ap

Vai al successivo POST della serie

NB: l'autore non risponde di eventuali danni causati da omissioni, inesattezze o errori eventualmente presenti nell'articolo pubblicato.
Prego, segnalare suggerimenti e migliorie commentando questo post o inviando una email a padnest@gmail.com.

giovedì 26 dicembre 2013

Studio PIC 18F (18F4431) #4 :: "PWM led"


Vai al precedente POST della serie

Generare un segnale PWM con i pic 18F è estremamente semplice soprattutto se questi dispongono del supporto hardware come nel caso del 4431.
Dando per scontato che si sappia già cosa sia un segnale PWM (eventualmente approfondire in rete l'argomento) vediamo come utilizzarlo per far lampeggiare un led in modo "sfumato" cioè con una progressione da spento fino alla massima luminosità e viceversa.

Iniziamo col dire che il 4431 dispone di 4 generatori PWM indipendenti tra loro in termini di duty cycle ma tutti dipendenti da uno stesso TIMER che ne determina la frequenza/periodo: questo TIMER è dedicato al modulo PWM e si chiama PTMR (non va confuso con gli altri timer del pic).
Associati ad ogni canale PWM abbiamo una coppia di pin di uscita: PWM0 e PWM1 (33-34) per il canale PWM0, PWM2 e PWM3 (35-36) per il canale PWM1, PWM4 e PWM5 (38/28-37) per il canale PWM2, PWM6 e PWM7 (29-30) per il canale PWM3.
NB: dato che i pin di uscita sono condivisi con le porte B e D sarà necessario riservare tali pin al modulo PWM tramite il registro PWMCON0.

In questo esempio utilizziamo un solo canale PWM: il canale 0 e solo il pin di uscita PWM0 (33).
I registri coinvolti sono: PTCON0, PTCON1, PWMCON0, PWMCON1, PTMRL, PTMRH, PTPERL, PTPERH, PDC0L, PDC0H.
I passi per generare il segnale PWM sono:
  1. inizializzare i registri di controllo del timer PTMR: PTCON0 e PTCON1
  2. inizializzare i registri di controllo del modulo PWM: PWMCON0 e PWMCON1
  3. impostare il numero di conteggi del timer PTMR settando i registri PTMRL e PTMRH (12 bit)
  4. impostare il duty cycle del segnale PWM settando i registri PDC0L e PDC0H (14 bit)
  5. avviare il timer PTMR settando a 1 il bit PTEN del registro PTCON1

Determinare la frequenza del segnale

La generazione del segnale PWM è molto semplice: il timer PTMR conta da 0 fino al valore impostato in PTPERL+H incrementando i registri PTMRL+H ad ogni impulso di clock pari a FOSC/4.
Si può ulteriormente scalare il clock attivando il prescaler agendo su PTCKPS<3:2> del registro PTCON0.

Se ad esempio utilizzo un quarzo da 8 MHZ avrò le seguenti possibili combinazioni:

OSC 8 MHZ
PTCKPSprescalerPTMR clockFrequenzaIntervallo incremento PTMR
001:1FOSC/42.000.000 HZ0,5 uSec
011:4FOSC/16500.000 HZ2 uSec
101:16FOSC/64125.000 HZ8 uSec
111:64FOSC/25631.250 HZ32 uSec

Quando il timer PTMR inizia il conteggio da 0 il pin di uscita è posto a livello alto e rimane cosi fino a quando il conteggio non raggiunge il valore impostato in PDCx: a questo punto il pin passa a livello basso.
Il conteggio prosegue fino a quando il valore di PTMRL+H non raggiunge il valore impostato in PTPERL+H: a questo punto PTMRL+H si azzerano, il pin di uscita torna alto e il ciclo ricomincia.
Questo è il funzionamento in modalità free-running: le altre due modalità possibili (single-shot e continuous-up/down) non sono trattate qui.

La frequenza del segnale PWM è quindi determinata da: (FOSC / 4) / ((PTPER+1) * prescaler).
Ad esempio: se il quarzo è da 8Mhz, il prescaler vale 1:4 e PTPER lo imposto a 0xFF avrò: (8.000.000 / 4) / (256 * 4) = 2.000.000 / 1.024 = 1.953,125 Hz.

Registri PDCxL e PDCH

Fino a qui sembra tutto molto semplice ma bisogna fare attenzione ad una particolare insidia che non emerge subito chiaramente dal datasheet: il valore del duty cycle (che determina il passaggio del segnale PWM a livello basso) va inserito nei registri PDCxL+H shiftato di 2 bit verso sinistra in quanto i primi due bit (1:0) di PDCxL determinano il Q-Clock cioè in quale fase di clock deve avvenire il confronto tra PTMRL+H e PDCxL+H.
PTMR e PTPER permettono di impostare al massimo un valore a 12 bit mentre PDCx a 14 bit cioè 12 bit di confronto del duty + 2 bit di impostazione su quando effettuare il confronto (vedi datasheet cap 18.6).

PDCx si presenta quindi in questo modo:
PDCxHPDCxL
XX XX 11 10 09 08 07 06 05 04 03 02 01 00 Q-1 Q-0

Dalla teoria alla pratica

Per far lampeggiare il led dobbiamo variare il duty cycle dallo 0% al 100% e dal 100% allo 0%.
Per fare questo possiamo utilizzare un timer oppure sfruttare un particolare interrupt generato dal modulo PWM ad ogni reset del timer PTMR: questa seconda possibilità è quella che ho scelto in questo caso.
Per semplificare le cose ho scelto di utilizzare solo i registri L e quindi limitare la risoluzione PWM a 8 bit.
Per avere un lampeggio lento ho ridotto il clock impostando il prescaler a 1:16 avendo quindi una frequenza di incremento pari a  FOSC/64.
La frequenza PWM sarà pari a: 2.000.000 / (256 * 16) = 488 Hz circa.
La durata del lampeggio è invece: (256*2) / 488 = 512 / 488 =  1,049 secondi circa.     

Il progetto MPLAB-X relativo a questo articolo è scaricabile qui.

Lo schema elettrico è il seguente:

Il risultato è questo:



Stay tuned!
ap

Vai al successivo POST della serie

NB: l'autore non risponde di eventuali danni causati da omissioni, inesattezze o errori eventualmente presenti nell'articolo pubblicato.
Prego, segnalare suggerimenti e migliorie commentando questo post o inviando una email a padnest@gmail.com.

mercoledì 14 agosto 2013

Studio PIC 18F (18F4431) #3 :: "Blinka baby, blinka!"


Vai al precedente POST della serie

La cosa più semplice che possiamo fare con un PIC è sicuramente quella di accendere un LED collegato ad un pin di una porta digitale.
Questo nel mondo dei microcontrollori corrisponde al classico HelloWorld dell'universo della programmazione.
Riservandoci più avanti di scrivere anche noi un vero e proprio "Hello World !!!" su un display LCD per il momento ci accontentiamo di pilotare un LED per parlare di una tra le più importanti risorse dei PIC: i TIMER.

Un PIC può disporre di uno o più TIMER e per questo vengono numerati. Ogni TIMER ha le sue peculiarità, illustrate nel datasheet, ma tutti svolgono lo stesso compito: incrementare un contatore di uno con una determinata frequenza.
Quando il contatore raggiunge il suo OVERFLOW, ciòè ricomincia da 0 in quanto ha superato il valore massimo rappresentabile, viene generato un particolare interrupt (l'esecuzione del programma salta al vettore di interrupt).

Noi possiamo quindi scegliere il TIMER che più ci aggrada e configurarlo in modo da stabilire:
  • la frequenza di incremento
  • il numero di incrementi prima di raggiungere l'OVERFLOW
  • se controllare ciclicamente l'avvenuto OVERFLOW oppure abiilitare l'interrupt per far eseguire in automatico un particolare blocco di codice
Ora proviamo a far lampeggiare (to blink che diventa blinkare !) il nostro LED con una frequenza di un secondo utilizzando un TIMER per ottenere un intervallo di lampeggio molto preciso.

Datasheet alla mano vediamo che il TIMER0 del 4431 fa proprio al caso nostro in quanto:
  • può lavorare con un contatore a 16 bit permettendoci di impostare fino a 65536 incrementi
  • dispone di uno specifico interrupt
  • dispone di un prescaler programmabile fino a 1:256
Per chi non sapesse nulla sui prescaler (e postscaler) basti pensare a dei semplici divisori di frequenza: una sorta di riduttori del numero di impulsi generati dal clock principale del PIC.
Senza il prescaler abilitato il TIMER è infatti connesso direttamente al clock interno FOSC/4 quello cioè che produce un numero di impulsi pari alla frequenza dell'oscillatore divisa per 4.

Se ad esempio utilizziamo un quarzo da 8 MHZ avremo il TIMER0 che si incrementerà con una frequenza pari a FOSC HZ/4 = 8.000.000/4  = 2.000.000  = 2 MHZ.
Ogni incremento avverrà quindi con un intervallo di tempo in secondi di 1/HZ = 1/2.000.000 = 0,0000005 secondi = 0,5 uSec.
Troppo veloce per il nostro scopo: anche impostando il numero massimo di incrementi pari a 65536 il TIMER scatenerà l'interrupt ogni: 65536 * 0,5 uSec = 32768 uSec = 32,768 mSec = 0,032768 secondi.
A noi serve un interrupt ogni secondo cioè ogni 1000 mSec (1.000.000 di uSec).

In nostro aiuto arriva quindi il prescaler del TIMER0 che ridurrà ulteriormente la frequenza di clock e quindi ci permetterà di impostare un numero di incrementi nel range dei 16 bit disponibili:

OSC 8 MHZ
PrescalerFOSC/4 al TIMERIntervallo incremento TIMER
1:1 (disabilitato)2.000.000 HZ0,5 uSec
1:21.000.000 HZ1 uSec
1:4500.000 HZ2 uSec
1:8250.000 HZ4 uSec
1:16125.000 HZ8 uSec
1:3262.500 HZ16 uSec
1:6431.250 HZ32 uSec
1:12815.625 HZ64 uSec
1:2567.812,5 HZ128 uSec


Per ottenere un secondo di intervallo possiamo utilizzare una tra le seguenti combinazioni di valori tra prescaler e numero di incrementi:

PrescalerIntervallo incremento TIMERIncrementiIntervallo totaleErrore
1:3216 uSec625001 Sec0
1:6432 uSec312501 Sec0
1:12864 uSec156251 Sec0
1:256128 uSec78120,999936 Sec-64 uSec
1:256128 uSec78131,000064 Sec+64 uSec

La scelta è ampia considerando che l'errore che otteniamo è nullo per ben 3 opzioni.

Possiamo quindi scegliere la 1:128 con 15625 incrementi: procediamo dunque!

Se non lo abbiamo ancora fatto è il momento di installare il tool di sviluppo (IDE) MPLAB-X scaricabile liberamente dal sito della microchip.

Aggiungiamo allo schema di base: un LED, una resistenza da 330 e cambiamo il quarzo con uno da 8 MHZ:
NB: il 4431 può fornire al massimo 25 mA di corrente da un singolo pin e 300 mA di corrente totale prelevabile da tutte le porte. Superare i valori raccomandati nel datasheet significa mettere fuori uso il PIC.
Non è bene connettere carichi che non siano altri dispositivi digitali alle porte del PIC: qui facciamo uno strappo alla regola connettendo direttamente un LED al pin RD1 della PORTD e limitando la corrente a 10mA circa con la R2.

Avviamo MPLAB-X, creiamo un nuovo progetto standalone seguendo il wizard e copiamo in un nuovo file sorgente asm il seguente codice:
; Copyright 2013 padnest@gmail.com

; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;   http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.

 LIST p=18F4431
 #include <p18f4431.inc>

; configs
 CONFIG OSC = HS
 CONFIG IESO = OFF
 CONFIG FCMEN = OFF
 CONFIG PWRTEN = ON
 CONFIG WDTEN = OFF
 CONFIG BOREN = OFF
 CONFIG MCLRE = ON
 CONFIG LVP = OFF
 CONFIG DEBUG = OFF
 CONFIG STVREN = ON

 #define LED LATD, RD1

; reset vector
 ORG 0x0000
 goto main

; interrupt vector in compatibility mode
 ORG 0x0008

interrupt:
 btg  LED
 bcf  INTCON, TMR0IF
 movlw 0xC2    ; set 15625 increments in TIMER0: 65536-15625 = 49911 (C2F7)
 movwf TMR0H
 movlw 0xF7
 movwf TMR0L
 retfie FAST

main:
 ; init PORTD
 clrf PORTD
 clrf TRISD

 ; init interrupts
 bcf  RCON, IPEN   ; disable high priority interrupts mode
 movlw b'10100000'   ; GIE + TMR0 enabled
 movwf INTCON

 ; init TIMER0
 movlw 0xFF    ; set 1 increment in TIMER0
 movwf TMR0H
 movwf TMR0L
 movlw b'10000110'   ; starting TIMER0 + 16bit mode + prescaler enabled (0) at 1:128 (110)
 movwf T0CON
 
loop8:       ; infinite loop
 goto loop8

 END

Compiliamo ed eseguiamo il programma nel PIC (clccando sull'apposita icona in MPLAB-X) e vedremo lampeggiare il led con l'intervallo voluto: 1 secondo acceso e un secondo spento.

Variante: volendo adesso raddoppiare la velocità di lampeggio in modo che il led resti acceso per 0,5 secondi e spento per altri 0,5 secondi come ci conviene intervenire sul programma?

Provate a modificare il valore del prescaler da 1:128 a 1:64, cambiando quindi la linea:
movlw b'10000110'   ; starting TIMER0 + 16bit mode + prescaler enabled (0) at 1:128 (110)
in
movlw b'10000101'   ; starting TIMER0 + 16bit mode + prescaler enabled (0) at 1:64 (101)


Stay tuned!
ap

Vai al successivo POST della serie

NB: l'autore non risponde di eventuali danni causati da omissioni, inesattezze o errori eventualmente presenti nell'articolo pubblicato.
Prego, segnalare suggerimenti e migliorie commentando questo post o inviando una email a padnest@gmail.com.

lunedì 12 agosto 2013

Studio PIC 18F (18F4431) #2 :: "Signor Sulu: velocità curvatura!"


Vai al precedente POST della serie

I PIC 18F dispongono di un comodo oscillatore interno, limitato però in termini di frequenza massima ottenibile e di precisione.
Nel caso specifico del 4431 la frequenza massima dell'oscillatore interno è di 8 MHZ.

Se vogliamo superare questo limite dobbiamo utilizzare un risonatore o, meglio, un quarzo esterno collegato tra i pin OSC1 e OSC2: purtroppo nel 4431 questi due pin sono condivisi con la PORTA e quindi si perde la possibilità di utilizzare rispettivamente RA7 e RA6.

Per raggiungere quindi la sospirata "velocità curvatura", che per il 4431 è 40 MHZ, andiamo ad aggiungere, al nostro circuito di sviluppo, tutto il necessario: un quarzo da 10 MHZ e due condensatori ceramici.

A questo punto il comandante Kirk avrebbe detto seccato: "Avevo dato un ordine signor Sulu! Velocità curvatura".

Da datasheet non risulta possibile utilizzare direttamente un quarzo da 40 MHZ ma il 4431 dispone di una risorsa speciale: un moltiplicatore PLL di frequenza (fisso a 4x) attivabile solo sull'oscillatore esterno avente una frequenza massima di 10MHZ.

Riguardo ai due condensatori il datasheet riporta la capacità "tipica" avvertendo che ci sono tanti fattori che determinano la loro capacità: frequenza del quarzo, temperatura di esercizio, tensione di alimentazione, ecc.

Sulu non ha tempo per fare complicati calcoli visto che il comandante è già abbastanza alterato e la nave Klingon è sempre più pericolosamente vicina: fruga nel cassetto e applica due condensatori da 22pF.

Il signor Spock annuisce a Sulu pur avendo già determinato a mente, tenendo presenti tutte le variabili in gioco, l'esatto valore.
Il vulcaniano sa infatti benissimo che questa capacità non è un fattore critico, la nave nemica si..

Ecco quindi lo schema di collegamento configurato per l'oscillatore esterno al quarzo:


E qui la BB pronta per i nostri test:




Più avanti proveremo anche noi la "velocità curvatura": lunga vita e prosperità!

Stay tuned!
ap

Vai al successivo POST della serie

NB: l'autore non risponde di eventuali danni causati da omissioni, inesattezze o errori eventualmente presenti nell'articolo pubblicato.
Prego, segnalare suggerimenti e migliorie commentando questo post o inviando una email a padnest@gmail.com.

venerdì 9 agosto 2013

Studio PIC 18F (18F4431) #1 :: connessioni minime per lo sviluppo

Inzia qui una serie di articoli sulla programmazione dei PIC 18F ed in particolare del modello 4431.
Ovviamente sarà facile adattare quanto trattato a qualsiasi altro PIC 18F.

Per prima cosa vediamo quali sono le connessioni minime da applicare sulla nostra BB di sviluppo per poter lavorare senza problemi.
Per programmare i PIC 18F utilizzo il PICKIT2 quindi le connessioni si riferiscono a tale tool.

Il PIC in questione nasconde subito un prima insidia che potrebbe farvi perdere un sacco di tempo in inutili tentativi di programmarlo: bisogna infatti seguire il datasheet alla lettera e collegare i pin AVdd e AVss anche se non è nostra intenzione utilizzare la conversione A/D.

Detto questo seguite pure questo schema:

In basso il pinout del connettore del PICkit 2 al quale connettere il tutto.

Ricordatevi che:
VDD positivo di alimentazione (esempio +5v)
VSS negativo di alimentazione (GND)


E qui la BB pronta per lo sviluppo:



Stay tuned!
ap

Vai al successivo POST della serie

NB: l'autore non risponde di eventuali danni causati da omissioni, inesattezze o errori eventualmente presenti nell'articolo pubblicato.
Prego, segnalare suggerimenti e migliorie commentando questo post o inviando una email a padnest@gmail.com.

lunedì 25 gennaio 2010

Servo controller con Pic18F su i2c (parte 2)

E' giunto il momento di dettagliare il protocollo di comando del controller che, come indicato nel titolo, è basato su i2c (se non hai letto la precedente parte clicca qui).

Di seguito i comandi inviabili (ovviamente ogni byte comando va preceduto dal byte address i2c per poter essere ricevuto):

SetServoPosition
Posiziona il servo connesso al canale specificato di n gradi a destra o a sinistra rispetto alla posizione centrale. Alla ricezione di questo comando viene automaticamente abilitata la generazione del segnale di pilotaggio sul canale relativo.
Richiede l'invio di 2 byte: il byte comando e il byte parametro che indica la posizione in gradi da 0 a 90.
Il bit DIR rappresenta la direzione di spostamento: 1 a sinistra, 0 a destra.
I bit CH rappresentano il canale selezionato: da 000 (0) a 111 (7).
Cmd byte
Param byte
1
1
0
0
DIR
CH
CH
CH
0
X
X
X
X
X
X
X


AdjustServoCentralPosition
Regola finemente la posizione centrale del servo connesso al canale specificato.
Richiede l'invio di 2 byte: il byte comando e il byte parametro che indica l'offset da 0 a 15.
Il bit OFS indica la direzione vero la quale applicare l'offset: 1 verso sinistra, 0 verso destra.
I bit CH rappresentano il canale selezionato: da 000 (0) a 111 (7).
Cmd byte
Param byte
1
1
0
1
OFS
CH
CH
CH
0
0
0
0
X
X
X
X
Il valore ideale va ricavato sperimentalmente e varia da servo a servo. Per effettuare la regolazione inviate al controller il comando SetServoPosition su 0 gradi in modo da posizionare il servo al centro. Consiglio poi di etichettare il servo con il valore di trimming ricavato in modo da non dover ripetere l'operazione in futuro.
Attenzione: ogni incremento del valore di offset rappresenta 4uSec in +/- di aggiustamento del segnale di pilotaggio e quindi valori troppo elevati potrebbero causare problemi di mancato stop della rotazione agli angoli estremi.


SetServoOutputState
Setta lo stato del canale specificato permettendo di abilitare o disabilitare la generazione del segnale.
Richiede l'invio del solo byte comando.
Il bit STS indica lo stato del canale: 1 abilitato, 0 disabilitato.
I bit CH rappresentano il canale selezionato: da 000 (0) a 111 (7).
Cmd byte
1
0
0
0
STS
CH
CH
CH


ResetAll
Resetta il controller allo stato iniziale disattivando tutti i canali e reimpostando i valori di trimming centrale a 0.
Richiede l'invio del solo byte comando.
Cmd byte
1
0
1
1
0
0
0
0

Questo è quanto andremo ad implementare nella logica del controller. Posso anticiparvi che il firmware che gestirà tale logica sarà facilmente adattabile ad ogni PIC della serie 18F che disponga del modulo i2c hardware (in quanto non lo emulerò via software).

Stay tuned!
ap

NB: l'autore non risponde di eventuali danni causati da omissioni, inesattezze e errori eventualmente presenti nell'articolo pubblicato.

mercoledì 20 gennaio 2010

Servo controller con Pic18F su i2c (parte 1)

Iniziamo il progetto analizzando il funzionamento di un servo RC e come ci dobbiamo interfacciare per poterne controllare il movimento/posizionamento.

Il servo RC analogico standard, e comunque ideale per questo controller, possiede le seguenti caratteristiche: escursione max di rotazione 180°, posizione centrale 1500 uSec.

Dal servo escono 3 fili di diverso colore (solitamente rosso, nero, giallo/bianco):
  • filo nero: GND
  • filo rosso: SUPPLY (generalmente +5 volt)
  • filo giallo/bianco: SIGNAL (segnale di pilotaggio logico 0/1)

Il servo possiede un'elettronica interna che è in grado di azionare il motorino collegato al proprio asse in relazione al segnale logico ricevuto.
Quindi per poterlo controllare dobbiamo generare un segnale, ad onda quadra, abbastanza preciso ed estremamente stabile:
  1. da livello 0 a 1 con durata minima di 600 uSec (posizione 0° cioè tutto a sinistra)
  2. eventuale mantenimento a livello 1 per un massimo di 1800 uSec in relazione all'angolo di posizionamento dell'asse voluto (angolo 0° = asse tutto a sinistra = 0 uSec, angolo 90° = posizione centrale = 900 uSec, angolo 180° = posizione tutto a destra = 1800 uSec)
  3. da livello 1 a 0 e ripezizione segnale dal punto 1 con frequenza di 50 HZ (20 mSec di intervallo)

In pratica abbiamo una variazione dell'impulso di +900 uSec dalla posizione tutto a sinistra (0°) a quella centrale (90°) e di +900 uSec tra quella centrale (90°) e quella tutto a destra (180°).
La durata dell'impulso va quindi da un minimo di 600uSec ad un massimo di 600 + 900 + 900 = 2400 uSec. Per posizionare il servo al centro l'impulso deve durare 600 + 900 = 1500 uSec.





Possiamo affermare che, per questa tipologia di servo, ogni grado angolare corrisponde a circa 10 uSec di variazione della lunghezza del segnale di livello 1.
Per posizionare l'asse a circa 45° (quindi verso sinistra) dobbiamo generare un impulso di 600 + 45*10 = 600 + 450 = 1050 uSec.
Invece per posizionare l'asse a circa 135° (quindi verso desta) dobbiamo generare un impulso di 600 + 135*10 = 600 + 1350 = 1950 uSec.

E' importante non tanto la precisione al uSec quanto la stabilità dell'impulso in quanto dovrà essere ripetuto identico ogni 20 millisecondi e comunque fino al termine della rotazione.

Infatti un impulso non stabile causa l'oscillazione continua della posizione con relativo inutile assorbimento di preziosi mA da parte del motore interno in continuo movimento.
Inoltre impulsi di durata inferiore ai 600 uSec o superiore ai 2.400 uSec sono altrettanto pericolosi in quanto provocano l'arresto a fine corsa della rotazione dell'asse del servo con conseguente continuo sforzo del motore.

Il controller potrà supportare anche servi RC analogici che abbiano escursioni di rotazione inferiori a 180° e voltaggio di alimentazione diverso da 5 volt.
Dobbiamo anche prevedere un sistema di taratura della posizione centrale in quanto anche fornendo lo stesso segnale a due servi identici (stesso modello) non si ottiene lo stesso identico posizionamento (tolleranza o errore).

Nella prossima parte vi parlerò del protocollo di comando del controller basato su i2c.

Stay tuned!
ap

NB: l'autore non risponde di eventuali danni causati da omissioni, inesattezze e errori eventualmente presenti nell'articolo pubblicato.