SlideShare a Scribd company logo
1 of 35
Download to read offline
Funzioni per un
Elettrocardiografo Digitale
Progettazione di dispositivi biomedici programmabili
Docente Marco Knaflitz
Zito Antonella matr.188795 - Gruppo di lavoro 09
a.a. 2012/2013
1
Sommario
Introduzione ...................................................................................................................................................... 2
1 Configurazione del circuito elettrico .............................................................................................................. 2
2 Specifiche di progetto..................................................................................................................................... 5
3 Caratteristiche del segnale in ingresso........................................................................................................... 5
4 Software ......................................................................................................................................................... 5
4.1 Inizializzazioni e impostazione del convertitore...................................................................................... 7
4.2 Subroutine di risposta ad interrupt....................................................................................................... 10
4.3 Funzione per la verifica della tensione di batteria ................................................................................ 12
4.4 Controllo dell’indirizzo di memoria....................................................................................................... 17
4.5 Funzione per il campionamento di un segnale analogico ..................................................................... 19
4.6 Funzione per la lettura e la ricostruzione del segnale........................................................................... 22
5 Appendice..................................................................................................................................................... 27
Listato completo del software..................................................................................................................... 27
2
Introduzione
Il progetto descritto in queste pagine ha come obiettivo quello di realizzare un circuito in grado di
svolgere alcune funzioni di un elettrocardiografo digitale. L’elemento circuitale principale è il
microcontrollore Atmel ATMEGA 8 opportunamente programmato in linguaggio Assembly. Per la
realizzazione delle varie funzioni, il microcontrollore è stato interfacciato con altri componenti
elettronici meglio specificati in seguito. La descrizione di ogni funzione è supportata dal flow-chart
e dal codice implementativo corrispondenti.
1 Configurazione del circuito elettrico
I componenti rilevanti del circuito sono:
 Il microcontrollore a 8 bit Atmel ATMEGA 8
 Il convertitore Digitale-Analogico DAC0808
 L’amplificatore Operazionale TL081
