Sacar promedio de muestras en ASM

Hola, quiero sacar el promedio de varias muestras que salen del convertidor analogico digital, pero en codigo ASM.
Hice una rutina, pero acarrea mucho error:
Código:
ADCT    MOVLW    .10
        MOVWF    DATCL
        CALL    ADC
        CALL    MODT            ;ACONDICIONA EL DATOL
CLPRM    MOVFF    DATOL,DATOP        
        CALL    ADC
        CALL    MODT            ;ACONDICIONA EL DATOL
        CALL    PROM
        DECFSZ    DATCL,1
        GOTO    CLPRM
        RETURN

PROM    MOVF    DATOL,W
        CLRF    DATOL
        ADDWF    DATOP,F
PROM1    MOVLW    .2
        SUBWF    DATOP,F
        BTFSS    STATUS,C
        RETURN
        INCF    DATOL,F
        GOTO    PROM1

Ojala me puedan ayudar, gracias
 
Y en que momento estas haciendo la division entre el numero de muestras?.
como funciona eso? como lo vas a aplicar?
 
Lo estoy haciendo con restas sucesivas, cada vez que hago una resta y el resultado sigue siendo positivo, le incremento en 1 a DATOL. Lo que quiero hacer es guardar 10 datos de ADRESL, sumarlos y promediarlos, despues enviar ese dato por la usart
 
El metodo para hacer lo que quieres es sumar y luego dividir. Yo trabajo solo la familia dsPIC, no el pic. Entonces no se si el pic tiene la instruccion de division, pero si la tiene, vas a tener que dividir.
Y si no puedes dividir, entonces si tendras que hacer restas sucecivas, pero no de la forma que lo estas haciendo, si no que una vez que tengas 10 numeros sumados, debes de contar las veces que le restas 10 a la suma de las muestras.
 
El pic es 18f4550, lo que yo tenia duda, es si puedo sumar los 10 numeros, por que creo que los registros son de 8 bits, no se si este bien, corrigeme si estoy mal.
Entonces por eso estaba sumando solo 2 numeros
 
Crea una rutina que sume 16 bits, es sencillisimo.

Tienes dos registros, que suman 16 bits.
Tienes el dato nuevo, y lo sumas al registro menos significativo.
Seguido, haces una suma con cero al registro mas significativo con carry y listo.
Para la division, como te dije, con la suma, usando el carry, pero hay que contar las veces que se reste el numero 10.
 
... Lo que quiero hacer es guardar 10 datos de ADRESL, sumarlos y promediarlos, despues enviar ese dato por la usart
:unsure: Lo de usar 10 datos es una exigencia o un tamaño de muestra que se te ocurrió a vos?
Si da lo mismo que sea una cantidad parecida a 10, usá muestras de 8 (o 16) datos. Donde todo lo que tenés que hacer para dividir es desplazar los registros 3 (o 4) lugares.
 
haces la suma de tus muestras (8 muestas) a 16 bits para que no tengas desbordamientos, y despues haces 4 corrimientos a la derecha (a los 16 bits) y es lo mismo que dividir entre ocho.
Gran idea eduardo!!!
 
cuando haces la suma de dos registros, si la suma es mayor que lo que puede contar un registro (255) se genera la señal carry que se encuentra en el registro de control.
Bueno... con peras y manzanas.

estamos que un registro te cuenta de 0(00h) a 255(FFh) por ser de ocho bits.
entonces si sumas 200 y 100, tendras en teoria el resultado de 300, pero no es posible con un registro, entonces lo que se hace es lo siguiente, como en las sumas de primaria.

el primer registro tienes C8h y el segundo 64h.
sumas

C8
64
___
2C

y llevas uno entonces el segundo registro se hace asi... sumas el registro con los numeros mas altos con un cero...

1
00
00
___
01

entonces te lo pongo todo junto

1
00 C8
64
______
1 2C

el registro bajo o menos significativo tendra 2C y el algo o mas significtivo tendra el 1.

Y para los corrimientos igual... juega con el carry.

corrimiento a la derecha del registro mas significativo, en el carry se mete el bit menos significativo. Segido por otro corrimiento a la derecha del registro menos significativo, se mete en el bit mas significativo el bit del carry.
Y asi te la llevas 4 veces y haces el corrimiento a 16 bits y ya tienes tu resultado.
 
Ok, gracias. Pense que el corrimiento era sin carry

