Anteprima
Vedrai una selezione di 5 pagine su 20
4 Esercitazioni Assembly Sistemi elettronici - No codice Pag. 1 4 Esercitazioni Assembly Sistemi elettronici - No codice Pag. 2
Anteprima di 5 pagg. su 20.
Scarica il documento per vederlo tutto.
4 Esercitazioni Assembly Sistemi elettronici - No codice Pag. 6
Anteprima di 5 pagg. su 20.
Scarica il documento per vederlo tutto.
4 Esercitazioni Assembly Sistemi elettronici - No codice Pag. 11
Anteprima di 5 pagg. su 20.
Scarica il documento per vederlo tutto.
4 Esercitazioni Assembly Sistemi elettronici - No codice Pag. 16
1 su 20
D/illustrazione/soddisfatti o rimborsati
Disdici quando
vuoi
Acquista con carta
o PayPal
Scarica i documenti
tutte le volte che vuoi
Estratto del documento

ON

generando una PWM costruita a mano con un timer e sfruttando l’overflow del timer, mi imposto

il timer in modo che vada in overflow ogni 500 ms, nel momento in cui entra nell’ISR accendo il

led, poi lo spengo e così via,avendo in totale un blinking di 1 s.

Prendiamo come sorgente di clock quella esterna a 32 kHz così ci svincoliamo dalla modalità

sincrona e possiamo lavorare anche in sleep.

Il modulo è 16 bit, l’overflow arriva dopo 65536 colpi di ticks. Calcolo poi il periodo massimo,

mettendo stavolta il prescaler a 1, poiché quello 8 non serve. Il periodo che mi interessa è 500 ms,

così al termine di ognuno posso settare il LEDon e il LEDoff.

Per ultima cosa voglio generare la PWM.

Qui l’ottica è un po’ diversa: mi viene chiesto di generare delle note. Di base l’onda sonora può

essere modellata come una sinusoide. Il parametro caratteristico è pitch, l’altezza della nota, che è

data dalla frequenza; ogni nota è caratterizzata dal proprio pitch, quindi dalla propria frequenza.

Se ho un’informazione su T e un’informazione su t io posso approssimare la sinusoide all’interno

ON

del mio circuito che è limitato come una forma d’onda quadra (una PWM appunto) e da qui

generare le varie note. T e t sono le uniche informazioni di cui ho bisogno per generare la mia

ON

nota.

Qui ho come informazione il periodo di Do, che vale 1912 us. A differenza dei timer precedenti,

non andiamo a caricare il valore massimo meno il numero di tick trovati, questo perché il TMR2

funziona in maniera diversa, si appoggia ad un modulo comparatore per cui il valore che vado a

trovare non lo vado a scrivere in TMR2 ma lo vado a scrivere in PR2, ovvero il valore comparatore,

una volta raggiunto il quale il timer si azzera. Il secondo modulo comparatore mi fa un confronto

tra il valore di TMR2 e il valore scritto nel registro CCPR1H (CCP interagisce con TMR1 e TMR2, per

il TMR2 che ha 8 bit non ho bisogno di parte alta e bassa, per il TMR1 che ha modulo 16 mi

servono parte alta e bassa per memorizzare la variabile). Nel momento in cui c’è il matching,

abbiamo individuato il t . I due comparatori ci servono perché uno determina il periodo della

ON

PWM e l’altro determina il duty cycle della stessa. Perciò la costante di tempo individuata prima

(119 tick) ci serve per individuare il periodo però non andrà scritta in TMR2, ma in PR2.

Se il t mi viene dato dal confronto tra TMR2 e CCPx e il duty cycle lo voglio al 50%, significa che

ON

dentro CCPx io ci vado a scrivere PR2/2.

Per memorizzare PR2/2 in binario, prendo il codice di PR2 e faccio lo shift a destra, causando una

n

divisione per 2. Regola: se shifto di n posizioni, ho una divisione di 2 .

Con tutto questo abbiamo generato la PWM. Come viene riprodotta? Nella scheda c’è un

piezoelettrico, un trasduttore, che mi permette di riprodurre quest’onda sonora: è un materiale

che produce una deformazione meccanica quando si applica una tensione ai suoi capi. Un modo

