Anteprima
Vedrai una selezione di 6 pagine su 22
Tesina sistemi elettronici, linguaggio Assembly - con codice Pag. 1 Tesina sistemi elettronici, linguaggio Assembly - con codice Pag. 2
Anteprima di 6 pagg. su 22.
Scarica il documento per vederlo tutto.
Tesina sistemi elettronici, linguaggio Assembly - con codice Pag. 6
Anteprima di 6 pagg. su 22.
Scarica il documento per vederlo tutto.
Tesina sistemi elettronici, linguaggio Assembly - con codice Pag. 11
Anteprima di 6 pagg. su 22.
Scarica il documento per vederlo tutto.
Tesina sistemi elettronici, linguaggio Assembly - con codice Pag. 16
Anteprima di 6 pagg. su 22.
Scarica il documento per vederlo tutto.
Tesina sistemi elettronici, linguaggio Assembly - con codice Pag. 21
1 su 22
D/illustrazione/soddisfatti o rimborsati
Disdici quando
vuoi
Acquista con carta
o PayPal
Scarica i documenti
tutte le volte che vuoi
Estratto del documento

INTCON

Concluso questo passaggio, si osserva che gli interrupt non verranno mai utilizzati in questo firmware,

perciò è nell’inizializzazione che devono essere disattivati.

clrf INTCON

Porte I/O

Le varie porte A, C, B, E vengono settate come input digitali per tutti i pin, tranne RA0 settato come

input analogico. Nella porta D i pin 0…3 sono settati come output (LED), mentre i pin 4…7 come input.

banksel TRISA

movlw 0xFF

movwf TRISA

movwf TRISC

movwf TRISB

movwf TRISE

movlw 0xF0

movwf TRISD

Anche qui, come già fatto in precedenza viene per prima cosa selezionato il banco di TRISA, lo stesso

degli altri registri utilizzati in seguito (per questo motivo è necessario un solo banksel). Muovendo la

literal FF (in binario ‘11111111’), si può soddisfare le richieste volute. Tuttavia copiando F0 in TRISD

faccio in modo che solo i primi 4 bit della porta vengano impostati come output, 4 bit che coincidono

con i 4 LED.

ANSELH Pag. 6 di 22

Di default, tutti i pin connessi all'ADC sono settati come input analogici, impedendone l'uso come I/O

digitali. L'impostazione seguente rende I/O digitali i pin RB0...RB3:

banksel ANSELH

clrf ANSELH

Selezionando come al solito banco di memoria e disattivando così AN8...AN13.

TIMER1

Nella seguente sezione vado ad impostare i valori del timer1 con i valori già descritti nel paragrafo

della definizione delle costanti. banksel T1CON

movlw B'00001010'

movwf T1CON

Quindi, prescaler impostato a 1 (bit 4-5 = 00), oscillatore del timer abilitato (bit 3 = 1) e input

sincronizzato col clock esterno (bit 2 = 0), clock esterno (bit1 = 1) e Timer1 non ancora attivato (bit0

= 0).

SERIALE banksel RCSTA

movlw B'10010000'

movwf RCSTA

Andando a copiare quel valore in RCSTA, modifico il Receive Status e il Control Register. Infatti

settando a 1 bit 7 e bit 4 faccio in modo che la connessione seriale sia abilitata (bit7, SPEN=1) così

come la ricezione (bit4, CREN). banksel SPBRG

movlw .12

movwf SPBRG

Queste tre righe di codice indicano la velocità di connessione della porta. Il registro SPBRG controlla

infatti il periodo di un timer indipendente.

banksel TXSTA

movlw B'00100100'

movwf TXSTA

viene settato il bit5 TXEN per la trasmissione, il bit4 SYNC è settato a 0 per connessione asincrona e

il bit 2 (non utilizzato in modo sincrono) è settato a 1 come high speed baud rate.

banksel BAUDCTL

clrf BAUDCTL

Infine, viene imposta una velocità di trasmissione/ricezione pari a 19.2 Kbit/s. Con queste righe viene

terminata l’inizializzazione dell’hardware.

Con la direttiva return si può ritornare a dove la call di INIT_HW è stata chiamata.

Pag. 7 di 22

Ritornati sul programma principale, con una semplice istruzione imposto lo stato dei LED all’accensione del

programma: banksel PORTD

clrf PORTD