Il microcontrollore è alimentato con una tensione costante (Vcc) di 5 V fornita attraverso il pin 7. Il
convertitore Analogico-Digitale interno al microcontrollore, che riceve in ingresso il segnale simil-
ECG e la tensione di batteria, è alimentato con una tensione costante di 5 V sul pin 20. Il
convertitore lavora con una tensione di riferimento interna misurata pari a 2,71 V. Il segnale simil-
ECG è portato in ingresso al convertitore tramite il pin 25, mentre la tensione di batteria arriva sul
pin 24 attraverso un partitore di tensione atto a dimezzare la tensione Vcc. L’alimentatore da
banco utilizzato è un Agilent E3631A.
I pin 15,16,17 settati come uscite comandano ciascuno l’accensione di un led.
A ciascuno dei pin 27 e 28, settati come ingressi, è collegato un interruttore per la selezione delle
modalità di funzionamento.
Il segnale convertito in digitale viene trasferito in parallelo al DAC0808 tramite i pin
2,3,4,5,6,11,12,13. Il DAC0808 è alimentato tra tensioni costanti di +5 V (sul pin 13) e -5 V (sul pin
3). La tensione di riferimento con cui lavora il DAC è la stessa utilizzata dal convertitore A/D e
viene direttamente prelevata dal pin 21 (AREF) del microcontrollore per essere condotta fino al
pin 14 del DAC.
Successivamente il segnale in uscita dal DAC0808 viene condotto all’amplificatore operazionale
TL081, il quale è alimentato tra tensioni costanti di +5 V (sul pin 7) e -5 V (sul pin 4). Al fine di
ridurre il rumore sul segnale in uscita dall’amplificatore sono stati utilizzati due condensatori (C8 e
C9) con capacità pari a 120 nF, collegati tra le rispettive tensioni d’alimentazione e la massa.
3
Figura 1. Configurazione del circuito elettrico
4
Figura 2. Foto del circuito
5
2 Specifiche di progetto
Le specifiche di progetto prevedono che il circuito sia in grado di svolgere le seguenti funzioni:
1. Verifica della tensione di batteria e generazione di un allarme visivo in presenza di tensione
troppo bassa.
2. Campionamento di un segnale analogico con frequenza pari a 500 Hz e memorizzazione dei
campioni in SRAM.
3. Lettura dei campioni di segnale ECG in SRAM e trasferimento ad un convertitore D/A parallelo
per ricostruire il segnale.
4. Variazione della velocità con la quale i campioni memorizzati sono portati al DAC.
3 Caratteristiche del segnale in ingresso
Il segnale in ingresso è un segnale simil-ECG ottenuto mediante un generatore di funzioni Agilent
33220A. La frequenza del segnale è stata impostata ad 1 Hz, mentre l’ampiezza picco-picco ad 1 V.
E’ stato introdotto un offset di 0.3 V in modo tale da evitare di inviare tensioni negative al
microcontrollore. Al fine di visualizzare correttamente la forma d’onda del segnale
sull’oscilloscopio è stata impostata la modalità con alta impedenza in uscita dal generatore di
funzioni.
4 Software
In questo capitolo verranno descritte singolarmente le varie parti che compongono il programma
caricato sul microcontrollore. Il listato del codice nella sua interezza è riportato in appendice.
L’implementazione è stata effettuata utilizzando il software AVR Studio 4 mentre la
programmazione del microcontrollore è avvenuta tramite l’utilizzo della scheda AVR Dragon.
Nella scrittura del programma, la prima operazione necessaria è quella di includere il file
“atmega8.inc” che consente di utilizzare delle stringhe piuttosto che esplicitare i corrispondenti
indirizzi di memoria specifici del microcontrollore. Questo si effettua tramite le direttive:
.NOLIST ; La direttiva .NOLIST fa si che ciò che segue non venga
;incluso nel listato.
.INCLUDE "atmega8.inc" ; La direttiva .INCLUDE inserisce il file "atmega8.inc"
.LIST ; La direttiva .LIST svolge l’operazione duale a quella
;svolta da .NOLIST.
6
Le successive operazioni che precedono il ciclo principale del software prevedono la definizione
dei registri utilizzati, l’assegnazione di stringhe ai valori numerici utilizzati e l’allocazione della
memoria SRAM necessaria alla memorizzazione di una variabile a 16 bit e dei campioni di segnale.
In particolare, si è scelto di allocare uno spazio pari a 500 bytes che ad una frequenza di
campionamento di 500 Hz consente la memorizzazione di un secondo di segnale. La porzione di
codice che svolge questo compito è la seguente:
.DEF mp = R16 ; registro di lavoro (generico)
.DEF mp1 = R17 ; registro di lavoro secondario (generico)
.DEF mp2 = R24 ; primo registro per il decremento della variabile a 16 bit
.DEF mp3 = R25 ; secondo registro per il decremento della variabile a 16 bit
.DEF count_500 = R18 ; primo registro per la temporizzazione a 500 Hz
.DEF count_1000 = R19 ; secondo registro per la temporizzazione a 1000 Hz
.EQU tsh_bat = 227 ; fissa la soglia di tensione a 2,4V nominali
.EQU alta30 = 0x75 ;valore alto di 30000 per temporizzare il check batteria
.EQU bassa30 = 0x30 ; valore basso di 30000
; Allocazione della memoria SRAM
.DSEG
ind_tempo_batt: .BYTE 2
; riserva 2 bytes in cui salvo la variabile a 16 bit
; (30000) per il controllo della tensione di batteria
.org 0x93
; dopo le 96 celle dedicate ai registri, per mantenere 50 celle libere
; della SRAM, scrive i campioni a partire dalla 147esima cella
indirizzo: .BYTE 500
; riserva 500 bytes per scrivere i campioni del segnale ECG
.CSEG
Nella seguente porzione di codice si specifica la gestione degli interrupt.
rjmp RESET ; Reset Handler
reti ;rjmp EXT_INT0 ; IRQ0 Handler
reti ;rjmp EXT_INT1 ; IRQ1 Handler
reti ;rjmp TIM2_COMP ; Timer2 Compare Handler
reti ;rjmp TIM2_OVF ; Timer2 Overflow Handler
reti ;rjmp TIM1_CAPT ; Timer1 Capture Handler
reti ;rjmp TIM1_CAPT ; Timer1 Capture Handler
reti ;rjmp TIM1_COMPA ; Timer1 CompareA Handler
reti ;rjmp TIM1_COMPB ; Timer1 CompareB Handler
reti ;rjmp TIM1_OVF ; Timer1 Overflow Handler
rjmp TIM0_OVF ; Timer0 Overflow Handler
reti ;rjmp SPI_STC ; SPI Transfer Complete Handler
reti ;rjmp USART_RXC ; USART RX Complete Handler
reti ;rjmp USART_UDRE ; UDR Empty Handler
reti ;rjmp USART_TXC ; USART TX Complete Handler
reti ;rjmp ADC_conv ; ADC Conversion Complete Handler
reti ;rjmp EE_RDY ; EEPROM Ready Handler
reti ;rjmp ANA_COMP ; Analog Comparator Handler
reti ;rjmp TWSI ; Two-wire Serial Interface Handler
reti ;rjmp SPM_RDY ; Store Program Memory Ready Handler
7
La parte successiva del codice consiste nella routine principale del programma il cui
funzionamento è schematizzato nel seguente flow-chart generale.
Figura 3. Flow-chart generale della routine principale del software
4.1 Inizializzazioni e impostazione del convertitore
All’interno della routine principale del programma, la prima operazione da compiere è
l’inizializzazione dello Stack Pointer. Ciò è d’obbligo in quanto si utilizzerà una subroutine di
risposta ad interrupt. Per l’inizializzazione si ricorre ai registri SPH ed SPL in cui vengono scritte
rispettivamente le parti alta e bassa dell’ultimo indirizzo della SRAM.
Per svolgere le funzioni richieste vengono utilizzate le porte B,C e D del microcontrollore. Per
scegliere la direzione dei dati sui pin delle varie porte si utilizzano i registri DDR (Data Direction
Register), mentre per impostare il valore iniziale presente sulla porta si fa utilizzo dei registri PORT.
La scelta progettuale prevede l’utilizzo di un solo Timer Counter a 8 bit, nello specifico il Timer
Counter 0. Per la sua gestione vengono utilizzati i registri TCCR0, TCNT0 e TIMSK che permettono
di impostare rispettivamente il passo di prescaler, il valore iniziale del timer e la generazione del
segnale di interrupt in corrispondenza di un overflow. Il valore iniziale assegnato a TCNT0 è pari a
255, in tal modo l’overflow del contatore si verifica circa ogni millisecondo poiché il passo di
prescaler prescelto è di 1024 e la frequenza del clock del sistema risulta pari a 1MHz.
Stabilito che il controllo della tensione di batteria venga effettuato ogni 30 secondi, per ottenere
l’intervallo di tempo corrispondente, si è scelto il valore 30000 essendo questo decrementato ogni
millisecondo. Tale valore a 16 bit viene memorizzato nella SRAM all’indirizzo precedentemente
assegnato (ind_tempo_batt).
RESET
INIZIALIZZAZIONI
CHECK BATTERIA
CONTROLLO
INDIRIZZO
SCRITTURA
LETTURA
FINE
8
Per stabilire l’intervallo di campionamento e quello di trasferimento dei campioni al convertitore
D/A, vengono inizializzate le variabili count_500 e count_1000.
Inoltre, l’ultima operazione di questa sezione di codice prevede l’inizializzazione della SRAM. Nelle
celle riservate alla memorizzazione dei campioni viene scritto il valore zero per avere certezza di
ciò che viene letto nel caso di avvio del programma nella modalità di lettura, quando cioè nella
SRAM non sono stati ancora memorizzati i campioni di segnale.
Quanto detto è riportato in dettaglio nel listato seguente:
RESET:
ldi mp,high(RAMEND) ;(0x04)
out SPH,mp
ldi mp,low(RAMEND) ;(0x5f)
out SPL,mp
; inizializzazione dello stack pointer all'ultimo indirizzo della SRAM
ldi mp,0b00000000
out DDRC,mp
; setta i pin della PORTA C tutti in ingresso
ldi mp,0x00
out PORTC,mp
; scrive zero nel registro della PORTA C
ldi mp,0b00001110
out DDRB,mp
; imposta in uscita i pin 15, 16 e 17 della PORTA B
; per i led di controllo scrittura, batteria, lettura
ldi mp,0x00
out PORTB,mp
; scrive zero nel registro della PORTA B
ldi mp,0b11111111
out DDRD,mp
; setta tutti i pin della PORTA D come uscite
ldi mp,0x00
out PORTD,mp
; scrive zero nel registro della PORTA D
ldi mp,0b00000101
out TCCR0,mp
; carica in TCCR0 i bit di mp, solo i primi 3 bit sono configurabili R/W,
; gli altri restano a 0. Il registro TCCR0 è usato per gestire la frequenza
; con cui generare un interrupt. Seleziona prescaler passo 1024
ldi mp,255
out TCNT0,mp
; imposta il valore iniziale del contatore a 255
ldi mp,0x01
out TIMSK,mp
; imposta il bit 0 del registro TIMSK ad 1 per abilitare la gestione degli
;interrupt in caso di overflow di TCNT0
9
ldi YL,low(indirizzo)
ldi YH,high(indirizzo)
; scrive in Y l'indirizzo da incrementare per scrivere i campioni di segnale
;nella SRAM
ldi XL,low(ind_tempo_batt)
ldi XH,high(ind_tempo_batt)
; scrive in X l'indirizzo dove andare a salvare il valore 30000 da decrementare
ldi mp,bassa30
ldi mp1,alta30
st X+,mp1
st X,mp
; scrive in SRAM il valore 30000 all'indirizzo contenuto in X
ldi count_500,2
ldi count_1000,1
; inizializza i contatori per temporizzare scrittura e lettura dei campioni
inizializzaRAM:
ldi mp,0
st Y+,mp
ldi mp,low(0x288)
cp YL,mp
brne inizializzaRAM
ldi mp,high(0x288)
cp YH,mp
brne inizializzaRAM
ldi YL,low(indirizzo)
ldi YH,high(indirizzo)
; scrive zero nelle 500 celle di memoria riservate a memorizzare
; i campioni del segnale in modo da essere certi del valore letto inizialmente
; all'avvio del programma
Prima di passare all’implementazione delle funzioni vere e proprie, si procede con la
configurazione del convertitore Analogico-Digitale interno al microcontrollore. Questo si fa
andando a modificare il registro ADCSRA. Il codice seguente svolge quanto detto.
ldi mp,0b10000010
out ADCSRA,mp
; imposta il fattore di prescaling pari a 4.
; ADCSRA è un registro a 8 bit in particolare:
; se il bit7=1 --> abilita ADC
; se il bit6=1 --> start conversione
; se il bit5=1 (ADFR) --> seleziona il Free Running mode
; se il bit4=1(ADIF) --> a fine conversione genero un interrupt portando ad 1 il
;bit 3
; i bit 2:0 selezionano il fattore di prescaling
Infine con l’istruzione sei viene abilitata la sensibilità della CPU agli interrupt, in modo tale che il
programma venga interrotto in corrispondenza di un overflow del Timer Counter 0 per
l’esecuzione della subroutine di risposta ad interrupt.
10
4.2 Subroutine di risposta ad interrupt
Il decrementi dei contatori che serve per temporizzare le operazioni di verifica della tensione di
batteria, di campionamento e scrittura o lettura, vengono svolte all’interno di una subroutine di
risposta ad interrupt denominata TIM0_OVF.
Figura 4. Flow-chart subroutine di risposta ad interrupt
Preliminarmente si usa l’istruzione di push dei registri utilizzati nella routine principale del
programma per garantire che il loro contenuto non venga modificato durante l’esecuzione di
TIM0_OVF. Inoltre si opera il push del registro di stato, SREG, in modo tale che terminata la
subroutine venga ripristinato lo stato precedente all’interrupt. L’istruzione di push consiste nel
salvare il contenuto dei registri sulla cima dello stack per poi recuperarlo tramite l’istruzione di
pop. Le altre operazioni compiute prevedono la reinizializzazione del registro TCNT0 al valore 255,
il decremento delle variabili a 8 bit, count_500 e count_1000, e il decremento del valore a 16
bit corrispondente al tempo rimanente al prossimo controllo della tensione di batteria.
11
Il codice che realizza quanto detto è il seguente.
TIM0_OVF:
push mp
push mp1
push mp2
push mp3
in mp,SREG
push mp
; push dei registri utilizzati, per garantire che non vengano modificati dalla
;subroutine di risposta ad interrupt
ldi mp,255
out TCNT0,mp
; reinizializza il contatore del timer counter
dec count_500
; decremento del contatore count_500
dec count_1000
; decremento del contatore count_1000
ldi XL,low(ind_tempo_batt)
ldi XH,high(ind_tempo_batt)
ld mp3,X+
ld mp2,X
sbiw mp3:mp2,1
; decremento della variabile a 16 bit per la temporizzazione del controllo di
;tensione di batteria
ldi XL,low(ind_tempo_batt)
ldi XH,high(ind_tempo_batt)
st X+,mp3
st X,mp2
; scrittura nella SRAM del valore a 16 bit decrementato
pop mp
out SREG,mp
pop mp3
pop mp2
pop mp1
pop mp
; ripristino dei registri utilizzati
reti
; ritorna all'esecuzione del programma principale
In particolare si nota come il decremento del valore a 16 bit venga effettuato tramite l’istruzione
sbiw che consente di decrementare in modo diretto parole di 2 bytes. Il valore in questione viene
caricato dalla SRAM tramite l’istruzione ld e successivamente, dopo essere stato decrementato,
viene memorizzato nella SRAM mediante l’istruzione st. L’istruzione finale reti permette di
ritornare all’esecuzione della routine principale del programma dal punto in cui era stata
interrotta.
12
4.3 Funzione per la verifica della tensione di batteria
La funzione di verifica della tensione di batteria ha lo scopo di valutare ogni 30 s la tensione
erogata dalla batteria. Nel caso di tensione al di sotto della soglia stabilita di 2.4 V nominali, il
sistema provvede alla generazione di un allarme visivo che consiste nell’accensione di un led giallo
che resta acceso fino a quando la tensione non viene ripristinata ad un valore accettabile e il
sistema riavviato. La scansione del tempo avviene tramite il decremento della variabile contenuta
all’indirizzo ind_tempo_batt della SRAM, di valore 30000. Questo decremento, come detto
precedentemente, viene effettuato ogni millisecondo, per cui per portare il valore 30000 a zero si
impiegheranno circa 30 s.
Il primo passo da compiere è proprio quello di verificare il valore di tempo corrente. Ciò viene
fatto semplicemente leggendo il valore della variabile scritto nella SRAM e confrontandolo con
zero.
Il valore 30000 viene codificato con una variabile a 16 bit, pertanto viene confrontata con zero
prima la parte bassa, bassa30,e poi la parte alta, alta30. Se la parte bassa è diversa da zero,
vuol dire che certamente non sono trascorsi 30 s, quindi si termina la funzione di verifica della
tensione di batteria e si prosegue con la parte successiva atta al controllo dell’indirizzo
(controllo_indirizzo), altrimenti è necessario verificare che anche la parte alta sia uguale a
zero. Se la parte alta non è uguale a zero vuol dire nuovamente che non sono trascorsi 30 s e si
passa a controllo_indirizzo, altrimenti si procede con le altre operazioni di verifica della
tensione di batteria. Allo scadere dei 30 s è necessario innanzitutto reinizializzare la variabile a 16
bit al valore 30000 in modo da poter contare nuovamente 30 s. Successivamente viene letta la
tensione di batteria, per fare ciò bisogna effettuare una conversione Analogico-Digitale. A questo
scopo viene impostato il pin di ingresso del convertitore interno al microcontrollore tramite il
registro ADMUX. Per dare inizio alla conversione si utilizza il registro ADCSRA.
Si effettua anche una verifica del termine della conversione, check_conv_batteria, tramite un
loop interno che introduce un ritardo che però, essendo di circa 10 µs, può essere tollerato
considerato che l’intervallo di campionamento è pari a 1 ms.
Il valore analogico, una volta convertito, viene scritto nel registro ADCH e può essere utilizzato per
il confronto con il valore di soglia. La tensione di riferimento interna del convertitore, in seguito ad
una misurazione compiuta, si è rivelata essere differente da quella dichiarata dal costruttore (2.56
V) e pari a 2.71 V. Di conseguenza il valore di soglia tsh_batt corrispondente a 2.4 V nominali, è
stato calcolato con una proporzione ed è risultato pari a 227. Se il valore letto nel registro ADCH è
minore della soglia tsh_batt, viene acceso un led giallo sul pin 16, altrimenti si passa a
controllo_indirizzo.
In figura 6 si vede come in corrispondenza di una tensione pari a 2.39 V misurata in ingresso al pin
24 (ADC1) il led giallo si accenda dopo 30 secondi dall’avvio del dispositivo. Per poter effettuare
tale verifica il dispositivo è stato avviato con una tensione di alimentazione pari a 4.8 V.
13
Figura 5. Flow-chart Verifica tensione di batteria.
14
Figura 6. Verifica tensione di batteria
15
Quanto visto precedentemente nel flow-chart, si traduce in linguaggio Assembly come riportato
nel listato seguente.
check_batteria:
ldi XL,low(ind_tempo_batt)
ldi XH,high(ind_tempo_batt)
; carica in X l'indirizzo in cui è salvato il valore 30000 che viene
;decrementato
ld mp1,X+
ld mp,X
; legge dalla SRAM il valore a 16 bit (30000) e lo carica nei registri mp1
;(parte alta) e mp (parte bassa)
cpi mp,0
brne controllo_indirizzo
; se la parte bassa è zero controlla la parte alta del valore altrimenti
; salta al controllo indirizzo
cpi mp1,0
brne controllo_indirizzo
; se anche la parte alta è zero reinizializza il valore a 30000 altrimenti
; salta al controllo indirizzo
ldi XL,low(ind_tempo_batt)
ldi XH,high(ind_tempo_batt)
ldi mp,bassa30
ldi mp1,alta30
st X+,mp1
st X,mp
; riscrive in SRAM il valore iniziale (30000) della variabile da decrementare
; per il controllo della batteria
ldi mp,0b11100001
out ADMUX,mp
; programma l'ADC in modo che lavori con tensione di riferimento interna a 2,56V
; (in realtà è 2,71V), giustifica a sinistra il risultato nel registro ADCH e
; seleziona ADC1 (pin 24) come ingresso del convertitore
in mp,ADCSRA
ldi mp1,0b01000000
or mp,mp1
out ADCSRA,mp
; inizia la conversione del valore di tensione di batteria
check_conv_batteria:
in mp,ADCSRA
ldi mp1,0b01000000
and mp,mp1
brne check_conv_batteria
; aspetta che la conversione sia pronta testando ADSC in ADCSRA
; a conversione terminata ADSC torna a 0
in mp,ADCH
; legge ADCH che contiene il valore di tensione convertito su 8 bit
16
cpi mp,tsh_bat
brsh controllo_indirizzo
; se il valore letto di tensione è maggiore o uguale alla soglia va avanti
;altrimenti accende il led
in mp1,PORTB ;legge quello che ho precedentemente scritto sulla porta B
ldi mp,0b00000100
or mp,mp1
;cambia solo il valore sul pin 16 mantenendo invariati gli altri
out PORTB,mp ;accende il led sul pin 16
In particolare si nota come per attivare la conversione viene portato a 1 il bit 6 del registro
ADCSRA chiamato ADSC, bit che tornerà a zero a conversione terminata. Per fare ciò è stata
eseguita un’operazione di or in modo da andare a modificare soltanto il bit di interesse. Al fine di
verificare che la conversione sia terminata è stato effettuato un and in modo da accertarsi che il
bit 6 sia effettivamente tornato a zero.
17
4.4 Controllo dell’indirizzo di memoria
Per un funzionamento di tipo “buffer circolare” dello spazio riservato ai campioni nella memoria
SRAM, è necessario che quando si è letto o scritto nell’ultima cella riservata si ricominci dalla
prima rileggendo o sovrascrivendo i campioni già presenti.
Figura 7. Flow-chart per il controllo dell'indirizzo corrente.
Gli indirizzi della SRAM sono parole di 2 bytes, pertanto per effettuare il confronto si procede
preliminarmente verificando che la parte bassa di Y sia uguale alla parte bassa di 0x288, indirizzo
corrispondente alla cella successiva all’ultima riservata per contenere i campioni. Se i due valori
non sono uguali evidentemente l’indirizzo corrente non è pari a 0x288 pertanto si passa alla
porzione di codice successiva a partire dal label scrittura. Se invece questi valori sono uguali, si
deve confrontare la parte alta dell’indirizzo corrente con quella alta di 0x288. Se le parti alte non
sono equivalenti si passa a scrittura, altrimenti si assegna all’indirizzo corrente il valore
dell’indirizzo della prima cella riservata (0x93) con la stessa procedura che tiene conto della parte
alta e di quella bassa.
Il codice relativo a quanto esplicitato dal precedente flow-chart, viene riportato di seguito.
controllo_indirizzo:
ldi mp,low(0x288)
cp YL,mp
brne scrittura
; se la parte bassa dell'indirizzo corrente è uguale alla parte bassa
;dell'indirizzo della prima cella dopo l'ultima riservata
;controlla anche la parte alta, altrimenti salta a scrittura
18
ldi mp,high(0x288)
cp YH,mp
brne scrittura
; se anche la parte alta dell'indirizzo corrente è uguale alla parte alta
;dell'indirizzo della prima cella dopo l'ultima riservata
;reinizializza l'indirizzo e prosegui con la scrittura, altrimenti salta a
;scrittura senza reinizializzare l'indirizzo
ldi YH,high(indirizzo)
ldi YL,low(indirizzo)
;reinizializza l'indirizzo della prima cella della SRAM per la scrittura/lettura
19
4.5 Funzione per il campionamento di un segnale analogico
Le operazioni di scrittura e lettura sono tra loro esclusive e identificate dall’accensione di led verdi
corrispondenti. La selezione di una delle due funzioni avviene mediante un interruttore sul pin 28
del microcontrollore. Il campionamento del segnale in ingresso e la scrittura dei campioni in
memoria vengono effettuati alla frequenza di 500 Hz. Per ottenere tale frequenza si fa ricorso alla
variabile count_500, che viene inizializzata al valore 2. Tale valore viene decrementato di 1 ogni
millisecondo, in modo tale che quando count_500 vale zero sia consentito campionare. Il
decremento sfrutta la subroutine di risposta ad interrupt TIM0_OVF.
Figura 8. Flow-chart funzione campionamento e scrittura
20
Per poter effettuare il campionamento del segnale simil-ECG in ingresso sul pin 25, l’interruttore
T1 deve far si che il valore logico in ingresso sul pin 28 sia basso, cioè zero. Altrimenti si passa
all’operazione di lettura. Per avere certezza del valore in uscita sulla PORTA D durante la scrittura,
si scrive zero nel registro PORTD. Nel caso in cui il dispostivo sia stato precedentemente in
modalità di lettura, ci si assicura che il led (pin 17) indentificativo di tale modalità sia spento. Viene
allora acceso il led sul pin 15 che identifica lo stato di scrittura. Dopodiché portando a 1 il bit ADC2
del registro ADMUX viene settato il pin 25 come ingresso del convertitore A/D.
Per verificare se è veramente giunto il momento di campionare si controlla il valore di
count_500, se questa variabile non è uguale a zero vuol dire che non sono passati 2 ms e si passa
avanti al label lettura. Altrimenti si passa innanzitutto alla reinizializzazione di count_500 in
modo da poter attendere che siano trascorsi 2 ms per campionare e scrivere nuovamente.
Successivamente si avvia la conversione e dopo aver atteso che questa sia terminata, come nel
caso precedentemente visto del check_conv_batteria, si legge dal registro ADCH il valore
convertito e lo si scrive nella SRAM in corrispondenza dell’indirizzo contenuto nel registro Y.
Dopodiché l’indirizzo della cella in cui è stato appena scritto il campione corrente viene
incrementato.
La parte di codice relativa a questa funzione è riportata di seguito.
scrittura:
in mp,PINC
ldi mp1,0b00100000
and mp,mp1
cpi mp,0
brne lettura
; controlla il valore dell'interruttore di scrittura/lettura. Se il valore sul
;pin 28 è uguale a zero procedi con la scrittura altrimenti passa alla lettura
ldi mp,0x00
out PORTD,mp
; dato che si sta effettuando la scrittura dei campioni, sulla PORTA D manda
;zero per avere contezza del valore sulla porta
in mp,PORTB
ldi mp1,0b11110111
and mp,mp1
ldi mp1,0b00000010
or mp,mp1
out PORTB,mp
; spegne il led di lettura sul pin 17 e accende il led di scrittura sul pin 15
ldi mp,0b11100010
out ADMUX,mp
; imposta ADC2 (pin 25) come ingresso al convertitore
cpi count_500,0
brne lettura
; verifica del contatore che permette una frequenza di campionamento di 500 Hz,
; se il contatore è uguale a zero è giunto l'istante di campionare
ldi count_500,2
; reinizializza il contatore a 2
21
in mp,ADCSRA
ldi mp1,0b01000000
or mp,mp1
out ADCSRA,mp
; inizia la conversione dei campioni del segnale
check_conv_scrittura:
in mp,ADCSRA
ldi mp1,0b01000000
and mp,mp1
brne check_conv_scrittura
; aspetta che la conversione sia pronta testando ADSC in ADCSRA: a conversione
;terminata ADSC torna a 0
in mp1,ADCH
; legge ADCH che contiene il campione convertito su 8 bit
st Y+,mp1
; scrive il campione in SRAM all'indirizzo contenuto in Y e incrementa
;l'indirizzo contenuto in Y
Il funzionamento in modalità di scrittura è rappresentato in figura 9, in cui è possibile vedere che il
led verde corrispondente alla scrittura è acceso e qual è la posizione dell’interruttore T1 in questa
modalità. Sullo schermo dell’oscilloscopio è rappresentato in alto il segnale proveniente dal
generatore inviato sul canale 1, mentre in basso è visualizzato il canale 2 a cui è collegata l’uscita
dell’amplificatore. Essendo in modalità di scrittura l’uscita è correttamente pari a zero.
Figura 9. Funzionamento in modalità di scrittura
Interruttore T1
22
4.6 Funzione per la lettura e la ricostruzione del segnale
La lettura dei campioni di segnale memorizzati nella SRAM viene attivata con l’interruttore T1.
Questa modalità è identificata dall’accensione di un led di colore verde corrispondente. I campioni
possono essere letti alla stessa frequenza con cui vengono scritti, 500 Hz, oppure a frequenza
doppia, 1000 Hz. La scelta della frequenza è operata dall’interruttore T2 sul pin 29. Per poter
ricostruire la forma d’onda del segnale i campioni letti vengono trasferiti in parallelo sulla PORTA D
del microcontrollore, settata come uscita. Questa è connessa ai pin di ingresso del convertitore
Digitale-Analogico, DAC 0808. Questo convertitore viene alimentato, come detto in precedenza,
con una tensione di alimentazione compresa tra +5 e -5 V. La tensione di riferimento che il DAC
utilizza per effettuare la conversione è la medesima che usa il convertitore Analogico-Digitale. La
configurazione circuitale standard del DAC 0808 prevede anche l’utilizzo di un amplificatore
operazionale, in questo progetto un TL081. Per visualizzare la forma d’onda del segnale ricostruito
è stato utilizzato un oscilloscopio digitale Agilent DSO3102A, prelevando il segnale fornito in uscita
dall’amplificatore. Il procedimento per fare tutto ciò è esplicitato dal flow-chart riportato in figura
7.
Come già detto si verifica immediatamente lo stato dell’interruttore sul pin 28. Se questo fa si che
il pin sia a valore logico basso, vuol dire che si è in modalità di scrittura pertanto si passa al label
fine e si può proseguire tornando alla funzione di verifica della tensione di batteria. Se invece il
valore logico sul pin 28 è alto, si procede con le operazioni di preparazione alla lettura.
Innanzitutto è necessario accendere il led sul pin 17 per identificare lo stato di lettura in corso,
dopo essersi assicurati che il led identificativo della scrittura (pin 15) sia spento. Queste operazioni
sono duali rispetto a quelle viste nel caso della funzione di scrittura.
La scelta della frequenza con cui ogni campione viene letto ed inviato al DAC è affidata ad un
interruttore T2 collegato sul pin 29. Se il valore logico sul pin è basso, la frequenza di lettura
impostata sarà 500 Hz, altrimenti si verificherà nuovamente lo stato dell’interruttore e se questo
sarà al valore logico alto la frequenza di lettura sarà di 1000 Hz. Nel primo caso, label freq_500, si
dovrà per prima cosa verificare che effettivamente sia giunto il momento di leggere, cioè che
count_500, sia uguale a zero ed eventualmente reimpostarne il valore a 2. Successivamente si
legge il campione nella cella della SRAM il cui indirizzo è contenuto nel registro Y, e gli 8 bit
corrispondenti vengono inviati sugli 8 pin della PORTA D. Dopodiché l’indirizzo corrente della cella
appena letta, viene incrementato. Nel caso in cui il valore logico sul pin 29 sia alto, in
corrispondenza di freq_1000, la variabile che viene considerata è count_1000, se questa è
uguale a zero viene reinizializzata al valore 1. Anche in questo caso dopo la reinizializzazione si
scrive sulla PORTA D il valore del campione letto e si incrementa l’indirizzo corrente. Al termine
della lettura si giunge al label fine da cui si torna alla verifica della tensione di batteria.
23
Figura 10. Flow-chart funzione di lettura
24
Il codice che realizza quanto descritto dal flow-chart è il seguente.
lettura:
in mp,PINC
ldi mp1,0b00100000
and mp,mp1
cpi mp,0
breq fine
; controlla il valore dell'interruttore di scrittura/lettura. Se il valore sul
;pin 28 è uguale a zero passa a fine altrimenti procedi
in mp,PORTB
ldi mp1,0b11111101
and mp,mp1
ldi mp1,0b00001000
or mp,mp1
out PORTB,mp
; spegne il led di scrittura sul pin 15 e accende il led di lettura sul pin 17
in mp,PINC
ldi mp1,0b00010000
and mp,mp1
cpi mp,0
brne freq_1000
; controlla il valore dell'interruttore delle frequenze. Se il valore sul pin 27
;è 0 legge a 500 Hz altrimenti a 1000 Hz
freq_500:
cpi count_500,0
brne freq_1000
; controlla il contatore che permette di leggere a 500 Hz. Se è uguale a zero
;vuol dire che la routine di risposta all'interrupt ha azzerato il valore
;iniziale di count_500, quindi può leggere il campione, altrimenti salta a
;freq_1000
ldi count_500,2
; reinizializza il contatore a 2
ld mp,Y+
out PORTD,mp
; scrive il valore letto dalla SRAM sul registro della PORTA D
freq_1000:
in mp,PINC
ldi mp1,0b00010000
and mp,mp1
cpi mp,0
breq fine
; controlla il valore dell'interruttore di scrittura/lettura. Se il valore sul
;pin 27 è uguale a zero passa a fine altrimenti procedi
cpi count_1000,0
brne fine
; controlla il contatore che permette di leggere a 1000 Hz. Se è uguale a zero
;vuol dire che la subroutine di risposta all'interrupt ha azzerato il valore
25
;iniziale di count_1000, quindi può leggere il campione, altrimenti salta a fine
ldi count_1000,1
; reinizializza il contatore a 1
ld mp,Y+
out PORTD,mp
; scrive il valore letto dalla SRAM sul registro della PORTA D
fine:
rjmp check_batteria
; ritorna alla verifica della tensione di batteria
Il funzionamento in modalità di lettura è rappresentato nelle figure 11 e 12, in cui è possibile
vedere che il led verde corrispondente alla lettura è acceso. In particolare, in figura 11 è
osservabile il funzionamento con frequenza di lettura impostata a 500 Hz tramite l’interruttore T2
evidenziato in figura. Sullo schermo dell’oscilloscopio è rappresentato in alto il segnale
proveniente dal generatore inviato sul canale 1, mentre in basso è visualizzato il canale 2 a cui è
collegata l’uscita dell’amplificatore. Sul canale 2 viene rappresentato ciclicamente il segnale
memorizzato nella SRAM di lunghezza pari ad 1 s.
Figura 11. Visualizzazione del segnale a 500 Hz
Interruttore T2
26
In figura 12 è osservabile il funzionamento con frequenza di lettura pari a 1000 Hz, ossia il doppio
della frequenza di campionamento.
Figura 12. Visualizzazione del segnale a 1000 Hz
Interruttore T2
27
5 Appendice
Listato completo del software
;*******************************************************************************
;
; File: elettrocardiografo_digitale.ASM
; Data: 26 giugno 2013
; Version: 1.0
; IDE: AVR-Studio 4.0
;
; Autore: Gruppo 09-Lab. Progettazione Dispositivi Biomedici Programmabili
; Riferimenti: Politecnico di Torino - DET
;
;*******************************************************************************
; Programma che consente di simulare le funzioni di un elettrocardiografo
;digitale in grado di memorizzare il segnale ECG.
;*******************************************************************************
.NOLIST ; La direttiva .NOLIST fa si che ciò che segue non venga
;incluso nel listato.
.INCLUDE "atmega8.inc" ; La direttiva .INCLUDE inserisce il file "atmega8.inc"
.LIST ; La direttiva .LIST svolge l’operazione duale a quella
;svolta da .NOLIST.
; Definizione dei registri utilizzati
.DEF mp = R16 ; registro di lavoro (generico)
.DEF mp1 = R17 ; registro di lavoro secondario (generico)
.DEF mp2 = R24 ; primo registro per il decremento della variabile a 16 bit
.DEF mp3 = R25 ; secondo registro per il decremento della variabile a 16 bit
.DEF count_500 = R18 ; primo registro per la temporizzazione a 500 Hz
.DEF count_1000 = R19 ; secondo registro per la temporizzazione a 1000 Hz
.EQU tsh_bat = 227 ; fissa la soglia di tensione a 2,4V nominali
.EQU alta30 = 0x75 ;valore alto di 30000 per temporizzare il check batteria
.EQU bassa30 = 0x30 ; valore basso di 30000
; Allocazione della memoria SRAM
.DSEG
ind_tempo_batt: .BYTE 2
; riserva 2 bytes in cui salvo la variabile a 16 bit
; (30000) per il controllo della tensione di batteria
.org 0x93
; dopo le 96 celle dedicate ai registri, per mantenere 50 celle libere
; della SRAM, scrive i campioni a partire dalla 147esima cella
indirizzo: .BYTE 500
; riserva 500 bytes per scrivere i campioni del segnale ECG
.CSEG
28
rjmp RESET ; Reset Handler
reti ;rjmp EXT_INT0 ; IRQ0 Handler
reti ;rjmp EXT_INT1 ; IRQ1 Handler
reti ;rjmp TIM2_COMP ; Timer2 Compare Handler
reti ;rjmp TIM2_OVF ; Timer2 Overflow Handler
reti ;rjmp TIM1_CAPT ; Timer1 Capture Handler
reti ;rjmp TIM1_CAPT ; Timer1 Capture Handler
reti ;rjmp TIM1_COMPA ; Timer1 CompareA Handler
reti ;rjmp TIM1_COMPB ; Timer1 CompareB Handler
reti ;rjmp TIM1_OVF ; Timer1 Overflow Handler
rjmp TIM0_OVF ; Timer0 Overflow Handler
reti ;rjmp SPI_STC ; SPI Transfer Complete Handler
reti ;rjmp USART_RXC ; USART RX Complete Handler
reti ;rjmp USART_UDRE ; UDR Empty Handler
reti ;rjmp USART_TXC ; USART TX Complete Handler
reti ;rjmp ADC_conv ; ADC Conversion Complete Handler
reti ;rjmp EE_RDY ; EEPROM Ready Handler
reti ;rjmp ANA_COMP ; Analog Comparator Handler
reti ;rjmp TWSI ; Two-wire Serial Interface Handler
reti ;rjmp SPM_RDY ; Store Program Memory Ready Handler
RESET:
ldi mp,high(RAMEND) ;(0x04)
out SPH,mp
ldi mp,low(RAMEND) ;(0x5f)
out SPL,mp
; inizializzazione dello stack pointer all'ultimo indirizzo della SRAM
ldi mp,0b00000000
out DDRC,mp
; setta i pin della PORTA C tutti in ingresso
ldi mp,0x00
out PORTC,mp
; scrive zero nel registro della PORTA C
ldi mp,0b00001110
out DDRB,mp
; imposta in uscita i pin 15, 16 e 17 della PORTA B
; per i led di controllo scrittura, batteria, lettura
ldi mp,0x00
out PORTB,mp
; scrive zero nel registro della PORTA B
ldi mp,0b11111111
out DDRD,mp
; setta tutti i pin della PORTA D come uscite
ldi mp,0x00
out PORTD,mp
; scrive zero nel registro della PORTA D
ldi mp,0b00000101
out TCCR0,mp
; carica in TCCR0 i bit di mp, solo i primi 3 bit sono configurabili R/W,
; gli altri restano a 0. Il registro TCCR0 è usato per gestire la frequenza
; con cui generare un interrupt. Seleziona prescaler passo 1024
ldi mp,255
out TCNT0,mp
; imposta il valore iniziale del contatore a 255
29
ldi mp,0x01
out TIMSK,mp
; imposta il bit 0 del registro TIMSK ad 1 per abilitare la gestione degli
;interrupt in caso di overflow di TCNT0
ldi YL,low(indirizzo)
ldi YH,high(indirizzo)
; scrive in Y l'indirizzo da incrementare per scrivere i campioni di segnale
;nella SRAM
ldi XL,low(ind_tempo_batt)
ldi XH,high(ind_tempo_batt)
; scrive in X l'indirizzo dove andare a salvare il valore 30000 da decrementare
ldi mp,bassa30
ldi mp1,alta30
st X+,mp1
st X,mp
; scrive in SRAM il valore 30000 all'indirizzo contenuto in X
ldi count_500,2
ldi count_1000,1
; inizializza i contatori per temporizzare scrittura e lettura dei campioni
inizializzaRAM:
ldi mp,0
st Y+,mp
ldi mp,low(0x288)
cp YL,mp
brne inizializzaRAM
ldi mp,high(0x288)
cp YH,mp
brne inizializzaRAM
ldi YL,low(indirizzo)
ldi YH,high(indirizzo)
; scrive zero nelle 500 celle di memoria riservate a memorizzare
; i campioni del segnale in modo da essere certi del valore letto inizialmente
; all'avvio del programma
;-------------------------------------------------------------------------------
; ABILITAZIONE E PROGRAMMAZIONE ADC
;-------------------------------------------------------------------------------
ldi mp,0b10000010
out ADCSRA,mp
; imposta il fattore di prescaling pari a 4.
; ADCSRA è un registro a 8 bit in particolare:
; se il bit7=1 --> abilita ADC
; se il bit6=1 --> start conversione
; se il bit5=1 (ADFR) --> seleziona il Free Running mode
; se il bit4=1(ADIF) --> a fine conversione genero un interrupt portando ad 1 il
;bit 3
; i bit 2:0 selezionano il fattore di prescaling
sei
; abilito la sensibilità della CPU agli interrupt
30
;-------------------------------------------------------------------------------
; VERIFICA TENSIONE DI BATTERIA
; Questa funzione controlla la tensione di batteria ad intervalli di 30 secondi
;generando un allarme visivo (accensione led su pin 16)
;-------------------------------------------------------------------------------
check_batteria:
ldi XL,low(ind_tempo_batt)
ldi XH,high(ind_tempo_batt)
; carica in X l'indirizzo in cui è salvato il valore 30000 che viene
;decrementato
ld mp1,X+
ld mp,X
; legge dalla SRAM il valore a 16 bit (30000) e lo carica nei registri mp1
;(parte alta) e mp (parte bassa)
cpi mp,0
brne controllo_indirizzo
; se la parte bassa è zero controlla la parte alta del valore altrimenti
; salta al controllo indirizzo
cpi mp1,0
brne controllo_indirizzo
; se anche la parte alta è zero reinizializza il valore a 30000 altrimenti
; salta al controllo indirizzo
ldi XL,low(ind_tempo_batt)
ldi XH,high(ind_tempo_batt)
ldi mp,bassa30
ldi mp1,alta30
st X+,mp1
st X,mp
; riscrive in SRAM il valore iniziale (30000) della variabile da decrementare
; per il controllo della batteria
ldi mp,0b11100001
out ADMUX,mp
; programma l'ADC in modo che lavori con tensione di riferimento interna a 2,56V
; (in realtà è 2,71V), giustifica a sinistra il risultato nel registro ADCH e
; seleziona ADC1 (pin 24) come ingresso del convertitore
in mp,ADCSRA
ldi mp1,0b01000000
or mp,mp1
out ADCSRA,mp
; inizia la conversione del valore di tensione di batteria
check_conv_batteria:
in mp,ADCSRA
ldi mp1,0b01000000
and mp,mp1
brne check_conv_batteria
; aspetta che la conversione sia pronta testando ADSC in ADCSRA
; a conversione terminata ADSC torna a 0
in mp,ADCH
; legge ADCH che contiene il valore di tensione convertito su 8 bit
31
cpi mp,tsh_bat
brsh controllo_indirizzo
; se il valore letto di tensione è maggiore o uguale alla soglia va avanti
;altrimenti accende il led
in mp1,PORTB ;legge quello che ho precedentemente scritto sulla porta B
ldi mp,0b00000100
or mp,mp1
;cambia solo il valore sul pin 16 mantenendo invariati gli altri
out PORTB,mp ;accende il led sul pin 16
;-------------------------------------------------------------------------------
; CONTROLLO SULL'INDIRIZZO ATTUALE DELLA SRAM
; Questa funzione controlla che l'indirizzo che punta alla cella di memoria in
;cui memorizzare il campione sia l'ultimo, in tal caso torna a memorizzare a
;partire dalla prima cella del blocco di memoria (500 bytes) riservato ai
;campioni, altrimenti continua a memorizzare nella cella successiva
;-------------------------------------------------------------------------------
controllo_indirizzo:
ldi mp,low(0x288)
cp YL,mp
brne scrittura
; se la parte bassa dell'indirizzo corrente è uguale alla parte bassa
;dell'indirizzo della prima cella dopo l'ultima riservata
;controlla anche la parte alta, altrimenti salta a scrittura
ldi mp,high(0x288)
cp YH,mp
brne scrittura
; se anche la parte alta dell'indirizzo corrente è uguale alla parte alta
;dell'indirizzo della prima cella dopo l'ultima riservata
;reinizializza l'indirizzo e prosegui con la scrittura. altrimenti salta a
;scrittura senza reinizializzare l'indirizzo
ldi YH,high(indirizzo)
ldi YL,low(indirizzo)
;reinizializza l'indirizzo della prima cella della SRAM per la scrittura/lettura
;-------------------------------------------------------------------------------
; CAMPIONAMENTO E SCRITTURA
; Questa funzione campiona il segnale in ingresso, lo converte in digitale e lo
;scrive nella SRAM
;-------------------------------------------------------------------------------
scrittura:
in mp,PINC
ldi mp1,0b00100000
and mp,mp1
cpi mp,0
brne lettura
; controlla il valore dell'interruttore di scrittura/lettura. Se il valore sul
;pin 28 è uguale a zero procedi con la scrittura altrimenti passa alla lettura
ldi mp,0x00
out PORTD,mp
; dato che si sta effettuando la scrittura dei campioni, sulla PORTA D manda
;zero per avere contezza del valore sulla porta
32
in mp,PORTB
ldi mp1,0b11110111
and mp,mp1
ldi mp1,0b00000010
or mp,mp1
out PORTB,mp
; spegne il led di lettura sul pin 17 e accende il led di scrittura sul pin 15
ldi mp,0b11100010
out ADMUX,mp
; imposta ADC2 (pin 25) come ingresso al convertitore
cpi count_500,0
brne lettura
; verifica del contatore che permette una frequenza di campionamento di 500 Hz,
; se il contatore è uguale a zero è giunto l'istante di campionare
ldi count_500,2
; reinizializza il contatore a 2
in mp,ADCSRA
ldi mp1,0b01000000
or mp,mp1
out ADCSRA,mp
; inizia la conversione dei campioni del segnale
check_conv_scrittura:
in mp,ADCSRA
ldi mp1,0b01000000
and mp,mp1
brne check_conv_scrittura
; aspetta che la conversione sia pronta testando ADSC in ADCSRA: a conversione
;terminata ADSC torna a 0
in mp1,ADCH
; legge ADCH che contiene il campione convertito su 8 bit
st Y+,mp1
; scrive il campione in SRAM all'indirizzo contenuto in Y e incrementa
;l'indirizzo contenuto in Y
;-------------------------------------------------------------------------------
; LETTURA E VISUALIZZAZIONE CAMPIONI
; Questa funzione legge i campioni di segnale memorizzati nella SRAM e li invia
;in uscita tramite la PORTA D, con due diverse frequenze, 500 e 1000 Hz.
;-------------------------------------------------------------------------------
lettura:
in mp,PINC
ldi mp1,0b00100000
and mp,mp1
cpi mp,0
breq fine
; controlla il valore dell'interruttore di scrittura/lettura. Se il valore sul
;pin 28 è uguale a zero passa a fine altrimenti procedi
in mp,PORTB
ldi mp1,0b11111101
and mp,mp1
ldi mp1,0b00001000
33
or mp,mp1
out PORTB,mp
; spegne il led di scrittura sul pin 15 e accende il led di lettura sul pin 17
in mp,PINC
ldi mp1,0b00010000
and mp,mp1
cpi mp,0
brne freq_1000
; controlla il valore dell'interruttore delle frequenze. Se il valore sul pin 27
;è 0 legge a 500 Hz altrimenti a 1000 Hz
freq_500:
cpi count_500,0
brne freq_1000
; controlla il contatore che permette di leggere a 500 Hz. Se è uguale a zero
;vuol dire che la routine di risposta all'interrupt ha azzerato il valore
;iniziale di count_500, quindi può leggere il campione, altrimenti salta a
;freq_1000
ldi count_500,2
; reinizializza il contatore a 2
ld mp,Y+
out PORTD,mp
; scrive il valore letto dalla SRAM sul registro della PORTA D
freq_1000:
in mp,PINC
ldi mp1,0b00010000
and mp,mp1
cpi mp,0
breq fine
; controlla il valore dell'interruttore di scrittura/lettura. Se il valore sul
;pin 27 è uguale a zero passa a fine altrimenti procedi
cpi count_1000,0
brne fine
; controlla il contatore che permette di leggere a 1000 Hz. Se è uguale a zero
;vuol dire che la subroutine di risposta all'interrupt ha azzerato il valore
;iniziale di count_1000, quindi può leggere il campione, altrimenti salta a fine
ldi count_1000,1
; reinizializza il contatore a 1
ld mp,Y+
out PORTD,mp
; scrive il valore letto dalla SRAM sul registro della PORTA D
fine:
rjmp check_batteria
; ritorna alla verifica della tensione di batteria
34
;-------------------------------------------------------------------------------
; SUBROUTINE DI RISPOSTA AD INTERRUPT
;-------------------------------------------------------------------------------
TIM0_OVF:
push mp
push mp1
push mp2
push mp3
in mp,SREG
push mp
; push dei registri utilizzati, per garantire che non vengano modificati dalla
;subroutine di risposta ad interrupt
ldi mp,255
out TCNT0,mp
; reinizializza il contatore del timer counter
dec count_500
; decremento del contatore count_500
dec count_1000
; decremento del contatore count_1000
ldi XL,low(ind_tempo_batt)
ldi XH,high(ind_tempo_batt)
ld mp3,X+
ld mp2,X
sbiw mp3:mp2,1
; decremento della variabile a 16 bit per la temporizzazione del controllo di
;tensione di batteria
ldi XL,low(ind_tempo_batt)
ldi XH,high(ind_tempo_batt)
st X+,mp3
st X,mp2
; scrittura nella SRAM del valore a 16 bit decrementato
pop mp
out SREG,mp
pop mp3
pop mp2
pop mp1
pop mp
; ripristino dei registri utilizzati
reti
; ritorna all'esecuzione del programma principale

