TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: weland98 en 30 de Marzo de 2018, 22:22:28

Título: Conversión digital analoga [SOLUCIONADO]
Publicado por: weland98 en 30 de Marzo de 2018, 22:22:28
Buenas a todos,

Acudo al foro con el fin de que me asesoren un poco con respecto al tema conversión digital análoga.
Sucede que la primer parte del código es realizar operaciones con dos entradas análogas variables, implementando interrupciones para un tiempo de muestreo de 10ms.

Pero la siguiente parte del código consiste en realizar la conversión digital (que es el resultado de la operación), a una salida análoga para apreciarla en el osciloscopio. Me dijeron que se podía con el módulo CCP del PIC, pero no sé como implementar este para realizar dicha conversión,

De antemano agradezco cualquier tipo de sugerencia, crítica o colaboración que puedan brindarme  :)

Gracias, aquí el codigo:

Código: C
  1. #include <16f877a.h>
  2. #device adc=10
  3. #fuses hs,nowdt,noprotect,noput
  4. #use delay (clock=4M)
  5. #int_timer1
  6.  
  7. void timer_1()
  8. {
  9.    set_timer1(64911);
  10. }
  11.  
  12. void main ()
  13. {
  14.  
  15.    setup_timer_1(t1_internal|t1_div_by_8);
  16.    set_timer1(64911);
  17.    enable_interrupts(int_timer1);
  18.    enable_interrupts(global);
  19.    int16 q;
  20.    int16 j;
  21.    float m;
  22.    float k=0.5;
  23.    setup_adc_ports(an0_an1_an3);
  24.    setup_adc(adc_clock_internal);
  25.  
  26.    while(true)
  27.    {
  28.      
  29.       set_adc_channel(0);
  30.       delay_us(20);
  31.       q=read_adc();
  32.       set_adc_channel(1);
  33.       delay_us(20);
  34.       j=read_adc();
  35.       if(input(pin_B0)==0)
  36.       {
  37.       m=(k*j*q);    
  38.       }
  39.       if(input(pin_B0)==1)
  40.       {        
  41.       m=(k*j)+q;
  42.       }
  43.      
  44.    }
  45. }
Título: Re:Conversión digital analoga
Publicado por: KILLERJC en 30 de Marzo de 2018, 22:32:12
Usas el CCP como PWM, y a la salida del PWM una resistencia + un capacitor, para "filtrarlo y asi obtener la componente de DC.

Lo que haces es variar el Duty de tu PWM y asi obtener una tension distinta del otro lado:

