Vai Indietro   PcTuner Forum > Sezione Hardware > Programmazione PIC
Arcade Registrazione Blogs Regolamento Feedback FAQ Lista Utenti Calendario Segna come Letti

Ultimi 5 blog pubblicati su PcTuner Blog
Data Titolo

Rispondi
 
Strumenti Discussione Modalità Visualizzazione
Vecchio 21-01-2005, 20.53.38   #1
Super Moderator
 
L'avatar di  FluidGuitar
 

Iscritto da: 04-01-2001
Locazione: Torino
Messaggi: 4,023
Feedback: (0)
Firmware di controllo WaterStation

Immagino che molti di voi abbiano letto o dato uno sguardo all'articolo che ho scritto qualche tempo fa sulla mia waterstation.
Visto che la neonata sezione PIC ha bisogno di una spintarella ho pensato di rispolverarlo per trasformarlo in argomento di discussione.
Il motivo è che il cuore della waterstation è un glorioso 16F84 che si occupa di fare un po' di cose interessanti, quindi, se anche buona parte del programma è finalizzato al progetto specifico, con un po' di pratica se ne possono estrapolare parti utili a tutti e soprattutto toccare con mano la programmazione del microcontrollare.
Spero che questo serva a "rompere il ghiaccio" per chi ogni volta, armato di buona volontà, arriva alla pagina bianca del MPLab e si ferma esclamando "e mo da dove comincio?!?".

Vorrei quindi iniziare un commento "riga per riga" del programma con tutte le spiegazioni del perchè e per come le cose siano state fatte in un certo modo anche da un punto di vista delle scelte circuitali effettuate.

Spero solo di avere un minimo di feedback in questo topic visto che non sarebbe bello impantanarmi in un soliloquio, quindi per adesso inizio ad esporre solo la prima parte del programma per vedere se la cosa suscita un minimo di interesse.

Codice:
;________________________________________________________
;
;	
;			FluidStation
;	
;			ver 1.0 (senza standby)
;________________________________________________________


        PROCESSOR       16F84a
        RADIX           DEC
        INCLUDE         "P16F84a.INC"
        ERRORLEVEL      -302, -305
        
        ;PIC configuration flags
        __CONFIG        0x3FF1		;XT oscillator
									;Disable watch dog timer
									;Enable power up timer
									;Disable code protect

cod_1 equ 11H			;\
cod_2 equ 6BH			; |
cod_3 equ 5BH			; |
cod_4 equ 1DH			; |
cod_5 equ 5EH			; |
cod_6 equ 7EH			;  >Codici per le 10 cifre + Error +Low + High
cod_7 equ 13H			; |
cod_8 equ 7FH			; |
cod_9 equ 5FH			; |
cod_0 equ 77H			; |	
cod_E equ 6EH			; |
cod_L equ 64H			; |
cod_H equ 3DH			;/
La versione del programma è quella presente anche nell'articolo.
Successivamente ho modificato il programma per risolvere il problema dell'avviamento sbagliato delle L25. La soluzione non è definitiva ma funziona nel 99% degli avviamenti. Ma di questo parleremo eventualmente più avanti.

