jueves, 29 de octubre de 2015

Conversión AD, análoga digital: assembler

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

Barrido de teclado: assembler ejemplo

Circuito en proteus




;Programa principal

.include "m164pdef.inc"

 .def tempo=r16

 .dseg

 tecla:     .byte 1
 binariol:  .byte 1
 binarioh:  .byte 1
 dig:       .byte 4
 segmentos: .byte 4



 .cseg
 .org 0x00

 clr tempo
out ddrb,tempo
out porta,tempo
com tempo
out portb,tempo
out ddra,tempo

ldi tempo,0b00001111
out ddrc,tempo ;los 4 bits menos significativos untilizo para control de encendido de display
out ddrd,tempo ;para el teclado 4 bits como salida y 4 como entrada
com tempo
out portc,tempo
ldi tempo,255
out portd,tempo

in tempo,mcucr
andi tempo,0b11101111
out mcucr,tempo

ldi tempo,high(ramend)
out sph,tempo
ldi tempo,low(ramend)
out spl,tempo

clr tempo
sts binariol,tempo
sts binarioh,tempo



 lazo:
;valor anterior
lds r16,tecla
call teclado
;valor actual de tecla
lds r20,tecla
;comparo para ver si el valor de tecla cambio (si no cambia es xq continua presionada)
cp r16,r20
breq continuar
cpi r20,0
breq continuar
;sumo lo que tenia acumulado con el valor de tecla
ldi tempo,0
lds r17,binariol
lds r18,binarioh
mov r17,r20
mov r18,tempo

sts binariol,r17
sts     binarioh,r18

continuar:
call bin_bcd
call bcd_7seg
call barrido

 rjmp lazo

   .include "teclado.asm"
  .include "binarioabcd.asm"
  .include "bcda7seg.asm"
   .include "barrido.asm"

;Subrutinas

; barrido

 barrido:
push r16
push r17
push r18
push    xl
push xh
ldi r17,4
ldi xh,high(segmentos)
ldi xl,low(segmentos)
ldi r18,0b11110111
barrido0:
    ser r16
out portc,r16
ld r16,x+
;no es necesario encender el punto borro estras líneas
;cpi r17,2
;breq punto
;ori r16,0b10000000
;punto:
out porta,r16
out portc,r18
call retardo_barrido
sec
ror r18
dec r17
brne barrido0

ser r16
out portc,r16

pop xh
pop xl
pop r18
pop r17
pop r16
 ret

retardo_barrido:
 push r16
 ldi r16,255
 retardo0:
 nop

 dec r16
 brne retardo0

 pop r16
 ret

 ;bcd_7seg

 bcd_7seg:
push r16
push r17
push xl
push xh
push yl
push yh
push zl
push zh
ldi xh,high(segmentos)
ldi xl,low(segmentos)
ldi yh,high(dig)
ldi yl,low(dig)
ldi r17,4

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
pop zh
pop zl
pop yh
pop yl
pop xh
pop xl
pop r17
pop r16
 ret

 tabla_seg:
.db 0b00111111,0b00000110 ;0,1
            .db 0b01011011,0b01001111 ;2,3
            .db 0b01100110,0b01101101 ;4,5
            .db 0b01111101,0b00000111 ;6,7
            .db 0b01111111,0b01101111 ;8,9
.db 0b00001000,0b00000000;A,B
.db 0b00110001,0b00000001;C,D
.db 0b00110000,0b00111000;E,F

;bin_bcd:

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,3
ldi xl,low(dig)
ldi xh,high(dig)
ldi zl,low(constantes<<1)
ldi zh,high(constantes<<1)
bin_bcd0:
lpm r19,z+
lpm r20,z+
bin_bcd1:
sub r16,r19
sbc r17,r20
brcs bin_bcd2
inc r21
rjmp bin_bcd1
bin_bcd2:
add r16,r19
adc r17,r20
st x+,r21
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  1000, 100, 10

;teclado:

teclado:
 push r16
 push r17

 
 ldi r17,0
 ldi r16,0b11111110
 out portd,r16
 sbis pind,4
 ldi r17,7
 sbis pind,5
 ldi r17,8
 sbis pind,6
 ldi r17,9
 sbis pind,7
 ldi r17,10

 ldi r16,0b11111101
 out portd,r16
 sbis pind,4
 ldi r17,4
 sbis pind,5
 ldi r17,5
 sbis pind,6
 ldi r17,6
 sbis pind,7
 ldi r17,11

 ldi r16,0b1111011
 out portd,r16
 sbis pind,4
 ldi r17,1
 sbis pind,5
 ldi r17,2
 sbis pind,6
 ldi r17,3
 sbis pind,7
 ldi r17,12

 ldi r16,0b11110111
 out portd,r16
 sbis pind,4
 ldi r17,13
 sbis pind,5
 ldi r17,14
 sbis pind,6
 ldi r17,15
 sbis pind,7
 ldi r17,16

 sts tecla,r17


 pop r17
 pop r16

 ret