(https://i.stack.imgur.com/Yi1xt.gif)

No va a ser tan recta la salida asi como la imagen, va a tener subidas y bajadas la tension debido a la carga cuando esta en alto y la descarga cuando esta en bajo. Pero al menos vas a tener una salida analogica (conversion Dig-Ana - DAC -) facilmente realizable.

El 100% de duty lo vas a definir vos, tal ves pases por una formula que te transforme el resultado de tus ADCs a tu duty.
Título: Re:Conversión digital analoga
Publicado por: weland98 en 31 de Marzo de 2018, 01:19:38
Ok, leí un poco más y con tu ayuda llegue a este codigo:

Código: C
  1. #include <16f877a.h>
  2. #device adc=10
  3. #fuses hs,nowdt,noprotect,noput
  4. #use delay (clock=4M)
  5. #include <math.h>
  6. #int_timer1
  7.  
  8. void timer_1()
  9. {
  10.    set_timer1(64911);
  11. }
  12.  
  13. void main ()
  14. {
  15.    set_tris_c(0b000);
  16.    setup_timer_1(t1_internal|t1_div_by_8);
  17.    set_timer1(64911);
  18.    setup_ccp1(ccp_pwm);
  19.    enable_interrupts(int_timer1);
  20.    enable_interrupts(global);
  21.    int16 q;
  22.    int16 j;
  23.    int16 m;
  24.    float k=0.5;
  25.    setup_adc_ports(an0_an1_an3);
  26.    setup_adc(adc_clock_internal);
  27.  
  28.    while(true)
  29.    {
  30.      
  31.      
  32.       set_adc_channel(0);
  33.       delay_us(20);
  34.       q=read_adc();
  35.       set_adc_channel(1);
  36.       delay_us(20);
  37.       j=read_adc();
  38.       if(input(pin_B0)==0)
  39.       {
  40.       m=(k*j*q);    
  41.       set_pwm1_duty(m);
  42.       }
  43.       if(input(pin_B0)==1)
  44.       {        
  45.       m=(k*j)+q;
  46.       set_pwm1_duty(m);
  47.       }
  48.    }
  49. }

Pero cuando lo simulo en Proteus, no me genera siquiera el ciclo "negativo" que debería tener pues de la señal analoga

Esta es la simulacion, agradezco hacerme caer en cuenta de algo que esté obviando, gracias...

(http://www.todopic.com.ar/foros/imgtiny/2c0pxt.png)
(http://www.todopic.com.ar/foros/imgtiny/2jflu0x.png)

También coloco un generador de onda como entrada analoga porque ese fue un requerimiento del taller
Título: Re:Conversión digital analoga
Publicado por: KILLERJC en 31 de Marzo de 2018, 08:34:29
Citar
Pero cuando lo simulo en Proteus, no me genera siquiera el ciclo "negativo" que debería tener pues de la señal analoga

El PIC se encuentra alimentado desde 2 pines GND y VCC, ( 0 a 5V/3v3) entonces no podes tener valores negativos, su salida va a ir desde 0V a 5V. Cualquier DAC en un micro te va a dar el mismo resultado, y lo que vos pedis es una señal alterna.

Si descompones esa señal de PWM en ondas senoidales, te vas a encontrar que tiene una componente de DC + varios senos armonicos de la frecuencia que le diste. Una forma de bloquear el DC, es tener un capacitor en serie.
Inverti los lugares de R3 y C1 (R3 hacela un poco mas grande, 1K por ejemplo) y observa la salida.

Título: Re:Conversión digital analoga
Publicado por: weland98 en 31 de Marzo de 2018, 11:11:57
Hola gracias por responder,

Invertí los componentes como me dijiste

(http://www.todopic.com.ar/foros/imgtiny/2jetkm1.png)

Creo que es algo un poco mejor, pero esos picos cómo los podría arreglar?
Título: Re:Conversión digital analoga
Publicado por: KILLERJC en 31 de Marzo de 2018, 13:30:37
¿Que queres alimentar para que sea tan perfecto y encima como un PWM?
Primero pedis un conversor DAC y luego me decis que lo que buscas es obtener una señal de alterna

Antes de continuar dando posibles soluciones, explicate bien que es lo que queres hacer. Y que pensas alimentar con eso.
Título: Re:Conversión digital analoga
Publicado por: weland98 en 31 de Marzo de 2018, 23:58:08
No no, borra lo que te dije del voltaje negativo, lo que quiero básicamente es que me salga una señal seno escalonada, sin embargo me están saliendo unos picos muy grandes, por eso te pregunto cómo podría corregir los picos que ves en la señal...
Título: Re:Conversión digital analoga
Publicado por: Eduardo2 en 01 de Abril de 2018, 01:10:50
No no, borra lo que te dije del voltaje negativo, lo que quiero básicamente es que me salga una señal seno escalonada, sin embargo me están saliendo unos picos muy grandes, por eso te pregunto cómo podría corregir los picos que ves en la señal...

Lo más parecido a eso que podés conseguir mediante la salida PWM filtrada es un seno de frecuencia mucho mas baja, donde vas cambiando el duty cycle acorde a la amplitud correspondiente

Para lo que supongo tenías en mente, con el 16F877 tenés que usar un DAC externo (o si son pocos bits de resolución una red R2R) e ir largando los valores del seno de una tabla.
Título: Re:Conversión digital analoga
Publicado por: KILLERJC en 01 de Abril de 2018, 11:22:50
Ahi te dio las 3 opciones Eduardo.

- Usar el PWM con una tabla de seno, calcular la resistencia+capacitor para la frecuecnia que estes usando. El escalon va a ser feo, pero podes llegar a hacer una senoide.
- Usar un R2R si es que no necesitas tantos escalones. Los escalones van a estar bien definidos.
- Usar un DAC externo, te comunicas por SPI/I2C y el envias los valores que queres.

Otra opcion
- Comprar un PIC con DAC
Título: Re:Conversión digital analoga
Publicado por: weland98 en 01 de Abril de 2018, 11:58:15
Tengo una duda respecto a la opción del pwm. Lo que pasa es que lo que me piden es que el periodo de muestreo sea de 10ms, eso lo garantizo con las interrupciones del timer 1. Lo que no estoy seguro es para cuadrar la frecuencia del pwm es si setear otro timer para dejar esta frecuencia distinta? Y si el filtro lo calculo para esa frecuencia del pwm, o para la frecuencia del generador de onda?

Gracias a todos por su ayuda.
Título: Re:Conversión digital analoga
Publicado por: Eduardo2 en 01 de Abril de 2018, 15:48:47
Tengo una duda respecto a la opción del pwm. Lo que pasa es que lo que me piden es que el periodo de muestreo sea de 10ms, eso lo garantizo con las interrupciones del timer 1. Lo que no estoy seguro es para cuadrar la frecuencia del pwm es si setear otro timer para dejar esta frecuencia distinta? Y si el filtro lo calculo para esa frecuencia del pwm, o para la frecuencia del generador de onda?
...

La frecuencia del PWM debe ser la mas alta posible (otro timer).

Pero tené en cuenta que un filtro no hace magia con un solo período PWM, para suavizar decentemente una señal de ese tipo se necesitan MUCHOS períodos (20 o mas).
Eso obliga a que para "ver escalones"  deba elegir la frecuencia mas alta para el oscilador del PWM y una resolución tal que el período resulte unos 2kHz.

Además, la señal PWM es p*ta de filtrar ==> mejor usar un filtro de 2do orden, por ejemplo, con dos RC en cascada (R=3k3 , C=330n , para períodos de 500ms)
Título: Re:Conversión digital analoga
Publicado por: weland98 en 04 de Abril de 2018, 13:03:20
Hola buenas ya pude filtrarla un poco mejor para una frecuencia de PWM de 8kHz.
Pero ahora lo que me piden es utilizar la función seno, solo que en ecuaciones en diferencia. ¿ alguna idea de como pueda plasmar una ecuación en diferencia en lenguaje C?
Título: Re:Conversión digital analoga
Publicado por: Eduardo2 en 05 de Abril de 2018, 00:59:30
Hola buenas ya pude filtrarla un poco mejor para una frecuencia de PWM de 8kHz.
Pero ahora lo que me piden es utilizar la función seno, solo que en ecuaciones en diferencia. ¿ alguna idea de como pueda plasmar una ecuación en diferencia en lenguaje C?

Al profesor le decís que buscaste en una tabla la transformada Z del seno (o coseno) y armaste la antitransformada por recurrencia.
Aunque si el párrafo anterior te suena a chino, decí que la encontraste en Internet.

La recurrencia para un seno es   Xn = k*Xn-1 - Xn-2   ,  n > 1

Siendo 
     k = 2*cos(ang)        ,  ang : El ángulo que avanza en cada paso.
     X0 = 0
     X1 = A*seno(ang)   ,  A : Amplitud. 



Ojo con las relaciones recursivas. 
- Si trabajás con punto flotante no hay problemas salvo claro , la velocidad.
- Pero cuando la velocidad importa hay que trabajar en enteros.  En ese caso hay que ser cuidadoso porque los truncamientos y la manera en que se hacen las operaciones pueden hacer desastres después de muchas iteraciones. 
Los "desastres" pueden ser  senos que se extinguen , que crecen y crecen (termina con overflows) , de amplitud variable , con un error en frecuencia o  uno poco de cada cosa.


Saludos.
Título: Re:Conversión digital analoga
Publicado por: KILLERJC en 05 de Abril de 2018, 08:05:03
No entiendo/encuentro como llegaste a esa formula. Puedo pensar en matematica discreta pero sigo sin ver el aproximado de la misma. Y sino podrías dar un ejemplo de como serian las primeras 4 resultados de esa ecuación?, Segun mi entendimiento seria:

Xn = k*Xn-1 - Xn-2

n = 0
Xn = k*0 - 0
n = 1
Xn = 2*cos(ang)*A*sen(ang)  - 0
n = 2
Xn = ¿?¿??¿ - 2*cos(ang)*A*sen(ang)

Si me decís que tengo que variar el angulo de coseno y seno, significa que necesito implementar 2 tablas, una de seno y otra de coseno! para obtener el seno ¿?¿?. Si no varia el angulo, y elijo un angulo igual a 0 para simplificar, el resultado es siempre 0. Porque k es 0.


En todos lados veo que usan series de taylor, o se puede usar los polinomios de Chebyshev, pero la anti trasformada como la planteas no la vi nunca.

Por mi:
Si quiere un calculo con una ecuación en diferencia, que cargue una tabla con la diferencia entre un punto y otro, y no el valor total. Algo simple y sigue siendo una ecuación en diferencia, el concepto esta, es culpa de el docente por no ser especifico.
Y por supuesto, la suma de todos los valores que cargues en la tabla te debe dar 0 si o si. Y nunca sobrepasar los limites 0 y el limite superior que elijas ( ejemplo 4095 )
Título: Re:Conversión digital analoga
Publicado por: Eduardo2 en 05 de Abril de 2018, 13:13:17
No entiendo/encuentro como llegaste a esa formula.

Aprovecho que las antitransformadas Z  salen con relaciones de recurrencia. 
Conociendo la transformada del seno (https://es.wikipedia.org/wiki/Transformada_Z#Tabla_con_los_pares_m%C3%A1s_habituales_de_la_transformada_Z) , la recurrencia queda:
Xn - 2*cos(a)*Xn-1 + Xn-2 = sin(a)*En-1
Usando de la excitación un impulso, simplificando y ordenando llegás a la expresión que puse.


Citar
Puedo pensar en matematica discreta pero sigo sin ver el aproximado de la misma. Y sino podrías dar un ejemplo de como serian las primeras 4 resultados de esa ecuación?, Segun mi entendimiento seria:

Xn = k*Xn-1 - Xn-2

n = 0
Xn = k*0 - 0
n = 1
Xn = 2*cos(ang)*A*sen(ang)  - 0
n = 2
Xn = ¿?¿??¿ - 2*cos(ang)*A*sen(ang)

Si me decís que tengo que variar el angulo de coseno y seno, significa que necesito implementar 2 tablas, una de seno y otra de coseno! para obtener el seno ¿?¿?

O sigue entrando un A*sen(ang) ?

No, como k es una constante se evalúa al inicio de acuerdo al ángulo de avance deseado.
Lo mismo con X1 = A*sen(ang) ,  es un valor inicial.

Un ejemplo en C  (para PC)  largando una lista de valores puede ser:

Código: [Seleccionar]
#include <stdio.h>
#include <math.h>

void main(void){

// Declaracion de variables

    int n ;
    double k , ang , A  ;
    double xn1 , xn ;

// Inicializacion

    ang = 4*M_PI/180  ; // Angulo de avance de 4°
    A   = 1000        ; // Amplitud  1000
    k   = 2*cos(ang)  ;
   
    xn1 = 0 ; xn  = A*sin(ang) ;     // Valores iniciales

// Salida de 200 valores , para no hacer
// un bucle infinito

    printf("%.3lf\n%.3lf\n",xn1,xn); // Muestro los dos
                                     // primeros
    for(n=2;n<200;n++){
        xn = -xn1 + k*(xn1=xn)  ;  // Esto es la única operación que se repite
        printf("%.3lf\n",xn)    ;
    }
}


Yo soy un amante de C porque los operadores permite bonitas fórmulas compactas (aunque díficil de interpretar)  :)

Por ejemplo, si a la recursión anterior la trabajamos un poco algebraicamente llegamos a la siguiente: 
   dn = dn-1 - k*xn
   xn = xn-1 + dn

Esas dos líneas , en C  equivalen a:     xn += dn -= k*xn ;

Este ejemplo genera exactamente la misma secuencia que el anterior (ojo que la definicion de k es diferente)

Código: [Seleccionar]
#include <stdio.h>
#include <math.h>

void main(void){

// Declaracion de variables

    int n ;
    double k , ang , A  ;
    double xn , dn ;

// Inicializacion

    ang = 4*M_PI/180  ; // Angulo de avance de 4°
    A   = 1000        ; // Amplitud  1000
    k   = 2*sin(ang/2);
    k  *= k           ;
    xn = 0 ; dn = A*sin(ang) ; // Valores iniciales

// Salida de 200 valores , para no hacer
// un bucle infinito

    printf("%.3lf\n",xn); // Muestro el valor inicial

    for(n=1;n<200;n++){
        xn += dn -= k*xn  ;
        printf("%.3lf\n",xn) ;
    }
}

Incluso puede implementarse sin ni siquiera calcular al inicio senos y cosenos sino manejarse con aproximaciones, ya que el avance angular siempre es un valor bajo.


Citar
En todos lados veo que usan series de taylor, o se puede usar los polinomios de Chebyshev, pero la anti trasformada como la planteas no la vi nunca.

Eso lo usás para calcular la función en un punto y lo lógico es usarlo para tablas de lookup o interpolar una tabla.

Acá la antitransformada es para hallar la ley de recurrencia y  meterla en un bucle infinito.

Citar
Por mi:
Si quiere un calculo con una ecuación en diferencia, que cargue una tabla con la diferencia entre un punto y otro, y no el valor total. Algo simple y sigue siendo una ecuación en diferencia, el concepto esta, es culpa de el docente por no ser especifico.
Y por supuesto, la suma de todos los valores que cargues en la tabla te debe dar 0 si o si. Y nunca sobrepasar los limites 0 y el limite superior que elijas ( ejemplo 4095 )

Ojo,  "ecuación en diferencias" se refiere a ecuaciones de este tipo (https://es.wikipedia.org/wiki/Ecuaciones_en_diferencias) ,  no al incremento respecto del valor anterior.   Salvo claro, que el docente haya abusado del lenguaje.


Saludos.
Título: Re:Conversión digital analoga
Publicado por: weland98 en 05 de Abril de 2018, 16:46:30
Hola buenas, justamente ayer el profesor explicó eso que hiciste ahí (publiqué antes de la clase pensando que no nos iba a decir ni explicar nada jaja).

Bien, teniendo la expresión como tal, nos hizo entender que es importante escalizar la salida de esa operación previamente dicha. Observando tu codigo, y teniendo en cuenta lo que el nos dijo, iniciamos a evaluar cuando n=2, ahora bien, tengo un par de inquietudes...

¿cómo puedo escalizar esa señal teniendo en cuenta que ese valor es el que va a leer el PWM para mostrarlo en la salida del CPP ?
¿basicamente lo unico que va en el ciclo sería la operación como tal? en mi caso, ¿iría dentro del while y el resto de la definición iria en el main?, considerando que nos dice que cada 10 ms, el programa tiene que repasar la operación...
Título: Re:Conversión digital analoga
Publicado por: Eduardo2 en 06 de Abril de 2018, 13:36:35
Citar
Bien, teniendo la expresión como tal, nos hizo entender que es importante escalizar la salida de esa operación previamente dicha. Observando tu codigo, y teniendo en cuenta lo que el nos dijo, iniciamos a evaluar cuando n=2, ahora bien, tengo un par de inquietudes...

¿cómo puedo escalizar esa señal teniendo en cuenta que ese valor es el que va a leer el PWM para mostrarlo en la salida del CPP ?

Es hacer una operaci'on tipo y=a+b*x

Si generás un seno de amplitud ligeramente menor que 1 en punto flotante y necesitás escalarlo a un entero de 10bit pues hacés:   xpwm = (x+1)*512

Lo de generarlo "ligeramente menor que 1" es para no tener overflow o underflow cuando x vale +/-1 , pues debido a los redondeos de las operaciones en punto flotante podría ocurrir que (x+1)*512 tome valores negativos o mayores de 1023 (0x3FF)


Citar
¿basicamente lo unico que va en el ciclo sería la operación como tal? en mi caso, ¿iría dentro del while y el resto de la definición iria en el main?, considerando que nos dice que cada 10 ms, el programa tiene que repasar la operación...

Algo así:

Generás un tic de 10ms

Código: [Seleccionar]
int1 tic = 0 ;

#INT_TIMER1
void tic_10ms() {
    set_timer1(xxxx);  // xxxx el que haga falta para 10ms
    tic = 1 ;
}

Y en main:

Código: [Seleccionar]
int16   xpwm    ;  // Global por si la uso fuera de main

void main(){

   .........  demás definiciones
   .................
    float32 x = .95 ;   // Valor inicial = Amplitud. Por prevención ligeramente menor que 1
    float32 d = 0   ;

    float32 k = 1/32  ;
    // El ángulo de avance será  ang = 2*asin(sqrt(k)/2)
    // Y la frecuencia  f = ang/(2*PI*T)
    // para T=10ms, k=1/32  resulta f=2.68Hz
   
    ..... Habilitaciones, etc
    ...................................

    xpwm = (x+1)*512 ;   // pwm duty

    while(TRUE)
    {
        if(tic){
            tic = 0 ;
            x += d -= x*k      ;   // genero el nuevo valor de seno
            xpwm = (x+1)*512   ;   // pwm duty
   
            .........  reajustar el duty cycle
            .........  si sincronizado, mejor.
 
        }
     ......... Demás tareas
     .........................
    }
}


Las operaciones en punto flotante son consumidoras de recursos, por eso no meterlas dentro de la interrupción, pues pueden hacer  "bailar" los tics de 10ms



Saludos.
Título: Re:Conversión digital analoga
Publicado por: weland98 en 08 de Abril de 2018, 11:31:43
Hola, llegué a un código basándome en lo que me dijiste para la ecuación en diferencias, asumiendo una f=10Hz y el Ts=ms:

y(k)=1.61y(k-1)-y(k-2)

Código: C
  1. #include <16f877a.h>
  2. #device adc=10
  3. #fuses hs,nowdt,noprotect,noput
  4. #use delay (clock=4M)
  5. #include <math.h>
  6. int1 tic = 0 ;
  7.  
  8. #INT_TIMER1
  9. void tic_10ms()
  10. {
  11.     set_timer1(64911);
  12.     tic = 1 ;
  13. }
  14.  
  15. int16   xpwm    ;  
  16.  
  17. void main(){
  18.  
  19.    set_tris_c(0b000);
  20.    setup_timer_2(T2_DIV_BY_1,199,1);
  21.    setup_ccp1(ccp_pwm);
  22.    enable_interrupts(int_timer1);
  23.    enable_interrupts(global);
  24.     float32 y1 = 1.61 ;  
  25.     float32 y2 = 1   ;
  26.     float32 y;
  27.     int16 q;
  28.     xpwm = (y+2)*512 ;   // pwm duty
  29.  
  30.     while(TRUE)
  31.     {
  32.         if(tic)
  33.         {
  34.             tic = 0 ;
  35.            
  36.             set_adc_channel(0);
  37.             delay_us(20);
  38.             q=read_adc();
  39.             y=q*(1.61*y1)-y2      ;   // ecuacion en diferencias, asumiendo 10Hz
  40.             xpwm = (y+2)*512;// escalización
  41.             set_pwm1_duty(xpwm);
  42.             y1=y;
  43.             y2=y1;
  44.    
  45.            
  46.         }
  47.    
  48.     }
  49. }

(http://www.todopic.com.ar/foros/imgtiny/2zogr4y.png)

Mira la señal que me genera :shock:

Calculé el timer 2 para una frecuencia de 8kHz, no sé que pueda estar asumiendo mal, o no teniendo en cuenta,

Gracias por toda la ayuda que me han brindado  :o :o
Título: Re:Conversión digital analoga
Publicado por: weland98 en 08 de Abril de 2018, 11:36:00
Se me olvidaba,

Cuando trato de variar la entrada análoga, el cambio no se evidencia ni siquiera en la siguiente muestra, por lo que me toca hacer stop en la simulación y reiniciar con un valor diferente, ¿qué podrá ser?
Título: Re:Conversión digital analoga
Publicado por: tsk en 08 de Abril de 2018, 12:11:53
primero revisa esta parte de tu código

Código: [Seleccionar]
            y1=y;
            y2=y1;

Al final el contenido de y1 y y2 va a ser el  valor actual de y

Código: [Seleccionar]
            y2=y1;
            y1=y;

De esta forma y2 va a tener el valor de y1 y y1 va a tener el valor actual de y
Título: Re:Conversión digital analoga
Publicado por: Eduardo2 en 08 de Abril de 2018, 14:42:27
De momento veo unos cuantos errores

Código: [Seleccionar]
    float32 y1 = 1.61 ;
    float32 y2 = 1   ;

Inicializando así te sale con una amplitud de casi 1.7

Para una amplitud 1 eso debió ser

Código: [Seleccionar]
    float32 y1 = 0.587 ;  // A*seno(2*PI*f*tic)
    float32 y2 = 0     ;  // Cero , pues inicia en 0

También por simplicidad se la puede inicializar con un valor cómodo, ya
que la fase inicial acá no importa.

Código: [Seleccionar]
    float32 y1 = .95   ;  // La amplitud real es ligeramente mayor
    float32 y2 = .95   ;  // que 0.95

En ambos casos, es preferible que la amplitud no esté al límite pues
para valores particulares, al final puede haber overflows.

Como para eso entra en juego el truncamiento/redondeo de las operaciones,
lo mas sencillo es ejecutar el programa y si ocurran overflows -> bajar
la amplitud.


Código: [Seleccionar]
    float32 y;
    int16 q;
    xpwm = (y+2)*512 ;   // pwm duty

Nones, fijate que para y positivos xpwm sale mayor se 1023 (los 10bits)
Para una amplitud menor que 1 debio ser xpwm = (y+1)*512 ; 

Código: [Seleccionar]
    q=read_adc();
    y=q*(1.61*y1)-y2      ;   // ecuacion en diferencias, asumiendo 10Hz
Ahí multiplicando por q, además que no se qué quisiste hacer, destrozás la recurrencia.

Va solamente       y = 1.61*y1 - y2

Si bien no es un error, es preferible un valor mas cercano a 2 (menor frecuencia)  para que el seno esté formado por mayor cantidad de puntos  (ejemplo: 1.95).

Si querés usar el valor del ADC para variar la amplitud lo tenés que hacer en el escalado:  xpwm = q*y/2+512 ;

Si querés usarlo para variar la frecuencia ya hay que recalcular el valor de K y un valor inicial.



Código: [Seleccionar]
    xpwm = (y+2)*512;// escalización
    set_pwm1_duty(xpwm);

De nuevo, el escalado a 10bit:  xpwm = (y+1)*512 ;   
Siempre que la amplitud de "y" sea menor que 1 claro.


Código: [Seleccionar]
    y1=y;
    y2=y1;

Esto ya lo vió tsk ,  debe ser:

Código: [Seleccionar]
    y2 = y1 ;
    y1 = y  ;



Saludos.
Título: Re:Conversión digital analoga
Publicado por: weland98 en 09 de Abril de 2018, 00:27:40
Lo que hice fue realizar una tabla de valores para la ecuación en diferencias:

Citar
La recurrencia para un seno es   Xn = k*Xn-1 - Xn-2   ,  n > 1

Siendo
     k = 2*cos(ang)        ,  ang : El ángulo que avanza en cada paso.

Hace de cuenta que partí de esta ecuación, asumiendo una f=10Hz y un Ts=10ms. Como el ángulo es w.Ts=2pi*10*0.01=0.628, por eso, al reemplazar y operar esa k que tienes, se obtiene 1.61, que es el valor inicial que tome. Básicamente lo que observé en la tabla de valores que armé, es que el seno que se forma, tiene una amplitud aproximada a 2, por eso hice la escalización a 2.

Citar
Si querés usar el valor del ADC para variar la amplitud lo tenés que hacer en el escalado:  xpwm = q*y/2+512 ;

Por qué pones y/2?

Hice las modificaciones para hacer la variación en xpwm, y sigue sin mostrarse la variación  en la salida del cpp :/
Título: Re:Conversión digital analoga
Publicado por: weland98 en 09 de Abril de 2018, 00:49:57
Sin embargo, hay dos cosas que aun no te entiendo del codigo que me sugeriste a seguir:

Por  qué un if (tic), y declararlo al principio como tic=0, luego como 1, y así?

Por qué me dices que hay que multiplicar por el 512 al xpwm?
Título: Re:Conversión digital analoga
Publicado por: Eduardo2 en 10 de Abril de 2018, 11:47:43
Disculpame la demora en responder.

Lo que hice fue realizar una tabla de valores para la ecuación en diferencias:
..............
Hace de cuenta que partí de esta ecuación, asumiendo una f=10Hz y un Ts=10ms. Como el ángulo es w.Ts=2pi*10*0.01=0.628, por eso, al reemplazar y operar esa k que tienes, se obtiene 1.61, que es el valor inicial que tome. Básicamente lo que observé en la tabla de valores que armé, es que el seno que se forma, tiene una amplitud aproximada a 2, por eso hice la escalización a 2.

Si ok, el inconveniente eran los valores iniciales y1,y2  que parecían puestos al azar y son muy importantes porque te definen la amplitud de la oscilación.


Citar
Citar
Si querés usar el valor del ADC para variar la amplitud lo tenés que hacer en el escalado:  xpwm = q*y/2+512 ;

Por qué pones y/2?

Porque q llega hasta 1023,  y si le sumás 512 te pasás de los 10 bits del PWM.

De todas formas, como vi que estás usando el 16F877  a 4MHz ,  para un duty 100%  el máximo es 800.


Citar
Sin embargo, hay dos cosas que aun no te entiendo del codigo que me sugeriste a seguir:

Por  qué un if (tic), y declararlo al principio como tic=0, luego como 1, y así?

Como las operaciones en punto flotante son consumidoras de tiempo, es preferible que no estén dentro de interrupciones que deben ocurrir a intervalos precisos.  En muchos casos puede no ser necesario, yo lo hice por default   :) .

Lo que hago con el tic es ponerlo en 1 cuando ocurre la interrupcion, de esa manera se entera el bucle en main() y ejecuta los cálculos con todo el tiempo del mundo disponible y sin problemas ante otras interrupciones que podrían ocurrir.
Luego de el if(tic) se pone en 0 para que no se vuelva ejecutar hasta que lo active la interrupción.

Citar
Por qué me dices que hay que multiplicar por el 512 al xpwm?

xpwm debe ser un numero entre 0 y 1023  a 20MHz y entre 0 y 800 a 4MHz

- Si tenés un float entre +/-1  tenés multiplicarlo por la nueva amplitud y sumarle un offset: 
xpwm = y*512 + 512 = (y+1)*512   (para 20MHz)
xpwm = y*400 + 400 = (y+1)*400   (para 4MHz)

- Si querés variar es amplitud con la lectura del ADC (0-1023) tenés que escalarla también:
xpwm = (q/1024) *y*512 + 512 = y*q/2 + 512        (para 20MHz)
xpwm = (q/1024) *y*400 + 400 = y*q/2.56 + 400   (para 4MHz)

--------------------------------------------------------------------------

Te pongo un ejemplo sin la parte de ADC.   
- Genero un seno de 4Hz que luce mejor que de 10Hz.

Código: [Seleccionar]
#include <16f877a.h>
#device adc=10
#fuses hs,nowdt,noprotect,noput
#use delay (clock=4M)

int1    tic = 0 ;
int16   xpwm    ;

#define PERIODO 65536-625

#INT_TIMER1
void tic_10ms()
{
    tic = 1    ;
    set_timer1(PERIODO);
    set_pwm1_duty(xpwm);
}

void main(){

    set_tris_c(0b000);
    setup_timer_1(t1_internal|t1_div_by_8);
    set_timer1(PERIODO);

    setup_timer_2(T2_DIV_BY_1, 199, 1);
    setup_ccp1(CCP_PWM);
    set_pwm1_duty(0);

    enable_interrupts(int_timer1);
    enable_interrupts(global);

    float32 k  = 1.937 ;  // 2*cos(2*PI*f*T)
    float32 y1 = .2363 ;  // Amp*seno(2*PI*f*T)
    float32 y2 = 0     ;  // Amp = .95  f = 4 Hz  T = .01s
    float32 y          ;

    xpwm = (y1+1)*400  ; 
    while(TRUE)
    {
        if(tic)
        {
            tic = 0 ;
            y = k*y1-y2   ;     
            xpwm = (y+1)*400   ;
            y2 = y1 ; y1 = y   ;
        }
    }
}


- Cambié las constantes del filtro RC.  Aún así, le falta un poco.
- Al osciloscopio le dejé dos trazos para marcar 0 y 5V
- Los glitches no estoy seguro si es el simulador que hace mal la parte analógica al no ser en tiempo real o algún problemita raro con el intervalo entre interrupciones.


(http://www.todopic.com.ar/foros/index.php?action=dlattach;topic=48658.0;attach=29024)
Título: Re:Conversión digital analoga
Publicado por: weland98 en 10 de Abril de 2018, 15:13:42
No hay problema, ya me varía la amplitud con la entrada análoga, sin embargo:

¿por qué asumes 400 para la escalización a 4 MHz, porque es simplemente un valor entre 0 y 800? ¿ahora bien, hay alguna fórmula o expresión que dicte que ese valor tiene que ser entre 0 y 800?

¿por qué en la recurrencia:

Citar
La recurrencia para un seno es   Xn = k*Xn-1 - Xn-2   ,  n > 1

Siendo
     k = 2*cos(ang)        ,  ang : El ángulo que avanza en cada paso.
     X0 = 0
     X1 = A*seno(ang)   ,  A : Amplitud.
 

X1=A*sen(ang)?
Título: Re:Conversión digital analoga
Publicado por: Eduardo2 en 10 de Abril de 2018, 15:51:37
....
¿por qué asumes 400 para la escalización a 4 MHz, porque es simplemente un valor entre 0 y 800? ¿ahora bien, hay alguna fórmula o expresión que dicte que ese valor tiene que ser entre 0 y 800?

Quejas a Microchip  ;-) 
Honestamente no he estudiado profundamente el datasheet, donde seguramente de manera poco clara explican la relación.

Yo lo generé via el PIC Wizard del CCS , en la pestaña Other/Code podés ver el código que va a usar.
Para dutys del 100% te da:  1023 @ 20MHz ,  800 @ 4MHz ,  200 @ 1MHz ....  (Valores que en el Proteus funcionan a la perfeccion).
Los  400 son un offset para aprovechar todo el rango : 
El mínimo en 0 :    -1*400+400 = 0   --> duty = 0%
Y el máximo en 800 :    1*400+400 = 800  --> duty = 100%



Citar
¿por qué en la recurrencia:
................................
X1=A*sen(ang)?

Eso pertenece a la solución de la ecuación de recurrencia.   
De esos dos valores iniciales depende la amplitud y la fase inicial.  Si uno quiere iniciar en valor 0 pues el siguiente debe ser ese, de lo contrario la amplitud será lo que decida Dios.

Tenés otras alternativas de inicialización, como ser en un máximo/míximo, con lo que X1 = X2 = +/-A   ( A: amplitud)
Título: Re:Conversión digital analoga
Publicado por: weland98 en 10 de Abril de 2018, 18:04:47
Okay, revisaré el datasheet.

Citar
Xn - 2*cos(a)*Xn-1 + Xn-2 = sin(a)*En-1

Como tal hasta acá entiendo que haces, pero no entiendo porque asumes un X1=A*sin(ang). Hastá aca, lo que el seno esta multiplicando es a la entrada retrasada una muestra, lo que en algun punto va a ser 0 si asumimos una entrada impulso. Por esto no te entiendo porqué asumes que X1 tome ese valor, y luego sea que lo asumas como x(n-1)...  :-/

Título: Re:Conversión digital analoga
Publicado por: weland98 en 10 de Abril de 2018, 18:59:29
Básicamente la ecuación a tomar en cuenta será:

y(k)=1.937y(k-1)-y(k-2)+0.248u(k-1)

Tú en el código asumes que ese 0.248 (multiplicado por 0.95) de u(k-1), sea el valor inicial que tome el y(k-1) y que el y(k-2) sea cero.

Es esta parte que aun no entiendo...
Título: Re:Conversión digital analoga
Publicado por: Eduardo2 en 10 de Abril de 2018, 22:45:32
Okay, revisaré el datasheet.

Citar
Xn - 2*cos(a)*Xn-1 + Xn-2 = sin(a)*En-1

Como tal hasta acá entiendo que haces, pero no entiendo porque asumes un X1=A*sin(ang). Hastá aca, lo que el seno esta multiplicando es a la entrada retrasada una muestra, lo que en algun punto va a ser 0 si asumimos una entrada impulso. Por esto no te entiendo porqué asumes que X1 tome ese valor, y luego sea que lo asumas como x(n-1)...  :-/

Como estás haciendo la antitransformada Z
   Xn = 0   si  n<0
   y  En es un impulso ==>  Vale  1 si n=0  y  0 si n!=0

Entonces

n=0 :   X0 - 2*cos(a)*X-1 + X-2 = sin(a)*E-1   ==>  X0 = 0   pues  X-1 = X-2 = E-1 = 0
n=1 :   X1 - 2*cos(a)*X0 + X-1 = sin(a)*E0     ==>  X1 = sin(a)   pues   X-1 = 0 , X0 = 0 del paso anterior  y  E0 = 1
n=2 :   X2 - 2*cos(a)*X1 + X0 = sin(a)*E1      ==>  X2 =  2*cos(a)*X1 - X0    esto es lo que repetís, pues  En = 0 para n<>0
Título: Re:Conversión digital analoga
Publicado por: weland98 en 11 de Abril de 2018, 11:29:47
AAAAAAAAAH vale, ya sé porqué no le encontraba sentido.

Lo que pasa es que yo asumo que en n=0, x0=1, asumiendo una señal paso. Y de ahí para adelante, obviamente los valores cambian. Por ejemplo, para X1=2cos(a)+sen(a), y asi sucesivamente. ¿te puedo preguntar por qué asumes X-1 = X-2 = E-1 = 0?
Título: Re:Conversión digital analoga
Publicado por: Eduardo2 en 11 de Abril de 2018, 13:01:10
En la definición de  H(xn) = SUM(xn z-n , n=0 to inf)   no se están utilizando lo k negativos. 

Para la antitransformada  de  H(z) = P(z)/Q(z) = X(z) 
se hace  Q(z)X(z) = P(z)E(z)   siendo En un impulso (pues Z(en) = 1) 

Luego, sin el mínimo pudor intelectual se reemplazan los  X(z)z-i e E(z)z-j por xn-i y en-j 
Ahí está la clave, de esa operación solamente se obtienen los xn originales si los xn y en son 0 para n<0

----------------------------------------------------------

Una manera de verlo es hacer la transformada Z de la recurrencia

a0 xn + a1 xn-1 + a2 xn-2 = b1 en-1   

Siendo en un impulso unitario.

Supongamos que  x-1 y x-2 sean distintos de 0  ¿Cual será la transformada Z de eso?

Transformando ambos miembros

Z(a0 xn + a1 xn-1 + a2 xn-2) = Z(bn-1 en-1)

a0 Z(xn) + a1 Z(xn-1) + a2 Z(xn-2) = b1 Z(en-1)

a0 X(z) + a1 (X(z)z-1 + x-1) + a2 (X(z)z-2 + x-1 z-1 + x-2) = b1 z-1
                                                               
(a0 + a1 z-1 + a2 z-2)X(z) + a1 x-1 + a2 x-1 z-1 + a2 x-2 = b1 z-1

==> X(z) = (b1 z-1 - (a1 x-1 + a2 x-1 z-1 + a2 x-2))/(a0 + a1 z-1 + a2 z-2)                                                         
   
Oh-oh  nada que ver con la transformada original.

Luego, deben ser x-1 = x-2 = 0


Comentario: Es una situación similar a la que ocurre con las transformadas de Laplace de derivadas. 
Título: Re:Conversión digital analoga
Publicado por: weland98 en 12 de Abril de 2018, 18:38:09
Hola vale,

Si ya lo entiendo,

Muchísimas gracias a todos los que me ayudaron ya daré el tema como solucionado, gracias.  ((:-))
Título: Re:Conversión digital analoga
Publicado por: Fer_TACA en 13 de Abril de 2018, 05:54:17
Sería bueno, entonces, que editaras el primer post cambiando el titulo y añadiéndole algo como !Solucionado!
Título: Re:Conversión digital analoga [SOLUCIONADO]
Publicado por: micronet3 en 17 de Abril de 2018, 12:23:33
Saludos, tengo una consulta, estoy buscando un pic con 20 entradas analogicas para poder conectar sensores, mi pregunta es que si es posible utilizar las 20 entradas analogicas de un pic?

gracias

atte
micronet
Título: Re:Conversión digital analoga [SOLUCIONADO]
Publicado por: KILLERJC en 17 de Abril de 2018, 12:52:09
Saludos, tengo una consulta, estoy buscando un pic con 20 entradas analogicas para poder conectar sensores, mi pregunta es que si es posible utilizar las 20 entradas analogicas de un pic?

gracias

atte
micronet

al mismo tiempo no, una detras de otro y esperando el tiempo de establecimiento si.
Título: Re:Conversión digital analoga [SOLUCIONADO]
Publicado por: micronet3 en 17 de Abril de 2018, 14:03:10
 :-/ :-/
ok gracias killerjc