per migliorare il segnale sarebbe l’utilizzo della lookup table, ma qui usiamo solo un buzzer, il

piezoelettrico, non perfetto come qualità poiché non dedicato alla musica.

Ora andiamo sul codice in MPLAB:

La define associa una sequenza di caratteri a un nome, in modo tale che all’interno del codice, ogni

volta che in fase di compilazione il processore va a fare la scansione del codice sorgente, va a

sostituire a questa sequenza di caratteri il nome indicato dalla define. Posso dire per esempio

define time 10, o per esempio un valore, oppure define loop, un’istruzione più o meno lunga. In

questo caso nel codice è presente

#define SHOW_SLEEP: qui utilizzo la define senza operandi, non c’è la sequenza di caratteri qui;

quando li utilizzo in questo modo è utilizzabile con le direttive ifdef e ifndef: mi dichiarano l’inizio e

la fine di questa sorta di macro. Se avessi scritto ifndef, ovvero se non è definita quella label, allora

eseguimi queste righe di codice, altrimenti no. Quindi:

- Utilizzata con gli operandi, in fase di compilazione il preprocessore sostituisce alla label la

sequenza di caratteri che la accompagna.

- Quando non c’è una label invece viene utilizzata come label per abilitare o meno una

porzione di codice

Dal codice in MPLAB: #define <nome-macro> <sequenza-caratteri>. La direttiva #define è usata

per associare una sequenza di caratteri a un identificatore. Il preprocessore, nel fare la scansione

del codice sorgente, sostituisce a ogni occorrenza dell’identificatore la stringa di caratteri che vi è

stata associata con la direttiva #define. La definizione di un nome senza la sua relativa stringa è da

considerarsi utilizzabile con le direttive #ifdef e #ifndef.

Abbiamo poi la direttiva list e l’include, che noi includiamo sempre mentre il libro no.

Poi il configuration word: stavolta c’è LVP_OFF, mi abilita un pin per la scrittura su seriale e quindi

la programmazione tramite programmatore fisico. Nei PIC ci sono pin che hanno più funzioni:

questo è il caso di RB3, che ha ingresso analogico AN9, il PGM legato all’LVP. Siccome voglio

utilizzare RB3 per il pulsante, poiché la mia scheda è collegata al pulsante, quindi disattivo LVP, in

modo da poter utilizzare il pin RB3 come I/O generico. Negli esempi precedenti lavoravamo con

RB0, quindi questo LVP_OFF non l’avevamo visto.

Con la direttiva EQU andiamo ad associare le costanti delle label che poi andremo ad utilizzare nel

codice. Tutta questa parte riguarda i calcoli che abbiamo fatto prima:

- Il TMR0 era usato per il debouncing di 10ms, e prima avevamo trovato il numero di 39 tick

per avere quel tempo, allora vado a definire la costante che sarà quello che andrò a

scrivere su TMR0 per far partire il conteggio: (.256 - .39).

- Il TMR1 era usato per il blinking dei led, avevamo calcolato il numero dei tick per avere

8

500ms, ovvero 16384, e lo andiamo a sottrarre non a 256 ma a 2 =65536.

- Il TMR2 era usato per ottenere le frequenze delle note desiderate. Qui non si tratta di

sottrazioni, ma di trovare un valore che vado a scrivere su PR2 per far avvenire il matching

tra il timer che incrementa e il valore scritto in PR2.

Ora con UDATA_SHR mi riservo in RAM una porzione di codice da allocare in RAM e condivisa a

tutti i banchi; lo faccio per il salvataggio di contesto: se sto utilizzando portB e TMR0, mi aspetto

che ci siano delle routine di interrupt, quindi per gestirli ho bisogno di salvataggi e ripristino del

contesto, quindi un byte per salvare il registro accumulatore, uno per lo status, uno per pclath (per

l’interrupt); poi siccome sto lavorando con pressione e rilascio di bottoni, riserviamo un byte per

salvare il valore dello stato precedente della porta B (portBprev). Visto che è tutto gestito tramite

interrupt, mi riservo un byte per far dormire la CPU fin quando non viene chiamato un interrupt

