I PIC Partendo da Zero - tartaruga elettronica

Transcript

I PIC Partendo da Zero - tartaruga elettronica
I PIC Partendo da Zero
By link_89
Indice:
1. Introduzione
2. Che cosa serve
3. I più usati
4. I registri
5. Il Primo progetto
Introduzione
Con questa guida non pretendo di insegnarvi a usare perfettamente un pic, ma solo di darvi
una infarinatura sulla loro struttura e le basi per programmarlo, in poche parole solo una
conoscenza base necessaria all’inizio, poi sta a voi ampliare le vostre conoscenze…
I PIC sono dei microcontrollori programmabili prodotti dalla Microchip Technology Inc. (>http://www.microchip.com), in questa guida tratterò solo la serie 12F e 16F, che sono i più
usati dagli hobbisti, anche se si stanno diffondendo anche quelli della serie 18F.
I PIC sono disponibili in vari package, tra cui:
•
PDIP/CERDIP
•
SOIC
•
SSOP
•
TQFP
•
MQFP
•
PLCC
Il formato più semplice da usare è il PDIP (Pastic Dual In Line) e CERDIP (Ceramic Dual In
Line), in quanto i pin hanno il passo di 0,1 pollici, o 2,54mm, e possono essere tranquillamente
montati su una piastra millefori o bread-board.
Gli altri package sono per montaggio superficiale, e quindi non alla portata di tutti gli hobbisti
(solo di quelli che si fanno i pcb in casa o se li fanno fare dalle ditte…), comunque hanno lo
stesso funzionamento degli altri package, in quanto il chip interno è il solito :D.
I PIC vengono chiamati microcontrollori anziché microprocessori perché, a differenza di un
normale microprocessore essi dispongono di registri e periferiche particolari come:
• Timer
• Porte di I/O
• Porte Seriali (UART,USART, I2C, SPI, USB, Ethernet, …)
• Porte parallele
• Contatori
• EEPROM
• RAM
• Comparatori
• Convertitori A/D
In oltre in un microprocessore i bus controlli, indirizzi e dati sono accessibili dall’esterno, in
quanto esso non dispone di periferiche integrate, mentre in un microcontrollore questi bus sono
interni, è collegati ai registri delle periferiche.
Mettiamo a confronto le due strutture interne:
• μProcessore:
•
μControllore:
Come si può notare la struttura di un microcontrollore è molto più articolata rispetto a quella di
un microprocessore.
Esso integra la ram, la EEPROM e la memoria del programma (Flash Program Memory nello
schema).
I Timer sono dei registri particolari, a seconda delle funzioni possono fare da contaimpulsi,
timer con sorgente degli impulsi interno o esterno, misurare il periodo alto e basso di un
segnale etc…
La EEPROM interna è di dimensioni piccole, ma può servire per salvare qualche variabile o
simili…
L’A/D è un convertitore analogico-digitale a 10 bit, è utile per misurare tensioni tra 0 e 5V…
I comparatori possono essere usati per comparare 2 tensioni in ingresso, il risultato può essere
letto sia su un registro interno del pic che su un pin di uscita.
L’USART è la porta seriale, utile per collegarlo al pc o ad altri dispositivi (modem etc…).
Le porte seriali sincrone sono l’I2C e SPI, possono essere usate per collegare al
microcontrollore memorie EEPROM esterne (tipo le 24Cxxxx), port expander, sensori etc…
Il voltage reference serve per creare una tensione di riferimento per un ingresso dei
comparatori…
Un microcontrollore PIC si programma tramite un “programmatore”, cioè un circuito elettronico
che serve a scrivere sulla flash interna, esso può essere acquistato in negozi di elettronica o su
internet, la Microchip vende il PicKit2, o sennò sono disponibili dei cloni, altra possibilità è
costruirsene uno con i vari schemi disponibili in rete, ad es il ludipipo o JDM:
Questo invece è uno che ho progettato io, richiede una alimentazione esterna, ma è
compatibile con tutti i pic della serie 12F e 16F, oltre alle memorie seriali I2C (è disponibile le
descrizioni e i pcb all’indirizzo http://www.grix.it/viewer.php?page=2116, il connettore a
vaschetta a 9 pin per la seriale è riferito a un cavo seriale null-modem):
I pin di uscita (+5V, V Prog, Clock, Dati e Gnd) vanno collegati ai rispettivi pin del pic per la
programmazione (vdd, mcrl, rb6, rb7, vss).
I programmi che essi caricano nella memoria del pic sono in formato *.hex, un esempio, di uno
che fa lampeggiare un led sul pin 0 della portb è questo:
:100000000428FF3FFF3FFF3FFF30031383168500A7
:10001000FE308600FF308700013083120605F100B4
:100020007108003A031D162806141728061006301A
:10003000FC00FF30FB00FF30FA00FC0B20282728D3
:10004000FB0B23282628FA0B232820281D281A30EA
:10005000FB00FF30FA00FB0B2E283128FA0B2E286C
:100060002B284230FA00FA0B332800000C283728DE
:02400E003A3F37
:00000001FF
Per comodità (e per semplicità) si usa l’assembler, un linguaggio a alto livello, ma comunque
richiede alte conoscenze dei registri del pic e dei vari comandi, per esempio lo stesso codice
diventa così:
; Assembly code generated by mikroVirtualMachine - V. 5.0.0.3
; Date/Time: 21/03/2009 19.46.56
; Info: http://www.mikroe.com
; ADDRESS OPCODE
ASM
; ---------------------------------------------$0000 $2804
GOTO _main
$0004 $
_main:
;lampeggio.pbas,3 ::
main:
$0004 $
_main_main:
;lampeggio.pbas,4 ::
trisa = $FF
$0004 $30FF
MOVLW
255
$0005 $1303
BCF
STATUS, RP1
$0006 $1683
BSF
STATUS, RP0
$0007 $0085
MOVWF
TRISA
;lampeggio.pbas,5 ::
trisb = $FE
$0008 $30FE
MOVLW
254
$0009 $0086
MOVWF
TRISB
;lampeggio.pbas,6 ::
trisc = $FF
$000A $30FF
MOVLW
255
$000B $0087
MOVWF
TRISC
;lampeggio.pbas,7 ::
while true
$000C $
lampeggio_L_2:
;lampeggio.pbas,8 ::
if portb.0 = 0 then
$000C $3001
MOVLW
1
$000D $1283
BCF
STATUS, RP0
$000E $0506
ANDWF
PORTB, 0
$000F $00F1
MOVWF
STACK_1
$0010 $0871
MOVF STACK_1, 0
$0011 $3A00
XORLW
0
$0012 $1D03
BTFSS STATUS, Z
$0013 $2816
GOTO lampeggio_L_7
$0014 $
lampeggio_L_6:
;lampeggio.pbas,9 ::
portb.0 = 1
$0014 $
lampeggio_L_9:
$0014 $1406
BSF
PORTB, 0
$0015 $
lampeggio_L_10:
$0015 $2817
GOTO lampeggio_L_8
;lampeggio.pbas,10 ::
else
$0016 $
lampeggio_L_7:
;lampeggio.pbas,11 ::
portb.0 = 0
$0016 $1006
BCF
PORTB, 0
$0017 $
lampeggio_L_12:
;lampeggio.pbas,12 ::
end if
$0017 $
lampeggio_L_8:
;lampeggio.pbas,13 ::
delay_ms(500)
$0017 $3006
MOVLW
6
$0018 $00FC
MOVWF
STACK_12
$0019 $30FF
MOVLW
255
$001A $00FB
MOVWF
STACK_11
$001B $30FF
MOVLW
255
$001C $00FA
MOVWF
STACK_10
$001D $0BFC
DECFSZ
STACK_12,
$001E $2820
GOTO $+2
$001F $2827
GOTO $+8
$0020 $0BFB
DECFSZ
STACK_11,
$0021 $2823
GOTO $+2
$0022 $2826
GOTO $+4
$0023 $0BFA
DECFSZ
STACK_10,
$0024 $2823
GOTO $-1
$0025 $2820
GOTO $-5
$0026 $281D
GOTO $-9
$0027 $301A
MOVLW
26
$0028 $00FB
MOVWF
STACK_11
$0029 $30FF
MOVLW
255
$002A $00FA
MOVWF
STACK_10
$002B $0BFB
DECFSZ
STACK_11,
$002C $282E
GOTO $+2
$002D $2831
GOTO $+4
$002E $0BFA
DECFSZ
STACK_10,
$002F $282E
GOTO $-1
$0030 $282B
GOTO $-5
$0031 $3042
MOVLW
66
$0032 $00FA
MOVWF
STACK_10
$0033 $0BFA
DECFSZ
STACK_10,
$0034 $2833
GOTO $-1
$0035 $0000
NOP
$0036 $280C
GOTO lampeggio_L_2
;lampeggio.pbas,14 ::
wend
$0037 $2837
GOTO $
F
F
F
F
F
F
Le righe che iniziano con il ; sono annotazioni del programma e i comandi in mikrobasic.
Il mikrobasic è un linguaggio più semplice, ad alto livello, con cui non importa conoscere i
registri del pic, ma solo il linguaggio, esso integra molte librerie per gestire i vari registri senza
accedervi direttamente, un esempio di listato è questo (è sempre il solito di sopra, e dopo gli ‘
c’è le note, o commenti sul programma :D):
program lampeggio
main:
trisa = $FF
trisb = $FE
trisc = $FF
while true
if portb.0 = 0 then
portb.0 = 1
else
portb.0 = 0
end if
delay_ms(500)
wend
end.
‘Inizio del programma
‘Porta A in ingresso
‘Porta B in ingresso eccetto il bit 0
‘Porta C in ingresso
‘Ciclo infinito
‘Se il bit 0 della porta B è a 0
‘Lo porta a 1 (accende il led)
‘Sennò (cioè se il bit 0 della porta B è a 1)
‘Lo porta a 0 (spenge il led)
‘Fine del ciclo if
‘Attende 500ms per fare un lampeggio a 1 Hz
‘Fine del ciclo infinito (da qui riparte da capo…)
‘Fine del programma
Come si può notare è molto più semplice e corto come linguaggio, e una sola istruzione,
convertita in assembler, diventa anche 30 righe di codice (vedete il comando delay_ms(500),
che serve “semplicemente a attendere 500ms…)
Per scrivere il programma in formato *.hex dentro il pic, oltre al programmatore, abbiamo
bisogno (nel caso di programmatori autocostruiti) di un programma che invii tramite la seriale
il file al pic, per questo si usa IC-Prog o WinPic 800.
Che cosa serve
Programmatore (uno a scelta):
• PicKit2, interfaccia usb (microchip)
• Ludipipo (JDM), interfaccia seriale (autocostruito)
• MiniPropic2clone, interfaccia parallela (autocostruito)
Programmi di interfaccia col programmatore (non necessari con PicKit2):
• IC-Prog -> http://www.ic-prog.com/index1.htm
• WinPic 800 -> http://www.winpic800.com/index.php?lang=en
Compilatori:
• Assembler:
o MP LAB -> http://www.microchip.com
• Basic:
o MikroBasic -> http://www.mikroe.com/en/compilers/mikrobasic/pic/
o PicBasic ->
http://www.microengineeringlabs.com/products/index.htm#Compiler
o Proton DS -> http://www.picbasic.it/it/
• C:
o MikroC -> http://www.mikroe.com/en/compilers/mikroc/pro/pic/
o PicC -> http://www.htsoft.com/
• Pascal:
o MikroPascal -> http://www.mikroe.com/en/compilers/mikropascal/pic/
Pic (uno a scelta):
• 16F84A
• 16F628A
• 16F876A
• 16F877A
Programmi per disegno schemi elettrici (uno a scelta):
• Proteus (a pagamento)
• Electronic Workbench
Altro:
•
•
•
•
•
•
•
•
•
Conoscenze di elettronica
Manualità
Strumenti vari (cacciaviti, pinze, tronchesine etc…)
Bread-Board
Componenti elettronici (quarzi, condensatori, regolatori di tensione (7805), resistenze,
led, pulsanti, potenziometri etc…)
Alimentatore stabilizzato (va bene anche a 12-18V, va costruito il circuito per abbassare
a 5V però)
I DATASHEET dei componenti usati (alcune volte è mooooolto utile stamparseli…)
MOLTA PAZIENZA ma soprattutto
VOGLIA DI IMPARARE
I più usati
I pic più usati dagli hobbysti sono:
12F629 - 8 Pin
12F675 - 8 Pin
16F84A - 18 Pin
16F627A - 18 Pin
16F628A - 18 Pin
16F876A - 28-Pin
16F877A - 40-Pin
PIC
12F629
12F675
16F84A
16F627A
16F628A
16F876A
16F877A
Memoria
Programma
Numero
istruzioni
1024
1024
1024
1024
2048
8192
8192
RAM
EEPROM
(byte)
(byte)
64
64
68
224
224
368
368
128
128
64
128
128
256
256
I/O
6
6
13
16
16
22
33
ADC
4
5
8
CCP
PWM
1
1
2
2
MSSP
USART
SPI
I²C
Y
Y
Y
Y
Y
Y
Y
Y
Timer
8/16 bit
1/1
1/1
1/0
2/1
2/1
2/1
2/1
I Registri
Il PIC per poter gestire gli input e output, le varie periferiche e i timer usa dei registri, cioè
degli indirizzi di memoria specifici per ogni periferica.
La loro posizione varia da pic a pic, ma i compilatori accettano anche i nomi dei registri, che
invece sono statici (il registro TRISA si chiama TRISA in tutti i PIC che hanno questa porta,
cioè i 16F).
I registri possono esseri bloccati (bit non usati), in sola lettura e in lettura/scrittura, il valore
che essi devono acquisire può essere scritto in binario (mettendo il suffisso %), in esadecimale
(o HEX, suffisso $) e decimale (senza suffisso)
Alcuni di questi registri sono (prendo in esame quelli del 16F876A e 16F877A):
• TRIS(porta): dove (porta) è la lettera della porta, serve a indicare se i pin della porta
sono in ingresso o uscita (0 = uscita, 1 = ingresso), ad esempio:
o TRISA = %11110000
‘porta A, bit 0-3 in uscita e bit 4-7 in ingresso
o TRISB = $F0
‘porta B, bit 0-3 in uscita e bit 4-7 in ingresso
o TRISC = 240
‘porta C, bit 0-3 in uscita e bit 4-7 in ingresso
•
•
•
•
PORT(porta): dove (porta) è la lettera della porta, serve a leggere o
se a livello alto o basso (0 = basso, 1 = alto), ad esempio:
o PORTA = %11110000
‘porta A, bit 0-3 in a livello basso
o PORTB = $F0
‘porta B, bit 0-3 in a livello basso
o PORTC = 240
‘porta C, bit 0-3 in a livello basso
scrivere la (porta),
e bit 4-7 alti
e bit 4-7 alti
e bit 4-7 alti
INTCON: è il registro di attivazione generale dei interrupt
OPTION_REG: gestisce i pull-up delle porte, oltre a dei parametri del timer0 (prescaler,
sensibilità sul fronte di salita o discesa ecc…)
TMR(n): dove (n) è il numero del timer, è il registro che contiene il valore del conteggio
del timer (se a 8 bit va da 0 a 255, se a 10 da 0 a 1023 e se a 16 da 0 a 65535).
La descrizione dei settaggi e dei vari valori di essi la trovate sul datasheet, oltre alla mappa
della memoria:
I registri a 10 e 16 bit non possono essere letti direttamente, in quanto sono composti da due
registri differenti da 8 bit, un esempio è il TMR1L e TMR1H, che sono i due pezzi del TMR1.
Un modo per poterli leggere entrambi insieme è raggrupparli in un unico registro, senza doverli
leggere entrambi e raggrupparli via software è inserendo tra le variabili una con indirizzo di
memoria fisso, che inizia alla posizione del TMR1L e lunga 16 bit:
dim timer16bit as word absolute $0E volatile
La direttiva absolute indica al compilatore che questa variabile deve iniziare all’indirizzo $0E, e
essendo lunga 2 byte, comprende anche l’indirizzo $0F, cioè quello del TMR1H, raggruppandoli
in una sola variabile; la direttiva volatile indica che questo registro può cambiare senza la
scrittura di un dato da parte del programma (ad esempio quando è impostato come
contaimpulsi).