More Related Content

What's hot

ATIPICO POTENTE TASCABILE INDUSTRIAL PLC
ATIPICO POTENTE TASCABILE INDUSTRIAL PLCATIPICO POTENTE TASCABILE INDUSTRIAL PLC
ATIPICO POTENTE TASCABILE INDUSTRIAL PLCRémi GUILBERT
 
Radioastronomia amatoriale e radiotelescopi
Radioastronomia amatoriale e radiotelescopiRadioastronomia amatoriale e radiotelescopi
Radioastronomia amatoriale e radiotelescopiFlavio Falcinelli
 
Lezione 4 arduino - corso 20 ore
Lezione 4 arduino - corso 20 oreLezione 4 arduino - corso 20 ore
Lezione 4 arduino - corso 20 oreMirko Mancin
 
Il cuore di Arduino: Un sistema di sviluppo basato su microcontrollore Atmel ...
Il cuore di Arduino: Un sistema di sviluppo basato su microcontrollore Atmel ...Il cuore di Arduino: Un sistema di sviluppo basato su microcontrollore Atmel ...
Il cuore di Arduino: Un sistema di sviluppo basato su microcontrollore Atmel ...Sardegna Ricerche
 
Ltc2990 monitoraggio di temperatura, tensione e corrente con i2 c - 2010-11-10
Ltc2990   monitoraggio di temperatura, tensione e corrente con i2 c - 2010-11-10Ltc2990   monitoraggio di temperatura, tensione e corrente con i2 c - 2010-11-10
Ltc2990 monitoraggio di temperatura, tensione e corrente con i2 c - 2010-11-10Ionela
 