ovvero tutti i LED (in particolare il primo led, l’unico che si va ad usare in questo firmware) sono inizializzati

come spenti.

Terminate le prime inizializzazioni, si entra nel primo polling, che va ad attendere il momento di pressione

del pulsante. Il loop di attesa della pressione del pulsante è il seguente:

wait_press

clrwdt

banksel PORTB

btfsc PORTB,0

goto wait_press

Si può notare infatti che fin quando il bit 0 della porta B è 1 (pulsante non premuto), il programma si racchiude

in un ciclo continuo, che potrà essere interrotto solo dal momento in cui viene rilevato il valore 0 sul bit 0

della portaB.

Per evitare il solito problema del bouncing, si va a richiamare subito il delay di 20ms, già descritto nella

dichiarazione delle costanti: pagesel DELAY

movlw tmr_20ms

call DELAY

con la pagesel viene impostata la pagina della memoria di programma in cui risiede la subroutine DELAY,

viene poi caricata la costante (precedentemente definita) per la misura di 20ms e chiamata quindi la routine

di DELAY.

DELAY

Anche in questo caso si lavora con un polling: settato il contatore al valore iniziale voluto, si azzera il

flag e si attende tramite un loop che il flag venga settato di nuovo.

banksel TMR0

movwf TMR0

bcf INTCON, T0IF

wait_delay

btfss INTCON, T0IF

goto wait_delay

return

copiato il registro accumulatore W in TMR0, ovvero i 20ms, si azzera il bit di overflow T0IF del timer0.

Dopodiché si entra nel loop, fin quando il flag di overflow del timer non risulta 1. Con il return c’è

l’uscita dalla subroutine al punto del codice in cui era stata chiamata.

Risolto il problema del debouncing alla pressione, bisogna risolvere lo stesso problema al rilascio del

pulsante. Anche in questo caso, il codice consiste in un loop di attesa del rilascio del pulsante.

wait_rel

clrwdt

banksel PORTB

btfss PORTB,0

goto wait_rel

pagesel DELAY

movlw tmr_20ms

Pag. 8 di 22

call DELAY

Il codice è molto simile al codice sulla pressione del pulsante, con la sola differenza che qui si attende che il

bit 0 di PORTB venga settato a 1 (pulsante rilasciato).

Il cronometro comincia a scorrere grazie alla subroutine START_STOPWATCH: si arriva qui dopo la pressione

del pulsante, perciò il timer1 può essere attivato:

banksel T1CON

movlw B'00001011'

movwf T1CON

Viene di fatto modificato un solo bit rispetto alla literal copiata nel registro T1CON nell’INIT_HW: il bit 0

(TMR1ON) viene settato a 1, dando il via al timer che, come impostato nella definizione delle costanti,

impiegherà 1s per arrivare a settare il flag a 1.

Passaggio successivo è quello di resettare tutte le singole cifre del cronometro:

pagesel reset_secondi_uni

call reset_secondi_uni

pagesel reset_secondi_dec

call reset_secondi_dec

pagesel reset_minuti_uni

call reset_minuti_uni

pagesel reset_minuti_dec

call reset_minuti_dec

Ogni due righe di codice viene chiamata la subroutine che va ad azzerare tutte 4 le cifre del cronometro; è

necessario solo muovere un registro accumulatore vuoto nelle variabili precedentemente dichiarate:

reset_secondi_uni clrw

movwf secondi_uni

return

reset_secondi_dec clrw

movwf secondi_dec

return

reset_minuti_uni clrw

movwf minuti_uni

return

reset_minuti_dec clrw

movwf minuti_dec

return

in questo modo infatti mi assicuro di far cominciare le quattro cifre tutte da 0.

Tuttavia, questi reset sarebbero inutili se poi non fossero mandati in stampa. Ed è ciò che viene fatto subito

dopo: pagesel transfer_data

call transfer_data

Con la call transfer_data il programma si occupa di inviare i dati

transfer_data

Viene eseguita la trasmissione dei dati nella seriale:

Pag. 9 di 22

movf minuti_dec, w

addlw .48

banksel TXREG

movwf TXREG

banksel PIR1

btfss PIR1, TXIF

goto $-1

Il primo carattere che voglio trasmettere è quello delle decine dei minuti, in modo da mandare in

stampa il cronometro come solitamente è fatto negli orologi da polso. Per prima cosa viene copiato

