Comments
Transcript
I PIC Partendo da Zero - La 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).