Convertitori Digitale-Analogico
Convertitori Digitale-AnalogicoConvertitori Digitale-Analogico
Convertitori Digitale-AnalogicoPasquale Alba
 
Progetto ldc
Progetto ldcProgetto ldc
Progetto ldcaaa bbbb
 
Encoder per sistemi robotici, motori & applicazioni OEM - Lika Electronic - E...
Encoder per sistemi robotici, motori & applicazioni OEM - Lika Electronic - E...Encoder per sistemi robotici, motori & applicazioni OEM - Lika Electronic - E...
Encoder per sistemi robotici, motori & applicazioni OEM - Lika Electronic - E...Lika Electronic
 
Candy washing machine_error_code_
Candy washing machine_error_code_Candy washing machine_error_code_
Candy washing machine_error_code_Domingo Arroyo
 
Timer multifunzione 555
Timer multifunzione 555Timer multifunzione 555
Timer multifunzione 555Pasquale Alba
 
Crouzet Automation - em4 Guida alla scelta
Crouzet Automation - em4 Guida alla sceltaCrouzet Automation - em4 Guida alla scelta
Crouzet Automation - em4 Guida alla sceltaCrouzet
 
Circuiti logici combinatori registri flip flop
Circuiti logici combinatori registri flip flopCircuiti logici combinatori registri flip flop
Circuiti logici combinatori registri flip flopPasquale Alba
 
Workshop arduino e sensori
Workshop arduino e sensoriWorkshop arduino e sensori
Workshop arduino e sensoriPaolo Aliverti
 
Ltc4219 controllore hot swap integrato da 5 a - 2010-10-13
Ltc4219   controllore hot swap integrato da 5 a - 2010-10-13Ltc4219   controllore hot swap integrato da 5 a - 2010-10-13
Ltc4219 controllore hot swap integrato da 5 a - 2010-10-13Ionela
 

What's hot (20)

ATIPICO POTENTE TASCABILE INDUSTRIAL PLC
ATIPICO POTENTE TASCABILE INDUSTRIAL PLCATIPICO POTENTE TASCABILE INDUSTRIAL PLC
ATIPICO POTENTE TASCABILE INDUSTRIAL PLC
 
Radioastronomia amatoriale e radiotelescopi
Radioastronomia amatoriale e radiotelescopiRadioastronomia amatoriale e radiotelescopi
Radioastronomia amatoriale e radiotelescopi
 
Lezione 4 arduino - corso 20 ore
Lezione 4 arduino - corso 20 oreLezione 4 arduino - corso 20 ore
Lezione 4 arduino - corso 20 ore
 
uNav - Board
uNav - BoarduNav - Board
uNav - Board
 
Il pic 16 f84a
Il pic 16 f84aIl pic 16 f84a
Il pic 16 f84a
 
Workshop su Arduino
Workshop su ArduinoWorkshop su Arduino
Workshop su Arduino
 
Attrezzature matera
Attrezzature materaAttrezzature matera
Attrezzature matera
 
Il cuore di Arduino: Un sistema di sviluppo basato su microcontrollore Atmel ...
Il cuore di Arduino: Un sistema di sviluppo basato su microcontrollore Atmel ...Il cuore di Arduino: Un sistema di sviluppo basato su microcontrollore Atmel ...
Il cuore di Arduino: Un sistema di sviluppo basato su microcontrollore Atmel ...
 
Ltc2990 monitoraggio di temperatura, tensione e corrente con i2 c - 2010-11-10
Ltc2990   monitoraggio di temperatura, tensione e corrente con i2 c - 2010-11-10Ltc2990   monitoraggio di temperatura, tensione e corrente con i2 c - 2010-11-10
Ltc2990 monitoraggio di temperatura, tensione e corrente con i2 c - 2010-11-10
 
Convertitori Digitale-Analogico
Convertitori Digitale-AnalogicoConvertitori Digitale-Analogico
Convertitori Digitale-Analogico
 
Progetto ldc
Progetto ldcProgetto ldc
Progetto ldc
 
Encoder per sistemi robotici, motori & applicazioni OEM - Lika Electronic - E...
Encoder per sistemi robotici, motori & applicazioni OEM - Lika Electronic - E...Encoder per sistemi robotici, motori & applicazioni OEM - Lika Electronic - E...
Encoder per sistemi robotici, motori & applicazioni OEM - Lika Electronic - E...
 
Candy washing machine_error_code_
Candy washing machine_error_code_Candy washing machine_error_code_
Candy washing machine_error_code_
 
Fare Musica con Arduino
Fare Musica con ArduinoFare Musica con Arduino
Fare Musica con Arduino
 
Timer multifunzione 555
Timer multifunzione 555Timer multifunzione 555
Timer multifunzione 555
 
Crouzet Automation - em4 Guida alla scelta
Crouzet Automation - em4 Guida alla sceltaCrouzet Automation - em4 Guida alla scelta
Crouzet Automation - em4 Guida alla scelta
 
