Codice: Seleziona tutto
#include <p12F629.inc>
LIST P=12F629
__CONFIG (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _MCLRE_OFF & _CP_OFF )
; Costanti
#define STATOMAX 3 ; Il massimo numero valido per lo stato del sistema
; Variabili in RAM
CBLOCK 0x20
Delay1 ; Queste due variabili servono per generare un ritardo antirimbalzo di 100 millisecondi
Delay2 ; Con il clock interno a 4 MHz, il PIC esegue 1,000,000 istruzioni al secondo
Stato ; Memoria dello stato in cui si trova la lampada, 0 per spento, 1, 2, 3 con i vari LED accesi
; Ulteriori opzioni possono essere implementate aggiungendo valori alla lista degli stati
SalvaW ; Per salvare il registro W durante le interruzioni
SalvaS ; Per salvare il registro STATUS durante le interruzioni
MaxStato ; Il massimo numero valido per lo stato del sistema
ENDC
ORG 0x000 ; Eseguito all'accensione
GOTO Start
ORG 0x004 ; Eseguito all'arrivo di un interrupt
; Per il caso specifico, non occorre salvare e ripristinare W e STATUS ma lascio le linee commentate
; MOVWF SalvaW ; Salviamo W e STATUS prima di eseguire il codice ISR vero e proprio
; MOVF STATUS,W
; MOVWF SalvaS
BCF INTCON, GPIF ; Azzeriamo il bit di interrupt
; Per ora non facciamo niente altro
; MOVFW SalvaS ; Ricarichiamo i valori precedenti per W e STATUS
; MOVF STATUS,F
; MOVFW SalvaW
RETFIE
Start:
BSF STATUS, RP0 ; Passa in Bank 1 per accedere OSCCAL
CALL 3FFh ; Leggi il valore calibrato in fabbrica
MOVWF OSCCAL ; Trasferiscilo nel registro opportuno
MOVLW b'00111000' ; Da GP7 a GP0: NC, NC, IN, IN, IN, OUT, OUT, OUT
MOVWF TRISIO ; GP0, GP1 e GP2 sono uscite, GP3, GP4 e GP5 sono ingressi
BCF STATUS, RP0 ; Ritorna in Bank 0
MOVLW b'00111111' ; Per definire come digitali i pin devono essere disassociati dal Comparatore
MOVWF CMCON
MOVLW 0x00 ; Tutte le uscite a zero
MOVWF GPIO
MOVLW STATOMAX ; Massimo numero di stati
MOVWF MaxStato ; Usiamo una locazione di RAM perche' torna comodo dopo fare i confronti
MOVLW b'11001000' ; GIE = 1, PEIE = 1, GPIE = 1 per abilitare interruzioni da GPIO (GP5)
MOVWF INTCON ; Abilita gli interrupt da cambiamenti all'ingresso GP5
MOVLW 0x00 ; Lo stato iniziale del sistema e' 0 ossia lampada spenta
MOVWF Stato
Nanna:
SLEEP ; Mettiamo il micro in uno stato in cui non consuma molto e attendiamo
WakeUp:
NOP ; Quando il micro si risveglia parte da qui, mettiamo un NOP per sicurezza
INCF Stato, F ; Incrementiamo la variabile di stato
MOVF Stato, W ; Leggiamo il nuovo valore
SUBWF MaxStato, W ; Confrontiamo la variabile di stato con il suo massimo valore valido
; Se Stato < MaxStato, STATUS,Z = 0 e STATUS,C = 1
; Se Stato = MaxStato, STATUS,Z = 1 e STATUS,C = 1
; Se Stato > MaxStato, STATUS,Z = 0 e STATUS,C = 0 e il valore non e' valido
; Se Stato <= MaxStato, Status,Z = X ma STATUS,C = 1 e il valore e' valido
BTFSC STATUS, C ; Quindi se il bit STATUS,V non e' zero eseguiamo la prossima istruzione
GOTO Valido ; Il valode di Stato e' valido e possiamo continuare
CLRF Stato ; Ricominciamo la sequenza degli stati da zero
Valido:
MOVF Stato, W ; Ricarichiamo il valore della variabile di stato
MOVWF SalvaW
CALL LEDget ; Leggiamo i valori che devono prendere i LED
BCF STATUS, RP0
MOVWF GPIO ; E scriviamoli nelle uscite che comandano i LED
CALL Aspetta ; Aspettiamo alcune decine di millisecondi per eliminare i rimbalzi del bottone
GOTO Nanna ; Torniamo ad addormentare il micro
LEDget:
; Aggiungendo linee alla fine di questa tabella (e modificando il valore di STATOMAX) permetti di aggiungere nuovi
; stati di operazione, per esempio un nuovo stato 4 con tutti e tre i LED accesi (maschera b'00000111').
ADDWF PCL, F ; W contiene l'indice dello Stato per recuperare dalla tabella il valore di GPIO giusto
RETLW b'00000000' ; Stato = 0, i tre LED collegati a GP0, GP1 e GP2 sono spenti
RETLW b'00000001' ; Stato = 1, i LED collegati a GP1 e GP2 sono spenti, quello collegato a GP0 e' acceso
RETLW b'00000010' ; Stato = 2, i LED collegati a GP0 e GP2 sono spenti, quello collegato a GP1 e' acceso
RETLW b'00000100' ; Stato = 3, i LED collegati a GP0 e GP1 sono spenti, quello collegato a GP2 e' acceso
Aspetta:
MOVLW d'100' ; Aspettiamo 100 millisecondi, 1000 microsecondi alla volta
MOVWF Delay1
Ciclo1:
CALL Aspetta1ms
DECFSZ Delay1, F ; Siamo arrivati a 100 millisecondi?
RETURN ; Si', basta aspettare
GOTO Ciclo1 ; No, aspettiamo un altro millisecondo
Aspetta1ms:
; Questa subroutine aspetta 1000 cicli ossia 1000 microsecondi a 4 MHz
MOVLW d'200' ; 1 microsecondo
MOVWF Delay2 ; 1 microsecondo
Ciclo2:
; Il codice che segue prende 5 cicli ossia 5 microsecondi ogni volta che gira tranne l'ultima
GOTO $+1 ; 2 microsecondi
DECFSZ Delay2, F ; 1 microsecondo se Delay2 > 0, 2 microsecondi se Delay2 = 0
RETURN ; 2 microsecondi
GOTO Ciclo2 ; 2 microsecondi
END