Le prime righe del codice sono direttive per il compilatore (mi riferisco all'MPLab scaricabile dal sito della microchip).

Si dichiara di utilizzare il 16F84A e si dice al compilatore che i numeri presenti nel codice saranno da interpretare come numeri decimali.
Si include un file di intestazione tipico del dispositivo che andremo ad usare; in tale file sono definiti dei nomi simbolici per identificare i registri e le porte del PIC.
Si disattivano i messaggi 302 e 305 che il compilatore mostra ad ogni compilazione (provate ad eliminare questa riga per scoprire quali siano... sono solo una noia, tanto vale disattivarli).

Si definisce il valore del CONFIGURATION REGISTER.
Si tratta di un valore a 14 bit che viene scritto in fase di programmazione del PIC e il significato di ciascun bit è documentato sul datasheet.
Nel nostro caso dobbiamo:
settare a 1 i bit dal 14 al 4: in questo modo evitiamo di attivare la protezione del codice
settare a 1 il bit 3: in questo modo attiviamo il Power Up timer
settare a 0 il bit 2: in questo modo disattiviamo il Watch Dog Timer
settare a 10 i bit 1 e 0: in questo modo attiviamo la modalità High Speed per l'oscillatore esterno.

Traducendo in esadecimale la parola binaria così costruita si ottiene il valore 3FF1 che è quello che andremo ad impostare.


To be continued...
__________________

Tu non sai niente, Jon Snow!

Ultima Modifica di FluidGuitar : 18-08-2006 21.53.32.
FluidGuitar Non in Linea   Rispondi Citando
Vecchio 22-01-2005, 02.22.04   #2
..:: Artista ::..
 
L'avatar di  nipponchallenge
 

Iscritto da: 20-09-2002
Locazione: HK
Messaggi: 2,511
Feedback: (0)
evvai, quando si parla di pic...

io mi iscrivo al topic!
__________________
powered by Ybris Stealth n°012 - ubi maior minor cessat
nipponchallenge Non in Linea   Rispondi Citando
Vecchio 22-01-2005, 08.01.27   #3
Super Moderator
 
L'avatar di  FluidGuitar
 

Iscritto da: 04-01-2001
Locazione: Torino
Messaggi: 4,023
Feedback: (0)
Dopo la configurazione del dispositivo ci sono ancora delle direttive per il compilatore: le "equ".

Codice:
cod_1 equ 11H			;\
cod_2 equ 6BH			; |
cod_3 equ 5BH			; |
cod_4 equ 1DH			; |
cod_5 equ 5EH			; |
cod_6 equ 7EH			;  >Codici per le 10 cifre + Error +Low + High
cod_7 equ 13H			; |
cod_8 equ 7FH			; |
cod_9 equ 5FH			; |
cod_0 equ 77H			; |	
cod_E equ 6EH			; |
cod_L equ 64H			; |
cod_H equ 3DH			;/
La direttiva "equ" serve a definire di nomi mnemonici in sostituzione di valori numerici.
Non si tratta di variabili ma di costanti; in fase di compilazione saranno sostituite dal rispettivo valore esadecimale.

Per inciso avrete notato che, avendo definito la radice numerica decimale, per esprimere un numero in esadecimale è necessario e sufficiente posporre una H alla fine del numero. Per i valori binari basta aggiungere una B.

In questa parte del programma definisco dei valori che mi serviranno per la visualizzazione sul display.
Credo che questa sia l'aspetto più "custom" del progetto in quanto si basa sull'utilizzo di un integrato molto particolare il "M5480" della ST.

Non ho indagato sulla reperibilità di questo integrato; io l'ho recuperato da un vecchio decoder di tele+ e l'ho trovato decisamente comodo.
E' in grado di pilotare direttamente display a 7 segmenti ad anodo comune per un totale di 23 segmenti.
Il controllo avviene trasmettendo una parola di 35 bit più un bit di start.
Quindi l'occupazione in termini di porte del pic si riduce ad una porta per il dato e una per il clock.
I codici di cui sopra sono stati costruiti assegnando un bit ad ogni segmento in modo abbastanza arbitrario secondo come sono stati collegati i singoli segmenti dei display al controller.
Faccio notare che nello stabilire questi collegamenti non ho minimamente ottimizzato la facilità di collegamento quanto lafacilità di scrittura del codice. A posteriori mi sono reso conto che sarebbe stato più furbo fare il contrario, ma quando l'ho fatto ero alle prime armi con i PIC e in seguito non ho più avuto voglia di riscrivere il codice.



Il codice prosegue così:


Codice:
	ORG     00H			;Reset Vector - Punto di inizio del programma al reset della CPU
	goto start

;_______Interrupt Vector - Punto d'inizio delle routines di interrupt handling_______________
;		Routine che serve a generare un'onda quadra sul pin RA0 alla frequenza di circa 400Hz

	ORG		04H			
	goto	interrupt_handler
	ORG		0CH
start
Qui troviamo un'altra direttiva: la "ORG".
Si tratta di una informazione data al compilatore su dove piazzare il codice nella memoria del PIC.

Al momento del reset il program counter è posizionato sull'indirizzo 00H e li metteremo la prima istruzione che vogliamo sia eseguita all'accensione o al reset del dispositivo.

In questo caso si verifica subito un salto incondizionato ("goto") che ci porta in un'altra posizione.

All'indirizzo 04H si trova l'interrupt vector: il punto in cui salta il program counter quando si verifica un interrupt.



To be continued....
__________________

Tu non sai niente, Jon Snow!

Ultima Modifica di FluidGuitar : 18-08-2006 21.56.12.
FluidGuitar Non in Linea   Rispondi Citando
Vecchio 22-01-2005, 08.40.16   #4
Ic designer in OC
 

Iscritto da: 02-03-2003
Locazione: friuli venezia giulia
Messaggi: 1,159
Feedback: (2)
segnato
__________________
Daily use oc system:: none
zziplex Non in Linea   Rispondi Citando
Vecchio 22-01-2005, 11.50.44   #5
Registered User
 

Iscritto da: 18-02-2002
Locazione: Cagliari
Messaggi: 4,297
Feedback: (1)
questa è manna dal cielo fluid.. grazie tante mi serve molto visto che mi stanno arrivando un paio di sample per iniziare a giochicchiare con i pic
__________________
i'm proud to be a yadayada lammah
Hunty Non in Linea   Rispondi Citando
Vecchio 22-01-2005, 12.51.11   #6
Super Moderator
 
L'avatar di  FluidGuitar
 

Iscritto da: 04-01-2001
Locazione: Torino
Messaggi: 4,023
Feedback: (0)
Continuiamo ad analizzare il codice.

Ovviamente ogni commento/critica è gradito sia per correggere eventuali errori sia per avere occasioni di approfondimento; questo è un invito sia a chi ne vuole sapere di più, sia a chi ne sa di più dal momento che la mia esperienza non è che sia tantissima.

Il programma continua così:

Codice:
	ORG		0CH
start

;____________________Configurazione Generale____________________________________    

Display_u	res 1		;8 bit per unità
Display_d	res 1		;8 bit per decine
Display_c	res 1		;8 bit per le centinaia anche se non servono
Delay		res 1		;Delay per il mezzo clock
LoopDelay	res 1		;Delay per il mezzo clock ausiliaria
BitCount	res 1		;Contatore bit trasmessi
uni			res	1		;unità
dec			res	1		;decine
cen			res	1		;centinaia
loops		res 1
loops2		res 1
KEY			res 1
count		res 1
ds1820		res 1
temp1		res 1		;byte alto della temperatura letto dalla sonda
temp2		res 1		;byte basso della temperatura letto dalla sonda
d1			res 1
d2			res 1
d3			res 1
errore		res 1		;variabile da usare come flag
temp3		res 1		;variabile temporanea per conversione temperatura
Pintera		res 1
Pdecimale	res 1



;___________  Sezione di configurazione delle porte e del prescaler  ____________________

        bsf     STATUS,RP0		;Commuta sul secondo banco dei registri

		;Configurazione del Timer
        ;Assegna il PRESCALER a TMR0 e lo configura a 1:4

        movlw   01000001B		;T0CS=0, PSA=0, PS2-PS1-PS0=100 ->1/4 --- INTEDG = 1
        movwf   OPTION_REG 		;250000 / 258 = 976.6 Hz ->onda quadra a 488.3 Hz

        ;Definizione delle linee di I/O (0=Uscita, 1=Ingresso)

        movlw   00001010B
        movwf   TRISA
;RA0->USCITA PWM						RB0->INGRESSO LINEA DAL PC
;RA1->INGRSSO SENS LIVELLO				RB1->USCITA LINEA VERSO IL PC
;RA2->ACCENSIONE DISPLAY				RB2->RELE' VENTOLA
;RA3->USCITA SENSORE TEMP				RB3->RELE' POMPE
;RA4->INGRESSO SENSORE TEMP				RB4->SEGNALE ALLARME
;										RB5->SWITCH VENTOLA
;										RB6->DISPLAY CLOCK
;										RB7->DISPLAY DATO

        movlw   00100001B
        movwf   TRISB

		clrf	INTCON
		bcf		INTCON,T0IE		;Abilitazione del Timer Overflow

		bcf		INTCON,RBIE		;Abilitazione interrupt su RB4-RB7
        bcf     STATUS,RP0      ;Commuta sul primo banco dei registri
		bcf		INTCON,GIE		;Global Interrupt Enable
Intanto notiamo la presenza di un'etichetta: "start".
Un'etichetta è ancora una volta una istruzione per il compilatore il quale prende nota della locazione di memoria in cui è situata per effettuare dei salti in quel punto.

In questo caso l'etichetta si trova subito dopo la direttiva ORG quindi "goto start" equivale a "goto 0CH"!

Dalla locazione 0CH inizia una serie di direttive che definiscono le variabili utilizzate nel programma.

Si utilizza la direttiva "res" la quale dice al compilatore di "riservare" un numero di byte specificato e di riferirsi a qualla locazione con l'etichetta specificata.

Quindi

Display_u res 1

significa che dalla locazione corrente, cioè 0CH, per la lunghezza di un byte (quindi di fatto solo la locazione 0CH) non sarà utilizzata dal compilatore per metterci delle righe di codice eseguibile ma verrà laasciata libera e etichettata col nome "Display_u".
E così via per tutte le altre variabili.

Tale cella di memoria si trova in una zona di memoria detta GPR da General Purpose Register. Si tratta di un insieme di registri di memoria RAM in cui si possono memorizzare dei valori anche a Run-Time e quindi di fatto ogni etichetta assegnata a tali locazioni è utilizzabile a tutti gli effetti come una variabile.

Bisogna fare solo un poco di attenzioe a non confondere l'assembly con un linguaggio ad alto livello.
Tali variabili sono SEMPRE e comunque delle parole a 8 bit che il processore tratta come interi in complemento a 2 e corrispondono a registri fisici della RAM: lo scope è a livello di programma, non di routine!
Quindi, nel prosieguo, quando anche si faranno delle chiamate a subroutine, non bisogna dimenticarsi che le variabili che si usano sono sempre globali ed evitare di utilizzarle in modo spregiudicato da una routine all'altra.

Sembra una precisazione ovvia ma essendo abituati ad utilizzare un linguaggio ad alto livello in cui tendenzialmente le varibili sono locali si rischia di prendere delle cantonate e di metterci un bel po' prima di accorgersene.

Non sto qui a commentare la funzione di ciascuna variabile perchè non se ne capirebbe subito l'utilità; meglio rimandare a quando saranno utilizzate nel programma.

Vale la pena di commentare invece la parte di configurazione e dire qualcosa sullo STATUS REGISTER.

Ma questo lo vedremo più avanti

Continua...
__________________

Tu non sai niente, Jon Snow!

Ultima Modifica di FluidGuitar : 18-08-2006 21.58.22.
FluidGuitar Non in Linea   Rispondi Citando
Vecchio 23-01-2005, 00.37.40   #7
Amministratore
 
L'avatar di  Luigi
 

Iscritto da: 27-12-2000
Locazione: Torino
Messaggi: 19,699
Feedback: (0)
Inserzione Blog: 7
Quote:
Originariamente inviato da Hunty
questa è manna dal cielo fluid.. grazie tante mi serve molto visto che mi stanno arrivando un paio di sample per iniziare a giochicchiare con i pic
ragazzi chiedete cio che vi serve, se possiamo affrontiamo l'argomento
__________________
Basta attendere per capire....
Luigi ora è in linea   Rispondi Citando
Vecchio 23-01-2005, 10.36.12   #8
Super Moderator
 
L'avatar di  FluidGuitar
 

Iscritto da: 04-01-2001
Locazione: Torino
Messaggi: 4,023
Feedback: (0)
Spendiamo adesso due parole per descrivere lo STATUS REGISTER.

Il registro di stato è una locazione di memoria che fa parte degli SFRs, cioè degli Special Function Registers.
Si tratta di un insieme di registri che assolvono a varie funzioni e di cui parleremo man mano che li incontriamo.

Vorrei solo ricordare che tutte le informazioni sull'hardware e sulla costituzione interna del PIC sono estratte pari pari dal datasheet del componente sul quale con un po' di pazienza si reperiscono tutte le informazioni necessarie ad utilizzare le varie funzionalità del processore.

Lo status register è un registro ad 8 bit_

bit 7- IRP: selezione del banco per indirect addressing
i PIC permettono di indirizzare la memoria in modo indiretto mediante una specie di puntatore; il bit 7 dello status register serve a specificare a quale banco di memoria si riferisce il puntatore. Nel 16F84A tale bit non è implementato e la microchip consiglia di lasciarlo a 0.

bit 6/5 - RP1/RP0: selezione del banco di memoria
la memoria del PIC è organizzata in banchi da 128 byte. Nel 16F84A ci sono 2 banchi, il banco 0 e il banco 1 ed è lo status register che decide qual'è il banco attivo istante per istante sulla base del valore del bit 5 (RP0). Se il bit 5 è 0 è attivo il banco 0, se il bit 5 è 1 è attivo il banco 1. Il bit 6 serve ad indirizzare altri banchi di memoria nei pic che li possiedono (es. il 16F877). Nel nostro caso il valore di RP1 non ha importanza ma la microchip consiglia di lasciarlo a 0.
Il passaggio dal banco 0 al banco 1 può essere fatto a Run-Time ed è indispensabile per poter leggere o scrivere gli SFR che vi sono contenuti. Gli Special Function Registers occupano le prime 12 locazioni di ciascun banco e le restanti rappresentano della RAM liberamente utilizzabile nei programmi.
Per l'uso di questa ram però è indifferente la selezione del banco in quanto gli indirizzi del banco 1 sono mappati sullo 0.
Questo significa che se punto alla locazione 8C che si trova nel banco 1 effettivamente leggo/scrivo nel registro 0C che si trova nel banco 0. La gestione dei banchi può sembrare macchinosa ma, almeno nel 16F84A, si riduce a qualche piccola accortezza di tanto in tanto in quanto di fatto ho necessità di attivare il banco 1 solo sporadicamente quando devo usare i registri speciali che vi sono contenuti.

bit 4 - TO: bit (negato) di time out
è un bit che è normalmente posto a 1 e diviene 0 quando si verifica un time out del Watch Dog Timer. Il WDT non è utilizzato nel progetto in esame quindi per chi volesse saperne di più rimando al datasheet.

bit 3 - PD: bit (negato) di Power Down
è un bit che è normalmente a 1 e diviene 0 quando il pic riceve una istruzione di sleep.

bit 2 - Z: zero bit
insieme al bit 0 è uno dei più importanti: diventa 1 quando il risultato di una operazione aritmetica o logica è zero.

bit 1 - CD: digit carry bit
diventa 1 quando una operazione matematica produce un overflow oltre il 4 bit

bit 0 - C: carry bit
è il bit di riporto; diventa 1 quando si produce un overflow oltre l'ottavo bit.


I bit 0 e 1 hanno anche la funzione di borrow (neg) nelle sottrazioni ricordando che le sottrazioni sono effettuate in complemento a 2.

Continua...
__________________

Tu non sai niente, Jon Snow!
FluidGuitar Non in Linea   Rispondi Citando
Vecchio 23-01-2005, 13.37.32   #9
Guaranteed Entropy Mod
 
L'avatar di  GByTe
 

Iscritto da: 30-10-2003
Locazione: Milano
Messaggi: 20,570
Feedback: (3)
scrib scrib... sottoscritto il 3d
__________________
~ ~
~ Memento Audere Semper. ~ Ingegneria Italiana anni '80
~ La moderazione è una cosa fatale. Nulla ha più successo dell'eccesso. [Oscar Wilde]
~ È la realtà, spesso, ad essere inesatta. [Douglas Adams]
GByTe Non in Linea   Rispondi Citando
Vecchio 23-01-2005, 14.25.18   #10
Super Moderator
 
L'avatar di  FluidGuitar
 

Iscritto da: 04-01-2001
Locazione: Torino
Messaggi: 4,023
Feedback: (0)
Prima di andare avanti con l'esame del codice è necessario parlare di un altro registro molto importante: lo OPTION REGISTER.

L'option register si trova nel banco 1, quindi per modificarne il contenuto è necessario prima attivare il banco 1 attraverso lo status register.

Vediamo la funzione dei singoli bit dell'option register:

bit 7 - RBPU (negato): abilita le resistenze di pull-up della porta B;
il pic ha due porte di input/output denominate A e B. Quando un pin della porta B è configurato come input ed è lasciato scollegato, attivando le resistenze interne di pull-up è possibile stabilizarne ad 1 lo stato.

bit 6 - INTEDG: fronte di riferimento per l'interrupt;
è possibile attivare un interrupt sul pin 0 della porta B. Se questo bit è posto a 1 l'interrupt avviene sul fronte di salita del segnale sul piedino 0.

bit 5 - T0CS: sorgente per il Timer 0;
il pic ha un timer interno che può avere alternativamente segnali di clock: se il bit 5 è posto a 1 viene preso un segnale presente sul pin 4 della porta A, altrimenti si utilizza il clock interno.

bit 4 - T0SE: fronte di riferimento del clock per il timer;
nel caso in cui sia stato selezionato un clock esterno con questo bit si controlla se il timer debba essere incrementato quando il segnale sul pin 4 si abbassa (T0SE=1) o si alza (T0SE=0).

bit 3 - PSA: assegnazione del prescaler;
fra la sorgente del clock e il contatore del timer è possibile interporre un divisore detto prescaler. Dal momento che il pic oltre al timer 0 ha anche il watch dog timer con questo bit si può decidere di assegnare il prescaler all'uno o all'altro (PSA=1->prescaler assegnato al WDT).

bit 2:0 - PS2:PS0: valore del prescaler;
decide il rapporto di divisione per il prescaler secondo la seguente tabellina:

valore - TMR0 - WDT
000 1/2 1/1
001 1/4 1/2
010 1/8 1/4
011 1/16 1/8
101 1/32 1/16
101 1/64 1/32
110 1/128 1/64
111 1/256 1/128

Adesso abbiamo gli strumenti per capire il significato delle successive righe di codice.

Continua...
__________________

Tu non sai niente, Jon Snow!
FluidGuitar Non in Linea   Rispondi Citando
Vecchio 23-01-2005, 20.05.37   #11
Super Moderator
 
L'avatar di  FluidGuitar
 

Iscritto da: 04-01-2001
Locazione: Torino
Messaggi: 4,023
Feedback: (0)
Riprendiamo questa parte di codice:

Codice:
       bsf     STATUS,RP0		;Commuta sul secondo banco dei registri

		;Configurazione del Timer
        ;Assegna il PRESCALER a TMR0 e lo configura a 1:4

        movlw   01000001B		;T0CS=0, PSA=0, PS2-PS1-PS0=100 ->1/4 --- INTEDG = 1
        movwf   OPTION_REG 		;250000 / 258 = 976.6 Hz ->onda quadra a 488.3 Hz

        ;Definizione delle linee di I/O (0=Uscita, 1=Ingresso)

        movlw   00001010B
        movwf   TRISA
;RA0->USCITA PWM                         RB0->INGRESSO LINEA DAL PC
;RA1->INGRSSO SENS LIVELLO                         RB1->USCITA LINEA VERSO IL PC
;RA2->ACCENSIONE DISPLAY                         RB2->RELE' VENTOLA
;RA3->USCITA SENSORE TEMP                         RB3->RELE' POMPE
;RA4->INGRESSO SENSORE TEMP                         RB4->SEGNALE ALLARME
;                                                                           RB5->SWITCH VENTOLA
;                                                                           RB6->DISPLAY CLOCK
;                                                                           RB7->DISPLAY DATO

        movlw   00100001B
        movwf   TRISB
Incontriamo la prima vera istruzione per il PIC: la bsf (che sta per Bit Set F)

Si tratta di una operazione che opera sul singolo bit del registro specificato e accetta come argomento il numero del bit da impostare a 1.
Quindi:

bsf STATUS,RP0

non fa altro che impostare a 1 il bit RP0 del registro STATUS di cui abbiamo parlato prima.

Faccio notare che se avessi scritto:

bsf 03H,5

avrei ottenuto lo stesso risultato in quanto il registro di Status si trova alla locazione esadecimale 03 e il bit RP0 è il quinto.

Come detto poco sopra mettere a 1 il bit RP0 significa commutare sul banco 1 l'accesso alla memoria; questo è necessario in quanto vogliamo impostare il valore dell'option register che si trova appunto nel banco 1.

Incontriamo altre 2 istruzioni del PIC:

movlw (MOVe Literal W): mette il valore "letterale" nell'accumulatore

movwf (MOV W to F): mette il valore dell'accumulatore nel registro f.

Il PIC essendo un processore risc con parola da 14 bit non è in grado di spostare direttamente il contenuto di una cella di memoria ad un'altra.
Tutti gli spostamenti avvengono passando da uno speciale registro detto "accumulatore" e indicato con W.
Anche le operazioni aritmetiche e booleane hanno come uno dei due argomenti sempre l'accumulatore.

In questo caso eseguiamo le seguenti operazioni:

movlw 01000001B

cioè mettiamo nell'accumulatore il valore "letterale" 01000001 e in seguito:

movwf OPTION_REG

spostiamo il contenuto dell'accumulatore nell' option register.
Questo ci risparmia di impostare uno ad uno i bit del registro in oggetto.
Il significato di ciascuno dei bit è chiaro per quanto detto poco sopra sull'option register.
Avevo bisogno di generare un'onda quadra permanente su uno dei piedini e, per far questo in modo trasparente al resto del programma, ho deciso di sfruttare il timer interrupt di cui parleremo fra poco.
In questa sede sto assegnando il prescaler al timer0 e lo sto configurando in modo da avere gli interrupt ad una frequenza di
circa 976Hz.

L'operazione di impostare un valore a 8 bit per un intero registro viene eseguita subito dopo con due altri importanti registri del banco 1: TRISA e TRISB.

Il contenuto dei registri TRISA e TRISB decide rispettivamente per la porta A e la porta B il funzionamento di ciascun PIN.
La porta A ha 5 PIN che corrispondono ai primi 5 bit del registro TRISA e la porta B ha tutti e 8 i PIN mappati sul TRISB.
Se nel registro TRIS un bit è impostato a 1 quel piedino si comporta come un ingresso, altrimenti come un'uscita.

Nota Bene: all'accensione e al reset del dispositivo i registri TRIS sono impostati a 1 per tutti i pin, cioè per default i piedini del pic sono degli ingressi.


Nel codice è chiaramente commentata la funzione di ciascun piedino.

Continua...
__________________

Tu non sai niente, Jon Snow!

Ultima Modifica di FluidGuitar : 18-08-2006 22.01.28.
FluidGuitar Non in Linea   Rispondi Citando
Vecchio 24-01-2005, 20.21.35   #12
Super Moderator
 
L'avatar di  FluidGuitar
 

Iscritto da: 04-01-2001
Locazione: Torino
Messaggi: 4,023
Feedback: (0)
Prima di continuare con l'esame del codice è necessario studiare la struttura di un altro importante registro: lo INTCON (INTerrupt CONfiguration).

Il significato dei singoli bit è il seguente:

bit 7 - GIE: abilitazione generale degli interrupt
se messo a 1 gli interrupt sono abilitati.

bit 6 - EEIE: fine scrittura sulla eprom
mettendo a 1 questo bit si verificherà un interrup alla fine di una operazione di scrittura sulla eprom interna del pic.

bit 5 - T0IE: interrupt sul timer overflow
abilita l'interrupt quando il contatore del timer raggiunge il massimo valore (255). Come già detto la velocità con cui si incrementa tale contatore dipende dall'impostazione del prescaler.

bit 4 - INTE: interrupt sul piedino RB0
abilita l'interrupt quando viene rilevato un impulso sul piedino 0 della porta B. Come già detto il registro di configurazione controlla se l'impulso viene rilevato sul fronte di salita o sul fronte di discesa del segnale.

bit 3 - RBIE: interrupt sui piedini 4:7 della porta B
una variazione di stato su uno di questi piedini (se configurati come ingresso ovviamente) genera un interrupt.

bit 2 - T0IF: flag per il timer interrupt
viene messo a 1 dal verificarsi dell'interrupt sul timer 0

bit 1 - INTF: flag per l'interrupt su RB0
viene messo a 1 dal verificarsi dell'interrupt sul piedino RB0

bit 0 - RBIF: flag per l'interrupt su RB4:RB7
viene messo a 1 dall'interrupt sul cambiamento della porta B.

Il verificarsi di uno qualsiasi degli interrupt abilitati provoca l'interruzione del programma principale e il salto alla locazione 04H.
Per discriminare quale interrupt si sia verificato è necessario controllare lo stato dei bit 0, 1, e 2 e ricordarsi di rimetterli eventualmente a 0 per permettere all'interrupt di verificarsi nuovamente.

Continua...
__________________

Tu non sai niente, Jon Snow!
FluidGuitar Non in Linea   Rispondi Citando
Vecchio 25-01-2005, 19.38.27   #13
Super Moderator
 
L'avatar di  FluidGuitar
 

Iscritto da: 04-01-2001
Locazione: Torino
Messaggi: 4,023
Feedback: (0)
Adesso che sappiamo come interpretare il registro di configurazione degli interrupt hanno un senso le seguenti righe del codice:

Codice:
		clrf	INTCON
		bcf		INTCON,T0IE		;Abilitazione del Timer Overflow

		bcf		INTCON,RBIE		;Abilitazione interrupt su RB4-RB7

        bcf		INTCON,GIE		;Global Interrupt Enable		
        bcf     STATUS,RP0      ;Commuta sul primo banco dei registri
Si tratta di istruzioni di inizializzazione che vengono effettuate solo all'avvio del microcontrollore quindi si disattivano tutti gli interrupt per riattivarli nel corso del programma quando sarà effettivamente necessario. Meno cose si lasciano al caso, meglio è!

Subito dopo vi sono altre istruzioni di inizializzazione:

Codice:
;______Inizializzazione delle variabili___________________

	clrf	Display_u
	clrf	Display_d
	clrf	Display_c
	clrf	errore

	bcf		PORTA,0
	bsf		PORTA,4
	bcf		PORTA,2

	bcf		PORTB,1
	bcf		PORTB,2
	bcf		PORTB,3				;spegne le pompe
	bcf		PORTB,6
	bcf		PORTB,7
	bcf		PORTB,4
;________________________________________________________
In cui si azzerano alcuni piedini delle porte di uscita e alcune variabili.

Sono state usate due nuove istruzioni:

bcf= Bit Clear F che serve a porre a 0 il bit specificato analogamente a come la bsf lo metteva a 1

clrf= Clear F che serve ad azzerare un intero registro.

Con la prossima istruzione vedremo come realizzare delle subroutine in asm.

Continua...
__________________

Tu non sai niente, Jon Snow!

Ultima Modifica di FluidGuitar : 18-08-2006 22.03.54.
FluidGuitar Non in Linea   Rispondi Citando
Vecchio 26-01-2005, 22.14.48   #14
Super Moderator
 
L'avatar di  FluidGuitar
 

Iscritto da: 04-01-2001
Locazione: Torino
Messaggi: 4,023
Feedback: (0)
Dopo queste fasi preliminari di configurazione e inizializzazione inizia il programma vero e proprio.

Codice:
	call	test_allarme
Si inizia subito con una chiamata ad una subroutine:

Codice:
;________________Routines controllate dall'interrupt_________________________________________

test_allarme
	bcf		INTCON,GIE		;disabilito interrupt
	bcf		PORTB,4
	call	delay_1s
	bsf		PORTB,4
	call	delay_15ms
	call	delay_15ms
	bcf		PORTB,4
	call	delay_1s
	bsf		PORTB,4
	call	delay_15ms
	call	delay_15ms
	bcf		PORTB,4
	call	delay_1s
	bsf		PORTB,4
	bcf		errore,1
	bsf		INTCON,GIE			;riabilito interrupt
	return
Per capire il significato di questa routine bisogna premettere che la waterstation è collegata al computer da 2 fili + la massa.
Su un filo viaggia il segnale che segnala alla waterstation che il computer è acceso; si tratta di un filo che prende i 5 volt direttamente da molex con una resistenza di sicurezza in serie.
Il secondo filo invece serve alla waterstation per segnalare al computer che è tutto a posto.
In realtà questo filo serve solo a mantenere spento una schedina di allarme che viene alimentata direttamente dal pc. Se la waterstation è spenta o scollegata l'allarme suona.
Il filo che mantiene spento l'allarme è collegato al piedino 4 della porta B e, all'avviamento della waterstation viene chiamata questa routine che non fa altro che mettere a 0 per 3 volte il piedino di allarme col preciso scopo di farlo suonare! Si tratta cioè di un check per verificare che il circuito di allarme funzioni correttamente.
In realtà quell'allarme è talmente fastidioso che in seguito ho modificato il codice per fargli fare solo un beep anzichè tre, ma qui volevo commentare il codice originale dell'articolo

In questa porzione di codice troviamo l'istruzione "call".
Si tratta dell'istruzione che permette di fare il salto ad una subroutine specificata da una label lungo il listato quindi se scorriamo il codice fin verso la fine troviamo la porzione che ho postato poche righe sopra.
Notiamo che la subroutine termina con l'istruzione "return".

Spendiamo due parole sulla coppia "call" - "return".

Nell'assembler del PIC l'uso delle subroutine, se anche permette di compattare il codice (cosa buona visto che la memoria non è tantissima), non è comunque da prendere alla leggera.
Infatti il PIC possiede uno stack a soli 8 livelli.
Questo significa che non possiamo nidificare più di 8 chiamate succesive a subroutine.
Infatti la call non fa altro che eseguire un "push" dell'indirizzo della successiva istruzione nello stack ed esegue un salto alla locazione indicata dalla label.
Successivamente la return eseguirà il "pop" di tale valore e lo rimetterà nel program counter.
Se la subroutine contiene al suo interno altre sub il valore del nostro intirizzo verrà spostato più in profondità nello stack e così via.
Siccome lo stack contiene al massimo 8 indirizzi, se eseguiamo 8 call senza nessuna return lo stack sarà pieno e una ulteriore call causerà la perdita del primo indirizzo memorizzato.
Lo stack funziona secondo una logica LIFO: Last Input First Output - l'ultimo valore immesso è il primo ad uscire.

La routine "test_allarme" fa le seguenti cose:

-disabilita la gestione degli interrupt
-azzera il piedino 4 della porta B: in questo modo l'allarme inizierà a suonare
-aspetta un secondo: l'allarme continua a suonare
-alza il piedino 4: l'allarme si spegne
-aspetta 15ms
-aspetta 15ms
-ripete l'operazione altre due volte
-alza il piedino 4
-mette a 1 il bit 1 della variabile errore: si tratta di una variabile della quale utilizo il bit 0 e il bit 1 come flag di controllo; in questo caso il bit 1 serve a capire se la waterstation è operativa o meno
-riabilito la gestione degli interrupt
-ritorna al punto in cui si è verificata la chiamata (andando a pescare questa informazione proprio nello stack).

Avrete notato che le operazioni "aspetta 1 s" e "aspetta 15ms" corrispondono ad altrettante chiamate a subroutine delle quali ci occuperemo nel prossimo post.

Continua...
__________________

Tu non sai niente, Jon Snow!

Ultima Modifica di FluidGuitar : 18-08-2006 22.06.19.
FluidGuitar Non in Linea   Rispondi Citando
Vecchio 27-01-2005, 14.45.59   #15
Registered User
 

Iscritto da: 18-02-2002
Locazione: Cagliari
Messaggi: 4,297
Feedback: (1)
fluid sei un grande.. appena finisco l'esame di assembler riprendo in mano il thread sperando di capirci qualcosina di +
__________________
i'm proud to be a yadayada lammah
Hunty Non in Linea   Rispondi Citando
Vecchio 27-01-2005, 22.44.20   #16
Super Moderator
 
L'avatar di  FluidGuitar
 

Iscritto da: 04-01-2001
Locazione: Torino
Messaggi: 4,023
Feedback: (0)
Grazie Hunty, ma soprattutto in bocca al lupo!

Intanto qui si va avanti col codice visto che è ancora lunghetto


Codice:
delay_15ms            movlw 182                 ; Aspetta 15 ms 
                      movwf d1
                      movlw 12
                      movwf d2
delay_15ms_loop       decfsz d1, f
                      goto $+2
                      decfsz d2, f
                      goto delay_15ms_loop
                      goto $+1
                      nop

                      return
Questa è la routine che realizza il ritardo di 15ms.
Il ritardo in un PIC si realizza ovviamente facendo fare al programma dei cicli a vuoto in numero sufficiente.
Dal momento che fra una istruzione e l'altra passano 4 cicli di clock e il clock è, nel caso in esame, a 4 MHz, le istruzioni vengono eseguite alla frequenza di 1MHz. Cioè fra una istruzione e l'altra passa un tempo di 1us.
Per fare 15ms dobbiamo eseguire 15000 istruzioni da 1 ciclo di clock.
Vediamo come:

delay_15ms (label per identificare l'inizio della routine)
movlw 182 (mette il valore numerico 182 nell'accumulatore)
movwf d1 (mette il valore dell'accumulatore nella variabile d1 definita a suo tempo al'inizio del programma)


movlw 12
movwf d2 (come sopra per la variabile d2)

delay_15ms_loop (label funzionale alla routine)
decfsz d1, f


Una nuova istruzione: "DECFSZ"
questa istruzione decrementa di uno il valore contenuto nel registro indicato (in questo caso d1) e mette il valore decrementato ancora in d1. Se il risultato del decremento è zero l'istruzione immediatamente successiva viene saltata (Skip if Zero)
N.B. Se il valore del decremento è zero diventa 1 il bit di zero dello status register (ricordate?) e se è uno il bit di zero l'istruzione decfsz eseguirà il salto.

goto $+2

Altra nuova istruzione: "GOTO"
è l'istruzione per il salto incondizionato. Ovviamente ha come argomento l'indirizzo di destinazione che può essere rappresentato da una label.
In questo caso l'argomento della goto è calcolato dal compilatore in quanto si fa uso del simbolo $ che è un meta-simbolo che indica la posizione corrente del Program Counter.
Cioè, durante la compilazione del programma la nostra istruzione goto occuperò un indirizzo ben preciso (che non conosco a priori e che può cambiare man mano che il programma viene scritto) e, con simbolo $ non faccio altro che identificare la locazione che contiene la mia goto.
A questo punto posso far puntare la goto in un punto qualsiasi rispetto a dove essa si trova , semplicemente aggiungendo dei valori al suo indirizzo.
Nel nostro caso la goto mi porterà più avanti di 2 istruzioni rispetto a dove si trova.
Rispetto alle altre istruzioni che richidono 1 ciclo di clock la goto ne richiede due mentre la decfsz ne richiede 1 se fa solo il decremento e 2 se oltre al decremento fa anche lo skip.

Studiando il flusso di queste poche righe di programma scopriremo che il ciclo non fa altro che decrementare d1 da 182 a zero eseguendo 5 istruzioni per fare questo. Dopodichè decrementa d2 e ricomincia a decrementare d1 che essendo zero ricomincerà da 255. Questo decremento da 255 a 0 avviene quindi per 12 volte.

Abbiamo quindi:

4 istruzioni di inizializzazione

182*5 istruzioni del primo decremento di d1 (totale 910)

5 istruzioni per decrementare d2 che vengono eseguite 12 volte (totale 60)

12*255*5 istruzioni per eseguire i 12 loop (totale 15300)

Più i due cicli di return (anche la return richiede due cicli di clock.

Raggiungiamo un totale di 16274 che è un po' di più di 15ms.

Non so perchè abbiano scelto questi valori perchè queste routine sono copia/incollate da non ricordo più quale sito, ma siccome funzionava non mi è sembrato che valesse la pena modificarla


Continua...

[EDIT]
Errata Corrige.
Ho rifatto meglio il calcolo visto che ieri sera ero un po' assonnato.
Le istruzioni da eseguire in loop sono 11*255*5
dal momento che d2 viene decrementata subito prima di iniziare i cicli da 255.
Quindi il totale è 14999..... decisamente meglio
__________________

Tu non sai niente, Jon Snow!

Ultima Modifica di FluidGuitar : 18-08-2006 22.08.02.
FluidGuitar Non in Linea   Rispondi Citando
Vecchio 28-01-2005, 00.02.42   #17
man of constant sorrow
 
L'avatar di  Reziel
 
Space Invaders Champion! Breakout Champion! Moon Lander Champion!
Iscritto da: 13-05-2004
Locazione: Roma
Messaggi: 12,066
Feedback: (0)
Inserzione Blog: 1
intanto lo segno e me lo leggo con calma =]
__________________


HELP Mi hanno rubato il notebook -
Dell XPS1730 grigio ¬ T7500 ¬ dual 8700M GT SLI - segni particolari SO Win XP PRO INGLESE, HD Fujitsu-Siemes 80GB SATA, non ha la Ageya Physx!!! né il BT
Reziel Non in Linea   Rispondi Citando
Vecchio 29-01-2005, 14.36.53   #18