Circuiti logici combinatori registri flip flop
Circuiti logici combinatori registri flip flopCircuiti logici combinatori registri flip flop
Circuiti logici combinatori registri flip flop
 
Conversione A/D
Conversione A/DConversione A/D
Conversione A/D
 
Workshop arduino e sensori
Workshop arduino e sensoriWorkshop arduino e sensori
Workshop arduino e sensori
 
Ltc4219 controllore hot swap integrato da 5 a - 2010-10-13
Ltc4219   controllore hot swap integrato da 5 a - 2010-10-13Ltc4219   controllore hot swap integrato da 5 a - 2010-10-13
Ltc4219 controllore hot swap integrato da 5 a - 2010-10-13
 

Similar to Design of programmable medical devices_Teamwork

Progettazione di un convertitore analogico digitale in architettura multistadio
Progettazione di un convertitore analogico digitale in architettura multistadioProgettazione di un convertitore analogico digitale in architettura multistadio
Progettazione di un convertitore analogico digitale in architettura multistadioNelson Firmani
 
An IoT prototype: from ideation to promotion
An IoT prototype: from ideation to promotionAn IoT prototype: from ideation to promotion
An IoT prototype: from ideation to promotionJennifer De Filicaia
 
Curva di equalizzazione per un acquisitore rev.01 - 11.04.2017
Curva di equalizzazione per un acquisitore   rev.01 - 11.04.2017Curva di equalizzazione per un acquisitore   rev.01 - 11.04.2017
Curva di equalizzazione per un acquisitore rev.01 - 11.04.2017Corrado Pecora
 
Corso Arduino Base - MUST
Corso Arduino Base - MUSTCorso Arduino Base - MUST
Corso Arduino Base - MUSTOPS Italia
 
Lezione 2 arduino - corso 20 ore
Lezione 2 arduino - corso 20 oreLezione 2 arduino - corso 20 ore
Lezione 2 arduino - corso 20 oreMirko Mancin
 
Teleoperating a robotic arm through a gyroscopic helmet
Teleoperating a robotic arm through a gyroscopic helmetTeleoperating a robotic arm through a gyroscopic helmet
Teleoperating a robotic arm through a gyroscopic helmetFrancesco Corucci
 
Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...
Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...
Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...Andrea Gulberti
 
Comunicazione per sensori intelligenti IO-Link
Comunicazione per sensori intelligenti IO-LinkComunicazione per sensori intelligenti IO-Link
Comunicazione per sensori intelligenti IO-Linkifm electronic gmbh
 
Dsp cosa sono i digital signal processor - seconda parte - 2010-10-19
Dsp  cosa sono i digital signal processor  - seconda parte - 2010-10-19Dsp  cosa sono i digital signal processor  - seconda parte - 2010-10-19
Dsp cosa sono i digital signal processor - seconda parte - 2010-10-19Ionela
 
30@30: Newsletter aprile
30@30: Newsletter aprile30@30: Newsletter aprile
30@30: Newsletter aprileLika Electronic
 
Brochure: Borstelloze DC motoren Green Line
Brochure: Borstelloze DC motoren Green LineBrochure: Borstelloze DC motoren Green Line
Brochure: Borstelloze DC motoren Green LineDrivetecno
 
Arkanoid on Altera DE-1
Arkanoid on Altera DE-1Arkanoid on Altera DE-1
Arkanoid on Altera DE-1Matteo Gazzin
 
Presentazione
PresentazionePresentazione
Presentazionecesario
 
EuComm
EuCommEuComm
EuCommiBLio
 
Il punto di partenza della radioastronomia amatoriale: un radiotelescopio a p...
Il punto di partenza della radioastronomia amatoriale: un radiotelescopio a p...Il punto di partenza della radioastronomia amatoriale: un radiotelescopio a p...
Il punto di partenza della radioastronomia amatoriale: un radiotelescopio a p...Flavio Falcinelli
 

Similar to Design of programmable medical devices_Teamwork (20)

Progettazione di un convertitore analogico digitale in architettura multistadio
Progettazione di un convertitore analogico digitale in architettura multistadioProgettazione di un convertitore analogico digitale in architettura multistadio
Progettazione di un convertitore analogico digitale in architettura multistadio
 
An IoT prototype: from ideation to promotion
An IoT prototype: from ideation to promotionAn IoT prototype: from ideation to promotion
An IoT prototype: from ideation to promotion
 
Workshop arduino
Workshop arduinoWorkshop arduino
Workshop arduino
 
Curva di equalizzazione per un acquisitore rev.01 - 11.04.2017
Curva di equalizzazione per un acquisitore   rev.01 - 11.04.2017Curva di equalizzazione per un acquisitore   rev.01 - 11.04.2017
Curva di equalizzazione per un acquisitore rev.01 - 11.04.2017
 
Corso Arduino Base - MUST
Corso Arduino Base - MUSTCorso Arduino Base - MUST
Corso Arduino Base - MUST
 
Assembly2
Assembly2Assembly2
Assembly2
 
Lezione 2 arduino - corso 20 ore
Lezione 2 arduino - corso 20 oreLezione 2 arduino - corso 20 ore
Lezione 2 arduino - corso 20 ore
 
Teleoperating a robotic arm through a gyroscopic helmet
Teleoperating a robotic arm through a gyroscopic helmetTeleoperating a robotic arm through a gyroscopic helmet
Teleoperating a robotic arm through a gyroscopic helmet
 
Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...
Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...
Sviluppo del sistema di controllo dell'assetto di un quadricottero con proces...
 
Technical Note Tn 1201
Technical Note Tn 1201Technical Note Tn 1201
Technical Note Tn 1201
 
Comunicazione per sensori intelligenti IO-Link
Comunicazione per sensori intelligenti IO-LinkComunicazione per sensori intelligenti IO-Link
Comunicazione per sensori intelligenti IO-Link
 
Dsp cosa sono i digital signal processor - seconda parte - 2010-10-19
Dsp  cosa sono i digital signal processor  - seconda parte - 2010-10-19Dsp  cosa sono i digital signal processor  - seconda parte - 2010-10-19
Dsp cosa sono i digital signal processor - seconda parte - 2010-10-19
 
30@30: Newsletter aprile
30@30: Newsletter aprile30@30: Newsletter aprile
30@30: Newsletter aprile
 
Brochure: Borstelloze DC motoren Green Line
Brochure: Borstelloze DC motoren Green LineBrochure: Borstelloze DC motoren Green Line
Brochure: Borstelloze DC motoren Green Line
 
Arkanoid on Altera DE-1
Arkanoid on Altera DE-1Arkanoid on Altera DE-1
Arkanoid on Altera DE-1
 
Presentazione
PresentazionePresentazione
Presentazione
 
EuComm
EuCommEuComm
EuComm
 
MEDIDOR
MEDIDORMEDIDOR
MEDIDOR
 
Patternator project
Patternator projectPatternator project
Patternator project
 
Il punto di partenza della radioastronomia amatoriale: un radiotelescopio a p...
Il punto di partenza della radioastronomia amatoriale: un radiotelescopio a p...Il punto di partenza della radioastronomia amatoriale: un radiotelescopio a p...
Il punto di partenza della radioastronomia amatoriale: un radiotelescopio a p...
 

