Con un
microcontrolador Atmega164P, diseñar un sistema que funcione como voltímetro o termómetro.
Se dispone de un pulsador que permite cambiar el modo de funcionamiento del
sistema de voltímetro a termómetro o viceversa y un segundo pulsador para
cambiar la unidad de medida.
Voltímetro:
Si el sistema
funciona como voltímetro permite medir un voltaje entre 0V y un Vmax, el valor
de voltaje medido se mostrara en 4 displays 7 segmentos en base 10. Con el
pulsador de unidad de medida, se podrá seleccionar entre mV ó V, como funciona
un multímetro real, un led indicara las unidades de la medida.
Como referencia utilizar Avcc, recordar que la
entrada análoga al microcontrolador puede ser máximo 5 V.
Termómetro:
Si el sistema
funciona como termómetro, se debe utilizar el sensor LM35 para medir la
temperatura ambiente y el valor medido se muestra en los displays, con el
pulsador de unidad de medida se puede escoger la temperatura en ºC ó ºF.
Utilizar la referencia interna de 2.56 V.
Ejemplo:
Temperatura:
22 ºC
(Temperatura ambiente)
En ambos casos
utilizar 10 bits de resolución y si se requiere realizar alguna operación
aritmética se debe realizar empleando los 10 bits.
Traer
el circuito armado para cumplir la tarea solicitada, los estudiantes deben
traer los elementos necesarios para el funcionamiento del sistema.
Codigo:
.include "m164pdef.inc"
.def tempo=r16
.def vol_ter=r24
; para el modo voltímetro o termómetro
.def
acumuladorl=r22
.def
acumuladorh=r23
.def
contador=r21
.dseg
uno: .byte 1
dos: .byte 1
tres: .byte 1
binariol: .byte 1
binarioh: .byte 1
digitos: .byte 4
segmentos:
.byte 1
segmentos1:
.byte 1
segmentos2:
.byte 1
segmentos3:
.byte 1
.cseg
.org 0x00
rjmp inicio
.org 0x02 ; interrupción 1
rjmp modo ;cambia de
voltimetro a termo
.org 0x04 ; interrupción 2
rjmp escala ; camvia de mili a voltios
inicio: ;configuro puertos
clr tempo
out
portb,tempo
out ddra,tempo
com tempo
out ddrb,tempo
ldi
tempo,0b11111100
out
porta,tempo
ldi tempo,
0b00001111
out ddrc,tempo
com tempo
out portc,tempo
ldi tempo,0b11000000
out ddrd,tempo
com tempo
out portd,tempo
in tempo,mcucr
andi tempo,0b11101111
out mcucr,tempo
;Stack
ldi tempo, high(ramend)
out sph,tempo
ldi tempo,low(ramend)
out spl,tempo
;INTERRUPCIONES
ldi
tempo,0b00001010 //activacion por flanco de bajada
sts
eicra,tempo
ldi
tempo,0b00000011 //activacion de int0 E INT1
out
eimsk,tempo
sei
;configuraCION
adc
ldi
tempo,0b01000000
sts
admux,tempo ;el adc tiene refernecia a avcc, 10 bits
justificacion a derecha y elijo canal 0
ldi
tempo,0b00000011
sts
didr0,tempo ; se indica que pa0 y pa1 tendran entrada
analogica
ldi tempo,
0b01111111
out
portd,tempo ;se enciende el led indicador para
multimetro
lazo:
ldi
acumuladorl,0 //limpio variables
ldi
acumuladorh,0
ldi
contador,2 ;se realizara dos mediciones antes de
sacar el dato
cpi
vol_ter,1 //analizo
para escoger modo voltimetro o termometro
breq temp
call
multimetro //
LLLAMADA DE SUBRUTINAS
call bin_bcd
call bcd_7seg
call barrido
rjmp lazo
temp:
call termometer
call bin_bcd
call bcd_7seg
push r16
lds
r16,segmentos1 //AQUI
ESTA EN DISPLAY SEG--SEG1--SEG2--SEG3
sts
segmentos,r16
lds
r16,segmentos2
sts
segmentos1,r16
ldi
r16,0b01100011 //ACTIVO LOS GRADOS DE CELSIUS
sts
segmentos2,r16
ldi
r16,0b00111001 //ACTIVO
LA C DE CELSIUS
sts
segmentos3,r16
pop r16
call barrido
rjmp lazo
//
INTERRUPCION 0
modo:
push r16
in
r16,sreg //SALVO
VARIABLE Y ESTADO DEL SREG
push r16
;
interrupcion
cpi vol_ter,1
ldi tempo,
0b10111111
out
portd,tempo
breq encerar
ldi vol_ter,1
ldi
tempo,0b11000001
sts
admux,tempo ;el adc tiene refereNcia interna 2.56v,
10 bits justificacion a derecha y elijo canal 1
rjmp salir
encerar:
ldi vol_ter,0
ldi tempo, 0b01111111
out portd,tempo
;se
configura el adc PARA QUE FUNCIONE COMO VOLTIMETRO
ldi
tempo,0b01000000
sts
admux,tempo ;el adc tiene refernecia a avcc, 10 bits
justificacion a derecha y elijo canal 0
salir:
;termina
la interrupcion ES DECIR TERMINO DE SER TERMOMETRO
pop r16
out
sreg,r16 //REGRESO
VARIABLES Y SREG SALVADAS
pop r16
reti
multimetro:
conversion:
ldi
tempo,0b11000110; activo conversion;comienzo
conversion;trigger manual;no int de ADC; se inicia la conversion con prescalado
de 64
sts
adcsra,tempo
esperar:
lds
tempo,adcsra
sbrc tempo,6 ;mientras el bit 6 sea 1 sigue esperando haciendo
conversion
rjmp esperar
dec contador
lds tempo,
adcl ; siempre se lee primero el valor bajo
add
acumuladorl,tempo //mando a acumuladorl el valor de
adclow
lds tempo,
adch
andi
tempo,0b00000011 //saco solo los 2 primeros bits de
adchigh
adc
acumuladorh,tempo //mando a acumuladorh el valor de
adchigh
cpi
contador,0
brne
conversion //tomo dos veces los datos x seguridad
;cambiar
aqui para que salga el valor deseado
;ya
que no se divide,se multiplicara por 0.5*0.0049=24
ldi r18,70
mul
acumuladorl,r18
mov r19,r0
mov r20,r1
mul
acumuladorh,r18
mov r25,r1 ; carry el numero es mayor a 16 bits
add r20,r0
ldi r18,0
adc r25,r18
sts uno,r19
sts dos,r20
sts tres,r25
;cpi
r25,0
;breq
no_hubo
escala:
push r16
push r17
ldi
r16,0b00000001
eor r17,r16
sbrs r17,0
rjmp no_hubo
si_hubo:
;si
el numero es mayor a 16 bits
mov
acumuladorl,r20
mov
acumuladorh,r25
ldi r18,28
mul
acumuladorl,r18
mov r19,r0
mov r20,r1
mul
acumuladorh,r18
add r20,r0
subi r19,0xa0
ldi r18,0x02
sbc r20,r18
sts binarioh,r20
sts binariol,r19
rjmp sal
no_hubo:
;
si el numero es menor a 16 bits
sts binariol,r19
sts binarioh,r20
sal:
ret
termometer:
ldi
contador,5
conversion_t:
ldi
tempo,0b11000110; se inicia la conversion con
prescalado de 64
sts
adcsra,tempo
esperar_t:
lds
tempo,adcsra
sbrc tempo,6 ;mientras el bit 6 sea 1 sigue esperando
rjmp esperar_t
dec contador
lds tempo,
adcl ; siempre se lee primero el valor bajo
add
acumuladorl,tempo
lds tempo,
adch
andi
tempo,0b00000011
adc
acumuladorh,tempo
cpi
contador,0
brne
conversion_t
;ya
que no se divide, se multiplicara por 0.5*0.0049=24
ldi r18,5
mul
acumuladorl,r18
mov r19,r0
mov r20,r1
mul
acumuladorh,r18
mov r25,r1 ; carry el numero es mayor a 16 bits
add r20,r0
ldi r18,0
adc r25,r18
sts uno,r19
sts dos,r20
sts tres,r25
sts binariol,r19
sts binarioh,r20
sal_t:
ret
bin_bcd:
push r16
push r17
push r18
push r19
push r20
push r21
push xl
push xh
push zl
push zh
lds r16,binariol
lds r17,binarioh
ldi r18,5
ldi xh,high(digitos)
ldi xl,low(digitos)
ldi zh,high(constantes<<1)
ldi zl,low(constantes<<1)
bin_bcd0:
lpm r19,z+
lpm r20,z+
bin_bcd1:
sub r16,r19 //restamos 10000
sbc r17,r20
brcs bin_bcd2; si c=1 salta
inc r21 //incremento los
miles
rjmp bin_bcd1
bin_bcd2:
add r16,r19 //restauro
adc r17,r20
st
x+,r21 //cargo
a digitos
clr r21
dec r18
brne bin_bcd0
st x,r16
pop zh
pop zl
pop xh
pop xl
pop r21
pop r20
pop r19
pop r18
pop r17
pop r16
ret
constantes:
.dw 10000, 1000,100,10
bcd_7seg:
push r16
push r17
push xl
push xh
push zl
push zh
ldi xh,high(segmentos)
ldi xl,low(segmentos)
ldi
yh,high(digitos)
ldi
yl,low(digitos)
ldi r17,4 ;contador
bcd_7seg0:
ldi zh,high(tabla_seg<<1)
ldi zl,low(tabla_seg<<1)
ld r16,y+
add zl,r16
clr r16
adc zh,r16
lpm r16,z
st x+,r16
dec r17
brne bcd_7seg0; si no es igual a cero regresa
pop zh
pop zl
pop xh
pop xl
pop r17
pop r16
ret
tabla_seg:
.db 0b00111111 , 0b00000110
.db 0b01011011 , 0b01001111
.db 0b01100110 , 0b01101101
.db 0b01111101 , 0b00000111
.db 0b01111111 , 0b01100111
barrido:
push r16
push r17
push r18
push xl
push xh
ldi r17,4 ;contador
ldi
xh,high(segmentos)
ldi
xl,low(segmentos)
ldi
r18,0b11110111
barrido0:
ldi r16,255
out portc,r16
;apaga todos los displays
ld r16,x+
cpi modo,0
breq multi
cpi r17,2
rjmp ya
multi:
cpi r25,0
breq bla
cpi r17,3
rjmp ya
bla:
cpi r17,4
ya:
breq punto
ori
r16,0b10000000
rjmp punto
punto:
out portb,r16
out portc,r18
call
retardo_barrido
sec ;1 en el carry
ror r18 ;0b11111011
dec r17
brne barrido0
ser r16
out portc,r16
pop xh
pop xl
pop r18
pop r17
pop r16
ret
retardo_barrido:
ldi r16,255
salto0:
nop
dec r16
brne salto0
ret