il registro accumulatore precedentemente definito in minuti_dec. Il valore .48 si spiega grazie alla

tabella dei valori ASCII: in questo modo infatti il codice partirà a trasmettere dal carattere 0, che si

trova proprio alla quarantottesima posizione nella tabella. Fatto ciò bisogna impostare la

trasmissione, selezionando il banco e andando muovere il registro accumulatore in TXREG, ed

aspettare poi che il flag TXIF del registro PIR1 assuma valore 1.

Queste righe di codice vengono quindi riproposte anche per gli altri valori, con la differenza del

nome del registro coinvolto.

Risulta più semplificata la trasmissione dei due punti che dividono minuti da secondi e del carriage

return, che permette di ritornare alla riga e colonna iniziale: per i primi, è sufficiente muovere il

carattere .58 del codice ASCII (carattere “:”) nel registro TXREG, per il secondo la literal da muovere

.13 (o anche /r).

Entro allora nel main_loop, la cui prima routine è la carica del contatore del timer1 con valore iniziale per

contare 1s. Sarà necessario ritornare in main_loop ogni qualvolta che è si è verificata una stampa, ovvero

almeno uno dei valori del cronometro è aumentato.

reload_timer1

Con questa subroutine viene ricaricato il timer1 in modo tale da poter ricominciare a contare il

secondo necessario a far assumere al flag il valore 1.

banksel T1CON

bcf T1CON, TMR1ON

Essendo in modalità asincrona, occorre arrestare il timer prima di aggiornare il registro del contatore.

Come al solito, si prende il bit 0 (TRM1ON) di T1CON e si fa un clear.

banksel TMR1L

movlw low tmr_1s

movwf TMR1L

movlw high tmr_1s

movwf TMR1H

La particolarità del timer1 rispetto gli altri timer è quella di avere 16 bit, a differenza di timer0 e

timer2 che sono forniti di “soli” 8 bit. Per questa ragione non è possibile muovere il valore del

contatore direttamente in un registro, ma è necessario dividerlo in due registri da 8 bit ognuno, high

e low. banksel PIR1

bcf PIR1, TMR1IF

banksel T1CON

bsf T1CON, TMR1ON

return

Al fine di poter ricominciare il conteggio in maniera corretta, è fondamentale azzerare il flag. Infine

viene riattivato il timer.

Come da richiesta, una volta reimpostato il timer, viene acceso il LED1:

banksel PORTD

Pag. 10 di 22

bsf PORTD, 0

Il main_loop1 introduce la situazione in cui il pulsante venga premuto durante lo svolgimento del

cronometro: è una sorta di evento esterno, che anche in questo caso viene gestito in polling:

banksel PORTB

btfss PORTB, 0

goto STOP_COUNTING

Nel caso il pulsante venga premuto, il codice salta direttamente all’istruzione STOP_COUNTING, la quale

porterà allo stop del timer e di conseguenza del cronometro.

STOP_COUNTING pagesel DELAY

movlw tmr_20ms

call DELAY

Anche questo caso, essendo premuto un pulsante, viene applicata un’operazione di debouncing.

banksel T1CON

movlw 0x01

xorwf T1CON, f

btfsc T1CON, 0

goto wait_rel2

Lo xor permette di leggere e analizzare in modo compatto (eliminando l’uso di due if) l’andamento

del timer: nel caso in cui sia attivo, lo xor tra la literal 01 e il bit 1 di T1CON fa sì che il timer venga

disattivato (e viceversa). Tuttavia, si noti che a seconda del nuovo comportamento assunto dal timer,

varia il settaggio del LED. Per questo motivo si suddivide in due ulteriori subroutine: nel caso in cui il

timer sia attivato (TMR1ON=1), entro nella subroutine wait_rel2:

❖ wait_rel2

grazie a questa subroutine il led si riaccende non quando scorre il numero sulla seriale ma

quando riparte il timer: banksel PORTB

btfss PORTB,0

goto wait_rel2

pagesel DELAY

movlw tmr_20ms

Dettagli
Publisher
A.A. 2016-2017
22 pagine
1 download
SSD Ingegneria industriale e dell'informazione ING-INF/01 Elettronica

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher brandontesla di informazioni apprese con la frequenza delle lezioni di Sistemi elettronici e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Università Politecnica delle Marche - Ancona o del prof Falaschetti Laura.