;************************************************************************************* ; Programar una rutina que calcule el promedio de un vector de 16 elementos ; almacenado en memoria RAM a partir de la etiqueta VECTOR. ; Se ejemplifica la definicion de interrupciones y el esqueleto para inicializar ; puertos y timers. ; ; ; Autor: Gabriel Gavinowich ; Padr?n: ; Fecha: 12/09/2016 ; ;************************************************************************************* .include "m88def.inc" ;Incluye los nombres de los registros específicos del microcontrolador Atmega88 y sus direcciones .equ TAMANIO_VECTOR = 16 ;Indico que las sentencias a continuacion van ubicadas en espacio de datos. .dseg .org 0x100 vector: .byte TAMANIO_VECTOR ;Indico que las sentencias a continuacion van ubicadas en espacio de codigo. .cseg .org 0x0000 rjmp inicio; ;Los valores de las interrupciones son dependientes del micro utilizado, ver la hoja de datos .org 0x0002 rjmp handler_external_int1 .org 0x000D rjmp handler_timer1_ovf .org 0x0010 rjmp handler_timer0_ovf ;Direccion siguiente a la ultima interrupcion. Es dependiente del micro utilizado por eso se utiliza esta macro .org INT_VECTORS_SIZE inicio: ; Se inicializa el Stack Pointer al final de la RAM utilizando la definicion global ; RAMEND init_micro: ldi r16,HIGH(RAMEND) out sph,r16 ldi r16,LOW(RAMEND) out spl,r16 ;Funcionas para inicializar los perifericos antes del loop principal del programa rcall configure_ports rcall configure_timers while_1: rcall TEST_cargar_vector ;funcion de testeo para cargar el vector rcall calcular_promedio ;Verifico el resultado, este codigo es de testeo ldi r19,TEST_RESULTADO sec cpse r18,r19 clc rjmp while_1 ;************************************************************************************* ; Se configuran los puertos del microcontrolador como entrada/salida/otra funcion ; ;Entrada: ;Salida: ;Registros utilizados: ;************************************************************************************* configure_ports: ret ;************************************************************************************* ; Se configuran los timers del microcontrolador ; ;Entrada: ;Salida: ;Registros utilizados: ;************************************************************************************* configure_timers: ret ;************************************************************************************* ; Se calcula el promedio de los valores contenidos en la variable en RAM vector que ; contiene TAMANIO_VECTOR elementos. Los valores son enteros sin signo de a 0 a 255 ; Primero se suman los 16 valores y luego se hace la division por 16. ; ; La suma se hace en doble precision para no perder ningun decimal. ; La division se hace corriendo todo para la derecha 4 veces, los digitos que se ; caen son descartados truncando el resultado. ; ; NOTA: El promediado es solo valido si TAMANIO_VECTOR es potencia de 2 y menor a 256 ; ; ;Entrada: la variable VECTOR en RAM de TAMANIO_VECTOR elementos ;Salida: R18 ;Registros utilizados: R16, R17, R19 <-- Guardados en stack, se restituye el valor ; z, <-- Se pierde ;************************************************************************************* calcular_promedio: ;Salvar los registros a utilzar en el stack push R16 push R17 push R19 ;Inicializar los contadores en 0 clr r18 ;Parte baja de la suma clr r19 ;Parte alta de la suma ldi r16,TAMANIO_VECTOR ;Contador de muestras ;Cargar el puntero z con la direccion de vector ldi zl,LOW(vector) ldi zh,HIGH(vector) sigo_promediando: ld r17,z+ ;Cargo el elemento del vector e incremento el puntero add r18,r17 ;Sumo la parte baja clr r17 ;Importante: No modifica el Carry adc r19,r17 ;Sumo 0 + C a la parte alta dec r16 brne sigo_promediando ;La division se hace corriendo a la derecha el resultado. ldi r16,log2(TAMANIO_VECTOR) ;Contador de muestras sigo_dividiendo: lsr r19 ror r18 dec r16 brne sigo_dividiendo ;Recuperar los registros del stack, siempre en sentido inverso pop r19 pop r17 pop r16 ret ;************************************************************************************* ; Funcion de prueba que carga un vector en ROM en el vector en RAM a promediar ; ;Entrada: la variable VECTOR en RAM de TAMANIO_VECTOR elementos ; La tabla en ROM vector_rom ;Salida: Ninguna ;Registros utilizados: R16, R17 <-- Guardados en stack ; x,z <-- Se pierden ;************************************************************************************* TEST_cargar_vector: push r16 push r17 ldi xl,LOW(vector) ldi xh,HIGH(vector) ldi zl,LOW(vector_rom<<1) ldi zh,HIGH(vector_rom<<1) ldi r17,16 loop_cargar_vector: lpm r16,z+ st x+,r16 dec r17 brne loop_cargar_vector pop r17 pop r16 ret vector_rom: .db 190,140,1,0,255,10,45,23,53,255,1,255,0,145,0,20 ;El resultado del promedio para testar si la funcion es correcta .equ TEST_RESULTADO = (190+140+1+0+255+10+45+23+53+255+1+255+0+145+0+20)/16 ;************************************************************************************* ; Handler que se llama cuando ocurre la interrupcion externa 1 ; ; ;Entrada: Ninguna ;Salida: Ninguna ;Registros utilizados: Ninguna ;************************************************************************************* handler_external_int1: reti ;Siempre retornar con RETI!!!! ;************************************************************************************* ; Handler que se llama cuando el timer 1 sufre un overflow ; ; ;Entrada: Ninguna ;Salida: Ninguna ;Registros utilizados: Ninguna ;************************************************************************************* handler_timer1_ovf: reti ;Siempre retornar con RETI!!!! ;************************************************************************************* ; Handler que se llama cuando el timer 0 sufre un overflow ; ; ;Entrada: Ninguna ;Salida: Ninguna ;Registros utilizados: Ninguna ;************************************************************************************* handler_timer0_ovf: reti ;Siempre retornar con RETI!!!!