Design of programmable medical devices_Teamwork

  • 1. Funzioni per un Elettrocardiografo Digitale Progettazione di dispositivi biomedici programmabili Docente Marco Knaflitz Zito Antonella matr.188795 - Gruppo di lavoro 09 a.a. 2012/2013
  • 2. 1 Sommario Introduzione ...................................................................................................................................................... 2 1 Configurazione del circuito elettrico .............................................................................................................. 2 2 Specifiche di progetto..................................................................................................................................... 5 3 Caratteristiche del segnale in ingresso........................................................................................................... 5 4 Software ......................................................................................................................................................... 5 4.1 Inizializzazioni e impostazione del convertitore...................................................................................... 7 4.2 Subroutine di risposta ad interrupt....................................................................................................... 10 4.3 Funzione per la verifica della tensione di batteria ................................................................................ 12 4.4 Controllo dell’indirizzo di memoria....................................................................................................... 17 4.5 Funzione per il campionamento di un segnale analogico ..................................................................... 19 4.6 Funzione per la lettura e la ricostruzione del segnale........................................................................... 22 5 Appendice..................................................................................................................................................... 27 Listato completo del software..................................................................................................................... 27
  • 3. 2 Introduzione Il progetto descritto in queste pagine ha come obiettivo quello di realizzare un circuito in grado di svolgere alcune funzioni di un elettrocardiografo digitale. L’elemento circuitale principale è il microcontrollore Atmel ATMEGA 8 opportunamente programmato in linguaggio Assembly. Per la realizzazione delle varie funzioni, il microcontrollore è stato interfacciato con altri componenti elettronici meglio specificati in seguito. La descrizione di ogni funzione è supportata dal flow-chart e dal codice implementativo corrispondenti. 1 Configurazione del circuito elettrico I componenti rilevanti del circuito sono:  Il microcontrollore a 8 bit Atmel ATMEGA 8  Il convertitore Digitale-Analogico DAC0808  L’amplificatore Operazionale TL081 Il microcontrollore è alimentato con una tensione costante (Vcc) di 5 V fornita attraverso il pin 7. Il convertitore Analogico-Digitale interno al microcontrollore, che riceve in ingresso il segnale simil- ECG e la tensione di batteria, è alimentato con una tensione costante di 5 V sul pin 20. Il convertitore lavora con una tensione di riferimento interna misurata pari a 2,71 V. Il segnale simil- ECG è portato in ingresso al convertitore tramite il pin 25, mentre la tensione di batteria arriva sul pin 24 attraverso un partitore di tensione atto a dimezzare la tensione Vcc. L’alimentatore da banco utilizzato è un Agilent E3631A. I pin 15,16,17 settati come uscite comandano ciascuno l’accensione di un led. A ciascuno dei pin 27 e 28, settati come ingressi, è collegato un interruttore per la selezione delle modalità di funzionamento. Il segnale convertito in digitale viene trasferito in parallelo al DAC0808 tramite i pin 2,3,4,5,6,11,12,13. Il DAC0808 è alimentato tra tensioni costanti di +5 V (sul pin 13) e -5 V (sul pin 3). La tensione di riferimento con cui lavora il DAC è la stessa utilizzata dal convertitore A/D e viene direttamente prelevata dal pin 21 (AREF) del microcontrollore per essere condotta fino al pin 14 del DAC. Successivamente il segnale in uscita dal DAC0808 viene condotto all’amplificatore operazionale TL081, il quale è alimentato tra tensioni costanti di +5 V (sul pin 7) e -5 V (sul pin 4). Al fine di ridurre il rumore sul segnale in uscita dall’amplificatore sono stati utilizzati due condensatori (C8 e C9) con capacità pari a 120 nF, collegati tra le rispettive tensioni d’alimentazione e la massa.
  • 4. 3 Figura 1. Configurazione del circuito elettrico
  • 5. 4 Figura 2. Foto del circuito
  • 6. 5 2 Specifiche di progetto Le specifiche di progetto prevedono che il circuito sia in grado di svolgere le seguenti funzioni: 1. Verifica della tensione di batteria e generazione di un allarme visivo in presenza di tensione troppo bassa. 2. Campionamento di un segnale analogico con frequenza pari a 500 Hz e memorizzazione dei campioni in SRAM. 3. Lettura dei campioni di segnale ECG in SRAM e trasferimento ad un convertitore D/A parallelo per ricostruire il segnale. 4. Variazione della velocità con la quale i campioni memorizzati sono portati al DAC. 3 Caratteristiche del segnale in ingresso Il segnale in ingresso è un segnale simil-ECG ottenuto mediante un generatore di funzioni Agilent 33220A. La frequenza del segnale è stata impostata ad 1 Hz, mentre l’ampiezza picco-picco ad 1 V. E’ stato introdotto un offset di 0.3 V in modo tale da evitare di inviare tensioni negative al microcontrollore. Al fine di visualizzare correttamente la forma d’onda del segnale sull’oscilloscopio è stata impostata la modalità con alta impedenza in uscita dal generatore di funzioni. 4 Software In questo capitolo verranno descritte singolarmente le varie parti che compongono il programma caricato sul microcontrollore. Il listato del codice nella sua interezza è riportato in appendice. L’implementazione è stata effettuata utilizzando il software AVR Studio 4 mentre la programmazione del microcontrollore è avvenuta tramite l’utilizzo della scheda AVR Dragon. Nella scrittura del programma, la prima operazione necessaria è quella di includere il file “atmega8.inc” che consente di utilizzare delle stringhe piuttosto che esplicitare i corrispondenti indirizzi di memoria specifici del microcontrollore. Questo si effettua tramite le direttive: .NOLIST ; La direttiva .NOLIST fa si che ciò che segue non venga ;incluso nel listato. .INCLUDE "atmega8.inc" ; La direttiva .INCLUDE inserisce il file "atmega8.inc" .LIST ; La direttiva .LIST svolge l’operazione duale a quella ;svolta da .NOLIST.
  • 7. 6 Le successive operazioni che precedono il ciclo principale del software prevedono la definizione dei registri utilizzati, l’assegnazione di stringhe ai valori numerici utilizzati e l’allocazione della memoria SRAM necessaria alla memorizzazione di una variabile a 16 bit e dei campioni di segnale. In particolare, si è scelto di allocare uno spazio pari a 500 bytes che ad una frequenza di campionamento di 500 Hz consente la memorizzazione di un secondo di segnale. La porzione di codice che svolge questo compito è la seguente: .DEF mp = R16 ; registro di lavoro (generico) .DEF mp1 = R17 ; registro di lavoro secondario (generico) .DEF mp2 = R24 ; primo registro per il decremento della variabile a 16 bit .DEF mp3 = R25 ; secondo registro per il decremento della variabile a 16 bit .DEF count_500 = R18 ; primo registro per la temporizzazione a 500 Hz .DEF count_1000 = R19 ; secondo registro per la temporizzazione a 1000 Hz .EQU tsh_bat = 227 ; fissa la soglia di tensione a 2,4V nominali .EQU alta30 = 0x75 ;valore alto di 30000 per temporizzare il check batteria .EQU bassa30 = 0x30 ; valore basso di 30000 ; Allocazione della memoria SRAM .DSEG ind_tempo_batt: .BYTE 2 ; riserva 2 bytes in cui salvo la variabile a 16 bit ; (30000) per il controllo della tensione di batteria .org 0x93 ; dopo le 96 celle dedicate ai registri, per mantenere 50 celle libere ; della SRAM, scrive i campioni a partire dalla 147esima cella indirizzo: .BYTE 500 ; riserva 500 bytes per scrivere i campioni del segnale ECG .CSEG Nella seguente porzione di codice si specifica la gestione degli interrupt. rjmp RESET ; Reset Handler reti ;rjmp EXT_INT0 ; IRQ0 Handler reti ;rjmp EXT_INT1 ; IRQ1 Handler reti ;rjmp TIM2_COMP ; Timer2 Compare Handler reti ;rjmp TIM2_OVF ; Timer2 Overflow Handler reti ;rjmp TIM1_CAPT ; Timer1 Capture Handler reti ;rjmp TIM1_CAPT ; Timer1 Capture Handler reti ;rjmp TIM1_COMPA ; Timer1 CompareA Handler reti ;rjmp TIM1_COMPB ; Timer1 CompareB Handler reti ;rjmp TIM1_OVF ; Timer1 Overflow Handler rjmp TIM0_OVF ; Timer0 Overflow Handler reti ;rjmp SPI_STC ; SPI Transfer Complete Handler reti ;rjmp USART_RXC ; USART RX Complete Handler reti ;rjmp USART_UDRE ; UDR Empty Handler reti ;rjmp USART_TXC ; USART TX Complete Handler reti ;rjmp ADC_conv ; ADC Conversion Complete Handler reti ;rjmp EE_RDY ; EEPROM Ready Handler reti ;rjmp ANA_COMP ; Analog Comparator Handler reti ;rjmp TWSI ; Two-wire Serial Interface Handler reti ;rjmp SPM_RDY ; Store Program Memory Ready Handler
  • 8. 7 La parte successiva del codice consiste nella routine principale del programma il cui funzionamento è schematizzato nel seguente flow-chart generale. Figura 3. Flow-chart generale della routine principale del software 4.1 Inizializzazioni e impostazione del convertitore All’interno della routine principale del programma, la prima operazione da compiere è l’inizializzazione dello Stack Pointer. Ciò è d’obbligo in quanto si utilizzerà una subroutine di risposta ad interrupt. Per l’inizializzazione si ricorre ai registri SPH ed SPL in cui vengono scritte rispettivamente le parti alta e bassa dell’ultimo indirizzo della SRAM. Per svolgere le funzioni richieste vengono utilizzate le porte B,C e D del microcontrollore. Per scegliere la direzione dei dati sui pin delle varie porte si utilizzano i registri DDR (Data Direction Register), mentre per impostare il valore iniziale presente sulla porta si fa utilizzo dei registri PORT. La scelta progettuale prevede l’utilizzo di un solo Timer Counter a 8 bit, nello specifico il Timer Counter 0. Per la sua gestione vengono utilizzati i registri TCCR0, TCNT0 e TIMSK che permettono di impostare rispettivamente il passo di prescaler, il valore iniziale del timer e la generazione del segnale di interrupt in corrispondenza di un overflow. Il valore iniziale assegnato a TCNT0 è pari a 255, in tal modo l’overflow del contatore si verifica circa ogni millisecondo poiché il passo di prescaler prescelto è di 1024 e la frequenza del clock del sistema risulta pari a 1MHz. Stabilito che il controllo della tensione di batteria venga effettuato ogni 30 secondi, per ottenere l’intervallo di tempo corrispondente, si è scelto il valore 30000 essendo questo decrementato ogni millisecondo. Tale valore a 16 bit viene memorizzato nella SRAM all’indirizzo precedentemente assegnato (ind_tempo_batt). RESET INIZIALIZZAZIONI CHECK BATTERIA CONTROLLO INDIRIZZO SCRITTURA LETTURA FINE
  • 9. 8 Per stabilire l’intervallo di campionamento e quello di trasferimento dei campioni al convertitore D/A, vengono inizializzate le variabili count_500 e count_1000. Inoltre, l’ultima operazione di questa sezione di codice prevede l’inizializzazione della SRAM. Nelle celle riservate alla memorizzazione dei campioni viene scritto il valore zero per avere certezza di ciò che viene letto nel caso di avvio del programma nella modalità di lettura, quando cioè nella SRAM non sono stati ancora memorizzati i campioni di segnale. Quanto detto è riportato in dettaglio nel listato seguente: RESET: ldi mp,high(RAMEND) ;(0x04) out SPH,mp ldi mp,low(RAMEND) ;(0x5f) out SPL,mp ; inizializzazione dello stack pointer all'ultimo indirizzo della SRAM ldi mp,0b00000000 out DDRC,mp ; setta i pin della PORTA C tutti in ingresso ldi mp,0x00 out PORTC,mp ; scrive zero nel registro della PORTA C ldi mp,0b00001110 out DDRB,mp ; imposta in uscita i pin 15, 16 e 17 della PORTA B ; per i led di controllo scrittura, batteria, lettura ldi mp,0x00 out PORTB,mp ; scrive zero nel registro della PORTA B ldi mp,0b11111111 out DDRD,mp ; setta tutti i pin della PORTA D come uscite ldi mp,0x00 out PORTD,mp ; scrive zero nel registro della PORTA D ldi mp,0b00000101 out TCCR0,mp ; carica in TCCR0 i bit di mp, solo i primi 3 bit sono configurabili R/W, ; gli altri restano a 0. Il registro TCCR0 è usato per gestire la frequenza ; con cui generare un interrupt. Seleziona prescaler passo 1024 ldi mp,255 out TCNT0,mp ; imposta il valore iniziale del contatore a 255 ldi mp,0x01 out TIMSK,mp ; imposta il bit 0 del registro TIMSK ad 1 per abilitare la gestione degli ;interrupt in caso di overflow di TCNT0
  • 10. 9 ldi YL,low(indirizzo) ldi YH,high(indirizzo) ; scrive in Y l'indirizzo da incrementare per scrivere i campioni di segnale ;nella SRAM ldi XL,low(ind_tempo_batt) ldi XH,high(ind_tempo_batt) ; scrive in X l'indirizzo dove andare a salvare il valore 30000 da decrementare ldi mp,bassa30 ldi mp1,alta30 st X+,mp1 st X,mp ; scrive in SRAM il valore 30000 all'indirizzo contenuto in X ldi count_500,2 ldi count_1000,1 ; inizializza i contatori per temporizzare scrittura e lettura dei campioni inizializzaRAM: ldi mp,0 st Y+,mp ldi mp,low(0x288) cp YL,mp brne inizializzaRAM ldi mp,high(0x288) cp YH,mp brne inizializzaRAM ldi YL,low(indirizzo) ldi YH,high(indirizzo) ; scrive zero nelle 500 celle di memoria riservate a memorizzare ; i campioni del segnale in modo da essere certi del valore letto inizialmente ; all'avvio del programma Prima di passare all’implementazione delle funzioni vere e proprie, si procede con la configurazione del convertitore Analogico-Digitale interno al microcontrollore. Questo si fa andando a modificare il registro ADCSRA. Il codice seguente svolge quanto detto. ldi mp,0b10000010 out ADCSRA,mp ; imposta il fattore di prescaling pari a 4. ; ADCSRA è un registro a 8 bit in particolare: ; se il bit7=1 --> abilita ADC ; se il bit6=1 --> start conversione ; se il bit5=1 (ADFR) --> seleziona il Free Running mode ; se il bit4=1(ADIF) --> a fine conversione genero un interrupt portando ad 1 il ;bit 3 ; i bit 2:0 selezionano il fattore di prescaling Infine con l’istruzione sei viene abilitata la sensibilità della CPU agli interrupt, in modo tale che il programma venga interrotto in corrispondenza di un overflow del Timer Counter 0 per l’esecuzione della subroutine di risposta ad interrupt.
  • 11. 10 4.2 Subroutine di risposta ad interrupt Il decrementi dei contatori che serve per temporizzare le operazioni di verifica della tensione di batteria, di campionamento e scrittura o lettura, vengono svolte all’interno di una subroutine di risposta ad interrupt denominata TIM0_OVF. Figura 4. Flow-chart subroutine di risposta ad interrupt Preliminarmente si usa l’istruzione di push dei registri utilizzati nella routine principale del programma per garantire che il loro contenuto non venga modificato durante l’esecuzione di TIM0_OVF. Inoltre si opera il push del registro di stato, SREG, in modo tale che terminata la subroutine venga ripristinato lo stato precedente all’interrupt. L’istruzione di push consiste nel salvare il contenuto dei registri sulla cima dello stack per poi recuperarlo tramite l’istruzione di pop. Le altre operazioni compiute prevedono la reinizializzazione del registro TCNT0 al valore 255, il decremento delle variabili a 8 bit, count_500 e count_1000, e il decremento del valore a 16 bit corrispondente al tempo rimanente al prossimo controllo della tensione di batteria.
  • 12. 11 Il codice che realizza quanto detto è il seguente. TIM0_OVF: push mp push mp1 push mp2 push mp3 in mp,SREG push mp ; push dei registri utilizzati, per garantire che non vengano modificati dalla ;subroutine di risposta ad interrupt ldi mp,255 out TCNT0,mp ; reinizializza il contatore del timer counter dec count_500 ; decremento del contatore count_500 dec count_1000 ; decremento del contatore count_1000 ldi XL,low(ind_tempo_batt) ldi XH,high(ind_tempo_batt) ld mp3,X+ ld mp2,X sbiw mp3:mp2,1 ; decremento della variabile a 16 bit per la temporizzazione del controllo di ;tensione di batteria ldi XL,low(ind_tempo_batt) ldi XH,high(ind_tempo_batt) st X+,mp3 st X,mp2 ; scrittura nella SRAM del valore a 16 bit decrementato pop mp out SREG,mp pop mp3 pop mp2 pop mp1 pop mp ; ripristino dei registri utilizzati reti ; ritorna all'esecuzione del programma principale In particolare si nota come il decremento del valore a 16 bit venga effettuato tramite l’istruzione sbiw che consente di decrementare in modo diretto parole di 2 bytes. Il valore in questione viene caricato dalla SRAM tramite l’istruzione ld e successivamente, dopo essere stato decrementato, viene memorizzato nella SRAM mediante l’istruzione st. L’istruzione finale reti permette di ritornare all’esecuzione della routine principale del programma dal punto in cui era stata interrotta.
  • 13. 12 4.3 Funzione per la verifica della tensione di batteria La funzione di verifica della tensione di batteria ha lo scopo di valutare ogni 30 s la tensione erogata dalla batteria. Nel caso di tensione al di sotto della soglia stabilita di 2.4 V nominali, il sistema provvede alla generazione di un allarme visivo che consiste nell’accensione di un led giallo che resta acceso fino a quando la tensione non viene ripristinata ad un valore accettabile e il sistema riavviato. La scansione del tempo avviene tramite il decremento della variabile contenuta all’indirizzo ind_tempo_batt della SRAM, di valore 30000. Questo decremento, come detto precedentemente, viene effettuato ogni millisecondo, per cui per portare il valore 30000 a zero si impiegheranno circa 30 s. Il primo passo da compiere è proprio quello di verificare il valore di tempo corrente. Ciò viene fatto semplicemente leggendo il valore della variabile scritto nella SRAM e confrontandolo con zero. Il valore 30000 viene codificato con una variabile a 16 bit, pertanto viene confrontata con zero prima la parte bassa, bassa30,e poi la parte alta, alta30. Se la parte bassa è diversa da zero, vuol dire che certamente non sono trascorsi 30 s, quindi si termina la funzione di verifica della tensione di batteria e si prosegue con la parte successiva atta al controllo dell’indirizzo (controllo_indirizzo), altrimenti è necessario verificare che anche la parte alta sia uguale a zero. Se la parte alta non è uguale a zero vuol dire nuovamente che non sono trascorsi 30 s e si passa a controllo_indirizzo, altrimenti si procede con le altre operazioni di verifica della tensione di batteria. Allo scadere dei 30 s è necessario innanzitutto reinizializzare la variabile a 16 bit al valore 30000 in modo da poter contare nuovamente 30 s. Successivamente viene letta la tensione di batteria, per fare ciò bisogna effettuare una conversione Analogico-Digitale. A questo scopo viene impostato il pin di ingresso del convertitore interno al microcontrollore tramite il registro ADMUX. Per dare inizio alla conversione si utilizza il registro ADCSRA. Si effettua anche una verifica del termine della conversione, check_conv_batteria, tramite un loop interno che introduce un ritardo che però, essendo di circa 10 µs, può essere tollerato considerato che l’intervallo di campionamento è pari a 1 ms. Il valore analogico, una volta convertito, viene scritto nel registro ADCH e può essere utilizzato per il confronto con il valore di soglia. La tensione di riferimento interna del convertitore, in seguito ad una misurazione compiuta, si è rivelata essere differente da quella dichiarata dal costruttore (2.56 V) e pari a 2.71 V. Di conseguenza il valore di soglia tsh_batt corrispondente a 2.4 V nominali, è stato calcolato con una proporzione ed è risultato pari a 227. Se il valore letto nel registro ADCH è minore della soglia tsh_batt, viene acceso un led giallo sul pin 16, altrimenti si passa a controllo_indirizzo. In figura 6 si vede come in corrispondenza di una tensione pari a 2.39 V misurata in ingresso al pin 24 (ADC1) il led giallo si accenda dopo 30 secondi dall’avvio del dispositivo. Per poter effettuare tale verifica il dispositivo è stato avviato con una tensione di alimentazione pari a 4.8 V.
  • 14. 13 Figura 5. Flow-chart Verifica tensione di batteria.
  • 15. 14 Figura 6. Verifica tensione di batteria
  • 16. 15 Quanto visto precedentemente nel flow-chart, si traduce in linguaggio Assembly come riportato nel listato seguente. check_batteria: ldi XL,low(ind_tempo_batt) ldi XH,high(ind_tempo_batt) ; carica in X l'indirizzo in cui è salvato il valore 30000 che viene ;decrementato ld mp1,X+ ld mp,X ; legge dalla SRAM il valore a 16 bit (30000) e lo carica nei registri mp1 ;(parte alta) e mp (parte bassa) cpi mp,0 brne controllo_indirizzo ; se la parte bassa è zero controlla la parte alta del valore altrimenti ; salta al controllo indirizzo cpi mp1,0 brne controllo_indirizzo ; se anche la parte alta è zero reinizializza il valore a 30000 altrimenti ; salta al controllo indirizzo ldi XL,low(ind_tempo_batt) ldi XH,high(ind_tempo_batt) ldi mp,bassa30 ldi mp1,alta30 st X+,mp1 st X,mp ; riscrive in SRAM il valore iniziale (30000) della variabile da decrementare ; per il controllo della batteria ldi mp,0b11100001 out ADMUX,mp ; programma l'ADC in modo che lavori con tensione di riferimento interna a 2,56V ; (in realtà è 2,71V), giustifica a sinistra il risultato nel registro ADCH e ; seleziona ADC1 (pin 24) come ingresso del convertitore in mp,ADCSRA ldi mp1,0b01000000 or mp,mp1 out ADCSRA,mp ; inizia la conversione del valore di tensione di batteria check_conv_batteria: in mp,ADCSRA ldi mp1,0b01000000 and mp,mp1 brne check_conv_batteria ; aspetta che la conversione sia pronta testando ADSC in ADCSRA ; a conversione terminata ADSC torna a 0 in mp,ADCH ; legge ADCH che contiene il valore di tensione convertito su 8 bit
  • 17. 16 cpi mp,tsh_bat brsh controllo_indirizzo ; se il valore letto di tensione è maggiore o uguale alla soglia va avanti ;altrimenti accende il led in mp1,PORTB ;legge quello che ho precedentemente scritto sulla porta B ldi mp,0b00000100 or mp,mp1 ;cambia solo il valore sul pin 16 mantenendo invariati gli altri out PORTB,mp ;accende il led sul pin 16 In particolare si nota come per attivare la conversione viene portato a 1 il bit 6 del registro ADCSRA chiamato ADSC, bit che tornerà a zero a conversione terminata. Per fare ciò è stata eseguita un’operazione di or in modo da andare a modificare soltanto il bit di interesse. Al fine di verificare che la conversione sia terminata è stato effettuato un and in modo da accertarsi che il bit 6 sia effettivamente tornato a zero.
  • 18. 17 4.4 Controllo dell’indirizzo di memoria Per un funzionamento di tipo “buffer circolare” dello spazio riservato ai campioni nella memoria SRAM, è necessario che quando si è letto o scritto nell’ultima cella riservata si ricominci dalla prima rileggendo o sovrascrivendo i campioni già presenti. Figura 7. Flow-chart per il controllo dell'indirizzo corrente. Gli indirizzi della SRAM sono parole di 2 bytes, pertanto per effettuare il confronto si procede preliminarmente verificando che la parte bassa di Y sia uguale alla parte bassa di 0x288, indirizzo corrispondente alla cella successiva all’ultima riservata per contenere i campioni. Se i due valori non sono uguali evidentemente l’indirizzo corrente non è pari a 0x288 pertanto si passa alla porzione di codice successiva a partire dal label scrittura. Se invece questi valori sono uguali, si deve confrontare la parte alta dell’indirizzo corrente con quella alta di 0x288. Se le parti alte non sono equivalenti si passa a scrittura, altrimenti si assegna all’indirizzo corrente il valore dell’indirizzo della prima cella riservata (0x93) con la stessa procedura che tiene conto della parte alta e di quella bassa. Il codice relativo a quanto esplicitato dal precedente flow-chart, viene riportato di seguito. controllo_indirizzo: ldi mp,low(0x288) cp YL,mp brne scrittura ; se la parte bassa dell'indirizzo corrente è uguale alla parte bassa ;dell'indirizzo della prima cella dopo l'ultima riservata ;controlla anche la parte alta, altrimenti salta a scrittura
  • 19. 18 ldi mp,high(0x288) cp YH,mp brne scrittura ; se anche la parte alta dell'indirizzo corrente è uguale alla parte alta ;dell'indirizzo della prima cella dopo l'ultima riservata ;reinizializza l'indirizzo e prosegui con la scrittura, altrimenti salta a ;scrittura senza reinizializzare l'indirizzo ldi YH,high(indirizzo) ldi YL,low(indirizzo) ;reinizializza l'indirizzo della prima cella della SRAM per la scrittura/lettura
  • 20. 19 4.5 Funzione per il campionamento di un segnale analogico Le operazioni di scrittura e lettura sono tra loro esclusive e identificate dall’accensione di led verdi corrispondenti. La selezione di una delle due funzioni avviene mediante un interruttore sul pin 28 del microcontrollore. Il campionamento del segnale in ingresso e la scrittura dei campioni in memoria vengono effettuati alla frequenza di 500 Hz. Per ottenere tale frequenza si fa ricorso alla variabile count_500, che viene inizializzata al valore 2. Tale valore viene decrementato di 1 ogni millisecondo, in modo tale che quando count_500 vale zero sia consentito campionare. Il decremento sfrutta la subroutine di risposta ad interrupt TIM0_OVF. Figura 8. Flow-chart funzione campionamento e scrittura
  • 21. 20 Per poter effettuare il campionamento del segnale simil-ECG in ingresso sul pin 25, l’interruttore T1 deve far si che il valore logico in ingresso sul pin 28 sia basso, cioè zero. Altrimenti si passa all’operazione di lettura. Per avere certezza del valore in uscita sulla PORTA D durante la scrittura, si scrive zero nel registro PORTD. Nel caso in cui il dispostivo sia stato precedentemente in modalità di lettura, ci si assicura che il led (pin 17) indentificativo di tale modalità sia spento. Viene allora acceso il led sul pin 15 che identifica lo stato di scrittura. Dopodiché portando a 1 il bit ADC2 del registro ADMUX viene settato il pin 25 come ingresso del convertitore A/D. Per verificare se è veramente giunto il momento di campionare si controlla il valore di count_500, se questa variabile non è uguale a zero vuol dire che non sono passati 2 ms e si passa avanti al label lettura. Altrimenti si passa innanzitutto alla reinizializzazione di count_500 in modo da poter attendere che siano trascorsi 2 ms per campionare e scrivere nuovamente. Successivamente si avvia la conversione e dopo aver atteso che questa sia terminata, come nel caso precedentemente visto del check_conv_batteria, si legge dal registro ADCH il valore convertito e lo si scrive nella SRAM in corrispondenza dell’indirizzo contenuto nel registro Y. Dopodiché l’indirizzo della cella in cui è stato appena scritto il campione corrente viene incrementato. La parte di codice relativa a questa funzione è riportata di seguito. scrittura: in mp,PINC ldi mp1,0b00100000 and mp,mp1 cpi mp,0 brne lettura ; controlla il valore dell'interruttore di scrittura/lettura. Se il valore sul ;pin 28 è uguale a zero procedi con la scrittura altrimenti passa alla lettura ldi mp,0x00 out PORTD,mp ; dato che si sta effettuando la scrittura dei campioni, sulla PORTA D manda ;zero per avere contezza del valore sulla porta in mp,PORTB ldi mp1,0b11110111 and mp,mp1 ldi mp1,0b00000010 or mp,mp1 out PORTB,mp ; spegne il led di lettura sul pin 17 e accende il led di scrittura sul pin 15 ldi mp,0b11100010 out ADMUX,mp ; imposta ADC2 (pin 25) come ingresso al convertitore cpi count_500,0 brne lettura ; verifica del contatore che permette una frequenza di campionamento di 500 Hz, ; se il contatore è uguale a zero è giunto l'istante di campionare ldi count_500,2 ; reinizializza il contatore a 2
  • 22. 21 in mp,ADCSRA ldi mp1,0b01000000 or mp,mp1 out ADCSRA,mp ; inizia la conversione dei campioni del segnale check_conv_scrittura: in mp,ADCSRA ldi mp1,0b01000000 and mp,mp1 brne check_conv_scrittura ; aspetta che la conversione sia pronta testando ADSC in ADCSRA: a conversione ;terminata ADSC torna a 0 in mp1,ADCH ; legge ADCH che contiene il campione convertito su 8 bit st Y+,mp1 ; scrive il campione in SRAM all'indirizzo contenuto in Y e incrementa ;l'indirizzo contenuto in Y Il funzionamento in modalità di scrittura è rappresentato in figura 9, in cui è possibile vedere che il led verde corrispondente alla scrittura è acceso e qual è la posizione dell’interruttore T1 in questa modalità. Sullo schermo dell’oscilloscopio è rappresentato in alto il segnale proveniente dal generatore inviato sul canale 1, mentre in basso è visualizzato il canale 2 a cui è collegata l’uscita dell’amplificatore. Essendo in modalità di scrittura l’uscita è correttamente pari a zero. Figura 9. Funzionamento in modalità di scrittura Interruttore T1
  • 23. 22 4.6 Funzione per la lettura e la ricostruzione del segnale La lettura dei campioni di segnale memorizzati nella SRAM viene attivata con l’interruttore T1. Questa modalità è identificata dall’accensione di un led di colore verde corrispondente. I campioni possono essere letti alla stessa frequenza con cui vengono scritti, 500 Hz, oppure a frequenza doppia, 1000 Hz. La scelta della frequenza è operata dall’interruttore T2 sul pin 29. Per poter ricostruire la forma d’onda del segnale i campioni letti vengono trasferiti in parallelo sulla PORTA D del microcontrollore, settata come uscita. Questa è connessa ai pin di ingresso del convertitore Digitale-Analogico, DAC 0808. Questo convertitore viene alimentato, come detto in precedenza, con una tensione di alimentazione compresa tra +5 e -5 V. La tensione di riferimento che il DAC utilizza per effettuare la conversione è la medesima che usa il convertitore Analogico-Digitale. La configurazione circuitale standard del DAC 0808 prevede anche l’utilizzo di un amplificatore operazionale, in questo progetto un TL081. Per visualizzare la forma d’onda del segnale ricostruito è stato utilizzato un oscilloscopio digitale Agilent DSO3102A, prelevando il segnale fornito in uscita dall’amplificatore. Il procedimento per fare tutto ciò è esplicitato dal flow-chart riportato in figura 7. Come già detto si verifica immediatamente lo stato dell’interruttore sul pin 28. Se questo fa si che il pin sia a valore logico basso, vuol dire che si è in modalità di scrittura pertanto si passa al label fine e si può proseguire tornando alla funzione di verifica della tensione di batteria. Se invece il valore logico sul pin 28 è alto, si procede con le operazioni di preparazione alla lettura. Innanzitutto è necessario accendere il led sul pin 17 per identificare lo stato di lettura in corso, dopo essersi assicurati che il led identificativo della scrittura (pin 15) sia spento. Queste operazioni sono duali rispetto a quelle viste nel caso della funzione di scrittura. La scelta della frequenza con cui ogni campione viene letto ed inviato al DAC è affidata ad un interruttore T2 collegato sul pin 29. Se il valore logico sul pin è basso, la frequenza di lettura impostata sarà 500 Hz, altrimenti si verificherà nuovamente lo stato dell’interruttore e se questo sarà al valore logico alto la frequenza di lettura sarà di 1000 Hz. Nel primo caso, label freq_500, si dovrà per prima cosa verificare che effettivamente sia giunto il momento di leggere, cioè che count_500, sia uguale a zero ed eventualmente reimpostarne il valore a 2. Successivamente si legge il campione nella cella della SRAM il cui indirizzo è contenuto nel registro Y, e gli 8 bit corrispondenti vengono inviati sugli 8 pin della PORTA D. Dopodiché l’indirizzo corrente della cella appena letta, viene incrementato. Nel caso in cui il valore logico sul pin 29 sia alto, in corrispondenza di freq_1000, la variabile che viene considerata è count_1000, se questa è uguale a zero viene reinizializzata al valore 1. Anche in questo caso dopo la reinizializzazione si scrive sulla PORTA D il valore del campione letto e si incrementa l’indirizzo corrente. Al termine della lettura si giunge al label fine da cui si torna alla verifica della tensione di batteria.
  • 24. 23 Figura 10. Flow-chart funzione di lettura
  • 25. 24 Il codice che realizza quanto descritto dal flow-chart è il seguente. lettura: in mp,PINC ldi mp1,0b00100000 and mp,mp1 cpi mp,0 breq fine ; controlla il valore dell'interruttore di scrittura/lettura. Se il valore sul ;pin 28 è uguale a zero passa a fine altrimenti procedi in mp,PORTB ldi mp1,0b11111101 and mp,mp1 ldi mp1,0b00001000 or mp,mp1 out PORTB,mp ; spegne il led di scrittura sul pin 15 e accende il led di lettura sul pin 17 in mp,PINC ldi mp1,0b00010000 and mp,mp1 cpi mp,0 brne freq_1000 ; controlla il valore dell'interruttore delle frequenze. Se il valore sul pin 27 ;è 0 legge a 500 Hz altrimenti a 1000 Hz freq_500: cpi count_500,0 brne freq_1000 ; controlla il contatore che permette di leggere a 500 Hz. Se è uguale a zero ;vuol dire che la routine di risposta all'interrupt ha azzerato il valore ;iniziale di count_500, quindi può leggere il campione, altrimenti salta a ;freq_1000 ldi count_500,2 ; reinizializza il contatore a 2 ld mp,Y+ out PORTD,mp ; scrive il valore letto dalla SRAM sul registro della PORTA D freq_1000: in mp,PINC ldi mp1,0b00010000 and mp,mp1 cpi mp,0 breq fine ; controlla il valore dell'interruttore di scrittura/lettura. Se il valore sul ;pin 27 è uguale a zero passa a fine altrimenti procedi cpi count_1000,0 brne fine ; controlla il contatore che permette di leggere a 1000 Hz. Se è uguale a zero ;vuol dire che la subroutine di risposta all'interrupt ha azzerato il valore
  • 26. 25 ;iniziale di count_1000, quindi può leggere il campione, altrimenti salta a fine ldi count_1000,1 ; reinizializza il contatore a 1 ld mp,Y+ out PORTD,mp ; scrive il valore letto dalla SRAM sul registro della PORTA D fine: rjmp check_batteria ; ritorna alla verifica della tensione di batteria Il funzionamento in modalità di lettura è rappresentato nelle figure 11 e 12, in cui è possibile vedere che il led verde corrispondente alla lettura è acceso. In particolare, in figura 11 è osservabile il funzionamento con frequenza di lettura impostata a 500 Hz tramite l’interruttore T2 evidenziato in figura. Sullo schermo dell’oscilloscopio è rappresentato in alto il segnale proveniente dal generatore inviato sul canale 1, mentre in basso è visualizzato il canale 2 a cui è collegata l’uscita dell’amplificatore. Sul canale 2 viene rappresentato ciclicamente il segnale memorizzato nella SRAM di lunghezza pari ad 1 s. Figura 11. Visualizzazione del segnale a 500 Hz Interruttore T2
  • 27. 26 In figura 12 è osservabile il funzionamento con frequenza di lettura pari a 1000 Hz, ossia il doppio della frequenza di campionamento. Figura 12. Visualizzazione del segnale a 1000 Hz Interruttore T2
  • 28. 27 5 Appendice Listato completo del software ;******************************************************************************* ; ; File: elettrocardiografo_digitale.ASM ; Data: 26 giugno 2013 ; Version: 1.0 ; IDE: AVR-Studio 4.0 ; ; Autore: Gruppo 09-Lab. Progettazione Dispositivi Biomedici Programmabili ; Riferimenti: Politecnico di Torino - DET ; ;******************************************************************************* ; Programma che consente di simulare le funzioni di un elettrocardiografo ;digitale in grado di memorizzare il segnale ECG. ;******************************************************************************* .NOLIST ; La direttiva .NOLIST fa si che ciò che segue non venga ;incluso nel listato. .INCLUDE "atmega8.inc" ; La direttiva .INCLUDE inserisce il file "atmega8.inc" .LIST ; La direttiva .LIST svolge l’operazione duale a quella ;svolta da .NOLIST. ; Definizione dei registri utilizzati .DEF mp = R16 ; registro di lavoro (generico) .DEF mp1 = R17 ; registro di lavoro secondario (generico) .DEF mp2 = R24 ; primo registro per il decremento della variabile a 16 bit .DEF mp3 = R25 ; secondo registro per il decremento della variabile a 16 bit .DEF count_500 = R18 ; primo registro per la temporizzazione a 500 Hz .DEF count_1000 = R19 ; secondo registro per la temporizzazione a 1000 Hz .EQU tsh_bat = 227 ; fissa la soglia di tensione a 2,4V nominali .EQU alta30 = 0x75 ;valore alto di 30000 per temporizzare il check batteria .EQU bassa30 = 0x30 ; valore basso di 30000 ; Allocazione della memoria SRAM .DSEG ind_tempo_batt: .BYTE 2 ; riserva 2 bytes in cui salvo la variabile a 16 bit ; (30000) per il controllo della tensione di batteria .org 0x93 ; dopo le 96 celle dedicate ai registri, per mantenere 50 celle libere ; della SRAM, scrive i campioni a partire dalla 147esima cella indirizzo: .BYTE 500 ; riserva 500 bytes per scrivere i campioni del segnale ECG .CSEG
  • 29. 28 rjmp RESET ; Reset Handler reti ;rjmp EXT_INT0 ; IRQ0 Handler reti ;rjmp EXT_INT1 ; IRQ1 Handler reti ;rjmp TIM2_COMP ; Timer2 Compare Handler reti ;rjmp TIM2_OVF ; Timer2 Overflow Handler reti ;rjmp TIM1_CAPT ; Timer1 Capture Handler reti ;rjmp TIM1_CAPT ; Timer1 Capture Handler reti ;rjmp TIM1_COMPA ; Timer1 CompareA Handler reti ;rjmp TIM1_COMPB ; Timer1 CompareB Handler reti ;rjmp TIM1_OVF ; Timer1 Overflow Handler rjmp TIM0_OVF ; Timer0 Overflow Handler reti ;rjmp SPI_STC ; SPI Transfer Complete Handler reti ;rjmp USART_RXC ; USART RX Complete Handler reti ;rjmp USART_UDRE ; UDR Empty Handler reti ;rjmp USART_TXC ; USART TX Complete Handler reti ;rjmp ADC_conv ; ADC Conversion Complete Handler reti ;rjmp EE_RDY ; EEPROM Ready Handler reti ;rjmp ANA_COMP ; Analog Comparator Handler reti ;rjmp TWSI ; Two-wire Serial Interface Handler reti ;rjmp SPM_RDY ; Store Program Memory Ready Handler RESET: ldi mp,high(RAMEND) ;(0x04) out SPH,mp ldi mp,low(RAMEND) ;(0x5f) out SPL,mp ; inizializzazione dello stack pointer all'ultimo indirizzo della SRAM ldi mp,0b00000000 out DDRC,mp ; setta i pin della PORTA C tutti in ingresso ldi mp,0x00 out PORTC,mp ; scrive zero nel registro della PORTA C ldi mp,0b00001110 out DDRB,mp ; imposta in uscita i pin 15, 16 e 17 della PORTA B ; per i led di controllo scrittura, batteria, lettura ldi mp,0x00 out PORTB,mp ; scrive zero nel registro della PORTA B ldi mp,0b11111111 out DDRD,mp ; setta tutti i pin della PORTA D come uscite ldi mp,0x00 out PORTD,mp ; scrive zero nel registro della PORTA D ldi mp,0b00000101 out TCCR0,mp ; carica in TCCR0 i bit di mp, solo i primi 3 bit sono configurabili R/W, ; gli altri restano a 0. Il registro TCCR0 è usato per gestire la frequenza ; con cui generare un interrupt. Seleziona prescaler passo 1024 ldi mp,255 out TCNT0,mp ; imposta il valore iniziale del contatore a 255
  • 30. 29 ldi mp,0x01 out TIMSK,mp ; imposta il bit 0 del registro TIMSK ad 1 per abilitare la gestione degli ;interrupt in caso di overflow di TCNT0 ldi YL,low(indirizzo) ldi YH,high(indirizzo) ; scrive in Y l'indirizzo da incrementare per scrivere i campioni di segnale ;nella SRAM ldi XL,low(ind_tempo_batt) ldi XH,high(ind_tempo_batt) ; scrive in X l'indirizzo dove andare a salvare il valore 30000 da decrementare ldi mp,bassa30 ldi mp1,alta30 st X+,mp1 st X,mp ; scrive in SRAM il valore 30000 all'indirizzo contenuto in X ldi count_500,2 ldi count_1000,1 ; inizializza i contatori per temporizzare scrittura e lettura dei campioni inizializzaRAM: ldi mp,0 st Y+,mp ldi mp,low(0x288) cp YL,mp brne inizializzaRAM ldi mp,high(0x288) cp YH,mp brne inizializzaRAM ldi YL,low(indirizzo) ldi YH,high(indirizzo) ; scrive zero nelle 500 celle di memoria riservate a memorizzare ; i campioni del segnale in modo da essere certi del valore letto inizialmente ; all'avvio del programma ;------------------------------------------------------------------------------- ; ABILITAZIONE E PROGRAMMAZIONE ADC ;------------------------------------------------------------------------------- ldi mp,0b10000010 out ADCSRA,mp ; imposta il fattore di prescaling pari a 4. ; ADCSRA è un registro a 8 bit in particolare: ; se il bit7=1 --> abilita ADC ; se il bit6=1 --> start conversione ; se il bit5=1 (ADFR) --> seleziona il Free Running mode ; se il bit4=1(ADIF) --> a fine conversione genero un interrupt portando ad 1 il ;bit 3 ; i bit 2:0 selezionano il fattore di prescaling sei ; abilito la sensibilità della CPU agli interrupt
  • 31. 30 ;------------------------------------------------------------------------------- ; VERIFICA TENSIONE DI BATTERIA ; Questa funzione controlla la tensione di batteria ad intervalli di 30 secondi ;generando un allarme visivo (accensione led su pin 16) ;------------------------------------------------------------------------------- check_batteria: ldi XL,low(ind_tempo_batt) ldi XH,high(ind_tempo_batt) ; carica in X l'indirizzo in cui è salvato il valore 30000 che viene ;decrementato ld mp1,X+ ld mp,X ; legge dalla SRAM il valore a 16 bit (30000) e lo carica nei registri mp1 ;(parte alta) e mp (parte bassa) cpi mp,0 brne controllo_indirizzo ; se la parte bassa è zero controlla la parte alta del valore altrimenti ; salta al controllo indirizzo cpi mp1,0 brne controllo_indirizzo ; se anche la parte alta è zero reinizializza il valore a 30000 altrimenti ; salta al controllo indirizzo ldi XL,low(ind_tempo_batt) ldi XH,high(ind_tempo_batt) ldi mp,bassa30 ldi mp1,alta30 st X+,mp1 st X,mp ; riscrive in SRAM il valore iniziale (30000) della variabile da decrementare ; per il controllo della batteria ldi mp,0b11100001 out ADMUX,mp ; programma l'ADC in modo che lavori con tensione di riferimento interna a 2,56V ; (in realtà è 2,71V), giustifica a sinistra il risultato nel registro ADCH e ; seleziona ADC1 (pin 24) come ingresso del convertitore in mp,ADCSRA ldi mp1,0b01000000 or mp,mp1 out ADCSRA,mp ; inizia la conversione del valore di tensione di batteria check_conv_batteria: in mp,ADCSRA ldi mp1,0b01000000 and mp,mp1 brne check_conv_batteria ; aspetta che la conversione sia pronta testando ADSC in ADCSRA ; a conversione terminata ADSC torna a 0 in mp,ADCH ; legge ADCH che contiene il valore di tensione convertito su 8 bit
  • 32. 31 cpi mp,tsh_bat brsh controllo_indirizzo ; se il valore letto di tensione è maggiore o uguale alla soglia va avanti ;altrimenti accende il led in mp1,PORTB ;legge quello che ho precedentemente scritto sulla porta B ldi mp,0b00000100 or mp,mp1 ;cambia solo il valore sul pin 16 mantenendo invariati gli altri out PORTB,mp ;accende il led sul pin 16 ;------------------------------------------------------------------------------- ; CONTROLLO SULL'INDIRIZZO ATTUALE DELLA SRAM ; Questa funzione controlla che l'indirizzo che punta alla cella di memoria in ;cui memorizzare il campione sia l'ultimo, in tal caso torna a memorizzare a ;partire dalla prima cella del blocco di memoria (500 bytes) riservato ai ;campioni, altrimenti continua a memorizzare nella cella successiva ;------------------------------------------------------------------------------- controllo_indirizzo: ldi mp,low(0x288) cp YL,mp brne scrittura ; se la parte bassa dell'indirizzo corrente è uguale alla parte bassa ;dell'indirizzo della prima cella dopo l'ultima riservata ;controlla anche la parte alta, altrimenti salta a scrittura ldi mp,high(0x288) cp YH,mp brne scrittura ; se anche la parte alta dell'indirizzo corrente è uguale alla parte alta ;dell'indirizzo della prima cella dopo l'ultima riservata ;reinizializza l'indirizzo e prosegui con la scrittura. altrimenti salta a ;scrittura senza reinizializzare l'indirizzo ldi YH,high(indirizzo) ldi YL,low(indirizzo) ;reinizializza l'indirizzo della prima cella della SRAM per la scrittura/lettura ;------------------------------------------------------------------------------- ; CAMPIONAMENTO E SCRITTURA ; Questa funzione campiona il segnale in ingresso, lo converte in digitale e lo ;scrive nella SRAM ;------------------------------------------------------------------------------- scrittura: in mp,PINC ldi mp1,0b00100000 and mp,mp1 cpi mp,0 brne lettura ; controlla il valore dell'interruttore di scrittura/lettura. Se il valore sul ;pin 28 è uguale a zero procedi con la scrittura altrimenti passa alla lettura ldi mp,0x00 out PORTD,mp ; dato che si sta effettuando la scrittura dei campioni, sulla PORTA D manda ;zero per avere contezza del valore sulla porta
  • 33. 32 in mp,PORTB ldi mp1,0b11110111 and mp,mp1 ldi mp1,0b00000010 or mp,mp1 out PORTB,mp ; spegne il led di lettura sul pin 17 e accende il led di scrittura sul pin 15 ldi mp,0b11100010 out ADMUX,mp ; imposta ADC2 (pin 25) come ingresso al convertitore cpi count_500,0 brne lettura ; verifica del contatore che permette una frequenza di campionamento di 500 Hz, ; se il contatore è uguale a zero è giunto l'istante di campionare ldi count_500,2 ; reinizializza il contatore a 2 in mp,ADCSRA ldi mp1,0b01000000 or mp,mp1 out ADCSRA,mp ; inizia la conversione dei campioni del segnale check_conv_scrittura: in mp,ADCSRA ldi mp1,0b01000000 and mp,mp1 brne check_conv_scrittura ; aspetta che la conversione sia pronta testando ADSC in ADCSRA: a conversione ;terminata ADSC torna a 0 in mp1,ADCH ; legge ADCH che contiene il campione convertito su 8 bit st Y+,mp1 ; scrive il campione in SRAM all'indirizzo contenuto in Y e incrementa ;l'indirizzo contenuto in Y ;------------------------------------------------------------------------------- ; LETTURA E VISUALIZZAZIONE CAMPIONI ; Questa funzione legge i campioni di segnale memorizzati nella SRAM e li invia ;in uscita tramite la PORTA D, con due diverse frequenze, 500 e 1000 Hz. ;------------------------------------------------------------------------------- lettura: in mp,PINC ldi mp1,0b00100000 and mp,mp1 cpi mp,0 breq fine ; controlla il valore dell'interruttore di scrittura/lettura. Se il valore sul ;pin 28 è uguale a zero passa a fine altrimenti procedi in mp,PORTB ldi mp1,0b11111101 and mp,mp1 ldi mp1,0b00001000
  • 34. 33 or mp,mp1 out PORTB,mp ; spegne il led di scrittura sul pin 15 e accende il led di lettura sul pin 17 in mp,PINC ldi mp1,0b00010000 and mp,mp1 cpi mp,0 brne freq_1000 ; controlla il valore dell'interruttore delle frequenze. Se il valore sul pin 27 ;è 0 legge a 500 Hz altrimenti a 1000 Hz freq_500: cpi count_500,0 brne freq_1000 ; controlla il contatore che permette di leggere a 500 Hz. Se è uguale a zero ;vuol dire che la routine di risposta all'interrupt ha azzerato il valore ;iniziale di count_500, quindi può leggere il campione, altrimenti salta a ;freq_1000 ldi count_500,2 ; reinizializza il contatore a 2 ld mp,Y+ out PORTD,mp ; scrive il valore letto dalla SRAM sul registro della PORTA D freq_1000: in mp,PINC ldi mp1,0b00010000 and mp,mp1 cpi mp,0 breq fine ; controlla il valore dell'interruttore di scrittura/lettura. Se il valore sul ;pin 27 è uguale a zero passa a fine altrimenti procedi cpi count_1000,0 brne fine ; controlla il contatore che permette di leggere a 1000 Hz. Se è uguale a zero ;vuol dire che la subroutine di risposta all'interrupt ha azzerato il valore ;iniziale di count_1000, quindi può leggere il campione, altrimenti salta a fine ldi count_1000,1 ; reinizializza il contatore a 1 ld mp,Y+ out PORTD,mp ; scrive il valore letto dalla SRAM sul registro della PORTA D fine: rjmp check_batteria ; ritorna alla verifica della tensione di batteria
  • 35. 34 ;------------------------------------------------------------------------------- ; SUBROUTINE DI RISPOSTA AD INTERRUPT ;------------------------------------------------------------------------------- TIM0_OVF: push mp push mp1 push mp2 push mp3 in mp,SREG push mp ; push dei registri utilizzati, per garantire che non vengano modificati dalla ;subroutine di risposta ad interrupt ldi mp,255 out TCNT0,mp ; reinizializza il contatore del timer counter dec count_500 ; decremento del contatore count_500 dec count_1000 ; decremento del contatore count_1000 ldi XL,low(ind_tempo_batt) ldi XH,high(ind_tempo_batt) ld mp3,X+ ld mp2,X sbiw mp3:mp2,1 ; decremento della variabile a 16 bit per la temporizzazione del controllo di ;tensione di batteria ldi XL,low(ind_tempo_batt) ldi XH,high(ind_tempo_batt) st X+,mp3 st X,mp2 ; scrittura nella SRAM del valore a 16 bit decrementato pop mp out SREG,mp pop mp3 pop mp2 pop mp1 pop mp ; ripristino dei registri utilizzati reti ; ritorna all'esecuzione del programma principale