Estuve haciendo los recorrimientos en papel en bits, y con cuatro corrimientos no sale la division, sale un valor menor, pero con 3 corrimientos si sale la division
 
Última edición:
Ok, gracias. Pense que el corrimiento era sin carry
Estuve haciendo los recorrimientos en papel en bits, y con cuatro corrimientos no sale la division, sale un valor menor, pero con 3 corrimientos si sale la division
Pero de cuanto la muestra? Con 4 corrimientos a la derecha estas dividiendo por 16, y con 3 por 8.

Tambien podes usar otros metodos para "planchar" la lectura.
Una forma pedorra es con un filtro IIR de 1er orden --> el proceso queda "un poco" mas simple.

Llamando a las variables en uso:
Sacc : registro auxiliar de 16bit o lo que haga falta.
Vout : Ultimo valor de salida.
Vin : Lectura actual del ADC.
Cada vez que tenes un nuevo valor en el ADC haces:
Sacc = Sacc + Vin - Vout ; actualizas Sacc
Vout = Sacc/16 ; actualizas la salida
La division por 16 son 4 corrimientos a la derecha. Podes usar mas o menos corrimientos de acuerdo a lo "lenta" que se tolere la evolucion de la salida.
Tambien tenes que tener en cuenta que si la evolucion es lenta Sacc puede dar overflow --> vas a necesitar mas de 16bits.
 
Estoy midiendo un sensor de temperatura (LM135).
Hice esta rutina pero no me sale el resultado correcto. me podrian ayudar?
ADC solo es la llamada a la subrutina de la lectura del dato del convertidor analogico digital, el dato que esta en el registro adresl lo muevo al registro datol con la instruccion movff

Código:
ADCT    CLRF    STATUS,C
        CLRF    DATOPL
        CLRF    DATOPH
        CLRF    DATCL
        MOVLW    .8
        MOVWF    DATCL
        CALL    ADC
        MOVFF    DATOL,DATOPL        
CLPRM    CALL    ADC
        MOVF    DATOL,W
        ADDWF    DATOPL
        BTFSC    STATUS,C
        INCF    DATOPH
        DECFSZ    DATCL,1
        GOTO    CLPRM
        RRCF    DATOPH,1
        RRCF    DATOPL,1
        RRCF    DATOPH,1
        RRCF    DATOPL,1
        RRCF    DATOPH,1
        RRCF    DATOPL,1
        CLRF    DATOL
        MOVFF    DATOPL,DATOL
        RETURN
Eduardo, lo que escribiste, tengo que sacar 16 muestras o como?

EDIT. Ya vi por que salia un valor erroneo, el valor de DATCL debe de ser 7 por que antes de CLPRM llamo al convertidor y despues lo vuelvo a llamar antes de que se haga la resta con DECFSZ. Seguire haciendo pruebas
 
Última edición:
...Eduardo, lo que escribiste, tengo que sacar 16 muestras o como?
No hay "cantidad de muestras", la respuesta de ese filtro es la misma que tendrias haciendo pasar una señal analogica por un filtro RC.
Simplemente vas ejecutando el algoritmo con cada lectura del ADC.
La cantidad de corrimientos de determina la velocidad de respuesta. El valor ideal va a depender del ruido que tengas y la cantidad de lecturas por segundo.

El bloque de codigo puede ser asi:

Código:
        CALL ADC_proc

        MOVF DATOsalida, W   
        SUBWF DATOL, W
        ADDWF DATOPL, F
        MOVLW 0
        ADDWFC DATOPH, F  ; Sacc += Vadc-Vsalida

        RRCF DATOPH, W      ;Vsal = Sacc>>N
        MOVWF AuxH
        RRCF DATOPL, W
        MOVWF AuxL
        RRCF AuxH, F     
        RRCF AuxL, F      ; >> 2 
        
        RRCF AuxH, F
        RRCF AuxL, F      ; >> 3
        
       ; RRCF AuxH, F
       ; RRCF AuxL, F      ; >> 4  
        
       ; RRCF AuxH, F
       ; RRCF AuxL, F      ; >> 5         
        
        MOVFF AuxL, DATOsalida
        RETURN
Use dos registros auxiliares para el corrimiento.
Ahi puse como comentario los dos ultimos corrimientos para que no sea tan lenta la evolucion.
La salida del filtro es DATOsalida, no DATOL como en la rutina que hiciste.

Los valores de DATOPL,DATOPH y DATOsalida se inicializan solamente al comienzo del programa o en un reset.
 
Última edición:
Atrás
Arriba