(canSleep); infine una variabile temp per fare una serie di calcoli utili nel codice.

Infine, come al solito mettiamo il vettore di reset RST_VECTOR, prima di cominciare

definitivamente il codice. Poi viene fatto il goto per spostarmi nella pagina di programma per far in

modo che non si blocchi a 0x0004 (fatto con codice rilocabile).

❖ Con lo start comincia il programma. La prima cosa è andate ad inizializzare l’hardware, e lo

faccio chiamando con la call della subroutine INIT_HW

➢ In INIT_HW dobbiamo impostare timer e porte GPIO, perciò le prime impostazioni che

vado a fare sono queste, poi ci sarà anche la PWM.

Per il TMR0 abbiamo visto l’option register, T1CON e T2CON per il timer 1 e 2.

Nel TMR0 volevo un clock interno, un prescaler a 256: imposto l’option register (controlla

171/688) con tutti 0 e gli ultimi tre settati a 1. Il valore del PSA viene impostato a 0 perché

in questo modo assegno il prescaler non al watchdog timer ma al TMR0. Quanto vale il bit

T0SE non ci interessa perché utilizziamo la sorgente di clock interna, ci interessa quanto

che T0CS sia messo a 0 per impostare la sorgente di clock interna. Metto perciò il valore

voluto dentro w e quindi dentro OPTION_REG, così ho configurato il TMR0.

A questo punto vado sul registro INTCON (controlla 33/338), il registro di configurazione

degli interrupt. Non voglio che si verifichi un interrupt adesso, non ho finito a configurare le

mie periferiche, quindi faccio un clear di INTCON

Quindi faccio la configurazione dei GPIO (controlla 41/388): scelgo A, B, C, E come input

digitali per tutti i pin tranne RC2 come output per il buzzer, la portaD connessa ai led la

voglio con i pin 0…3 che siano settati come output, i pin 4…7 come input. La direzione I/O

mode è data dal registro TRISx, quindi per le porte A, B, E metto tutti input, ovvero tutti 1

in TRISx. Per il C, io voglio RC2 come output per il buzzer, il terzo bit lo metto a 0, tutti gli

altri li posso lasciare a 1. Per quanto riguarda TRISD, voglio 0…3 settati come output, 4…7

settati come input, quindi avrò 0xF0, che vado a scrivere dentro TRISD.

Di default ho che tutti i pin connessi all’ADC, che in questo caso sono RB0…RB3, che volevo

utilizzare come input, di default sono settati come input analogici, quindi mi impediscono

l’utilizzo come input digitali. Per poterli utilizzare come I/O digitali, vado a fare un clear di

tutto il registro che automaticamente mi disabilita l’utilizzo di tutti quei I/O come input

analogici, perché erano proprio quelli che volevo utilizzare per il bottone.

Su PORTB ho detto qual è la direzione, ho configurato TRISB per avere la direzione dei pin

sul banco PORTB (RB0…RB3 come input). In particolare voglio abilitare l’interrupt on

change su questi bit. Nel PIC16F84 si faceva subito, poiché avevo l’interrupt enable e

l’interrupt flag dedicato; in questi PIC16F887 il cambiamento di stato della portaB lo posso

avere su tutti i pin della portaB, in particolare in questo caso lo voglio limitare ai primi 4.

Qui ho il registro IOC che mi va a specificare su quale bit io voglio il mio portB on-change: io

lo volevo sui primi 4 più bassi quindi vado a scrivere 0x0F su IOCB.

Nel TMR1 imposto il registro di controllo che stavolta è T1CON (controlla 183/688) e andrò

a settare i bit: setto il quarzo esterno così posso lavorare in modalità asincrona, voglio il

prescaler a 1 e il timer attivo, ovvero B’00001111’.

Nel TMR2 imposto due registri di controllo, T2CON (controlla 197/688) e CCP1CON

(controlla 205/688) in modo tale da avere sorgente di clock interna, prescaler a 16, timer

inizialmente off perché lo andrò ad attivare quando avrò finito di configurare il modulo CCP

per la PWM. Su T2CON vado a scrivere B’00000011’ in modo

Dettagli
Publisher
A.A. 2016-2017
20 pagine
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.