Autor Tema: Comunicación serie de 2 Pic a Diferente Frecuencia  (Leído 12775 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Abner_emanuel

  • PIC16
  • ***
  • Mensajes: 160
Re:Comunicación serie de 2 Pic a Diferente Frecuencia
« Respuesta #30 en: 29 de Mayo de 2017, 18:29:19 »
 

Una pregunta y perdona mi ignorancia, que significa esta linea: #define MUESTRAS (1 << 3)   (¿cuantas muestras va a tomar? o ¿como la interpreto?)
« Última modificación: 01 de Junio de 2017, 09:34:57 por Abner_emanuel »
El señor es mi pastor,  nada me faltará.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Comunicación serie de 2 Pic a Diferente Frecuencia
« Respuesta #31 en: 29 de Mayo de 2017, 22:31:57 »
Cuando tenes valores constantes, no es necesario crear una variable. Por ejemplo del modo que vos hiciste "Muestras" el compilador va a reservar un lugar en la RAM para Muestras, le va a cargar un valor, luego cuando hagas Muestras + 1 , va a generar las instrucciones para sumarle 1.

En mi caso al usar el #define le estoy diciendo al compilador que cuando encuentre la palabra MUESTRAS en el codigo simplemente lo reemplaze con (1<<3) es decir 8. En resumen es como si tuvieras un valor constante, el cual no se reserva RAM para este, ni tampoco deberia generar instrucciones si sumas una constante como es si pones un MUESTRAS +1, ya que el compilador luego de reemplazarlo se daria cuenta que el numero es constante y por lo tanto reemplazaria por un numero simple en ese lugar.

Desconectado Abner_emanuel

  • PIC16
  • ***
  • Mensajes: 160
Re:Comunicación serie de 2 Pic a Diferente Frecuencia
« Respuesta #32 en: 30 de Mayo de 2017, 12:50:05 »
Otra vez yo preguntando killer y perdona eso pero me a gustado mucho la forma en que reduces el code, solo que no entiendo estas lineas.

Porqué el 0xFF en ese vector?.. Chanels séra [6] en lugar de 5, por que así me da error al compilar.

const int8 ADC_Channels[5] =
{0,1,2,3,5,0xFF};

Y aquí también como se interpreta ese 0xFF del for
 
      for(i=0; i!=0xFF ; i++)

Aquí seria += para ir acumulando las lecturas en el adC?

ADC_Val[ i ] = read_adc();

« Última modificación: 30 de Mayo de 2017, 13:13:48 por Abner_emanuel »
El señor es mi pastor,  nada me faltará.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Comunicación serie de 2 Pic a Diferente Frecuencia
« Respuesta #33 en: 30 de Mayo de 2017, 14:08:02 »
Si en realidad cometi MAS errores. Luego te doy el codigo coorregido y te digo los errores que tuve. Primero te cuento mis intenciones.

Cuando intente reducir el codigo me encontre que no utilizas las entradas 0,1,2,3,4 sino que la ultima es el 5. Es decir no son todas seguidas.

Una solución es en el codigo fijarse que si el indice es el 4, usar el canal 5. Esta es una solucion muy simple, pero que si algun dia cambias las entradas o la cantidad de entradas tendrias que modificar el codigo. Lo cual no sirve, y es mejor un codigo que pueda ser reutilizado

La otra solucion fue hacer una tabla. De los canales y coeficientes.

Código: C
  1. const int8 ADC_Channels[5] = {0,1,2,3,5};

Esto me permite que yo pueda cambiar el orden de las entradas leidas o coeficientes sin tener que cambiar el codigo, lo cual me permite reutilizarlo.

Y aqui llega un nuevo problema.... Cuando se cuando se terminan las entradas?

Existen 2 formas de realizarlo.. La primera y mas simple es agregar un termino que finalice el loop. Como yo hice fue agregar un 0xFF, entonces la idea es que cuando ADC_Channels sea igual a 0xFF salga. (Este es uno de mis errores). Entonces el codigo correcto seria asi:

Código: C
  1. #define MUESTRAS (1<<3)
  2.  
  3. float ADC_Values[5];
  4. const int8 ADC_Channels[6] = {0,1,2,3,5,0xFF};
  5. const float ADC_Coef[5] = {0.48875855327468230694037145650049,0.48875855327468230694037145650049,0.48875855327468230694037145650049,0.48875855327468230694037145650049,0.06109481915933528836754643206256};
  6.  
  7. void filtro_promediado(float * ADC_Val)
  8. {
  9.  
  10.       int8 i,j;
  11.       for(i=0; ADC_Channels[i]!=0xFF ; i++)
  12.       {
  13.             set_adc_channel(ADC_Channels[i]);
  14.             delay_us(20);
  15.             for(j=0; j<MUESTRAS;j++) {
  16.                   ADC_Val[i] = read_adc();
  17.             }
  18.             ADC_Val[i] /= MUESTRAS;
  19.             ADC_Val[i] *= ADC_Coef[i];
  20.       }
  21. }

Otra forma de saber cuando termina es darle de antemano la cantidad. Utilizando el operador sizeof, para esto ya no utilizamos mas un termino para indicarnos el fin. Lo cual hace mas intuitivo la parte de elegir los canales y coeficientes, ya que si tenes 5 canales necesitas si o si 5 coeficientes y 5 lugares donde ponerlo.

Código: C
  1. #define MUESTRAS (1<<3)
  2. #define CANT_CANALES 5
  3.  
  4. float ADC_Values[CANT_CANALES];
  5. const int8 ADC_Channels[CANT_CANALES] = {0,1,2,3,5};
  6. const float ADC_Coef[CANT_CANALES] = {0.48875855327468230694037145650049,0.48875855327468230694037145650049,0.48875855327468230694037145650049,0.48875855327468230694037145650049,0.06109481915933528836754643206256};
  7.  
  8. void filtro_promediado(float * ADC_Val, int8 Asize)
  9. {
  10.  
  11.       int8 i,j;
  12.       for(i=0; i < Asize ; i++)
  13.       {
  14.             set_adc_channel(ADC_Channels[i]);
  15.             delay_us(20);
  16.             for(j=0; j<MUESTRAS;j++) {
  17.                   ADC_Val[i] = read_adc();
  18.             }
  19.             ADC_Val[i] /= MUESTRAS;
  20.             ADC_Val[i] *= ADC_Coef[i];
  21.       }
  22. }

Para esto vamos a llamar a la funcion de esta forma:

Código: C
  1. filtro_promediado(ADC_Values, (sizeof ADC_Values)/(sizeof ADC_Values[0]))

sizeof se precalcula antes por el compilador y luego es reemplazado por una constante en el programa. Es decir no es una funcion que va a tener sus instrucciones en el microcontrolador.

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

Si aun asi queres mas generalizacion de la funcion podes hacer:

Código: C
  1. #define MUESTRAS (1<<3)
  2. #define CANT_CANALES 5
  3.  
  4. float ADC_Values[CANT_CANALES];
  5. const int8 ADC_Channels[CANT_CANALES] = {0,1,2,3,5};
  6. const float ADC_Coef[CANT_CANALES] = {0.48875855327468230694037145650049,0.48875855327468230694037145650049,0.48875855327468230694037145650049,0.48875855327468230694037145650049,0.06109481915933528836754643206256};
  7.  
  8. void filtro_promediado(float * ADC_Val, const int8 * ADC_Chan, const float * ADC_Cof, int8 Asize)
  9. {
  10.  
  11.       int8 i,j;
  12.       for(i=0; i < Asize ; i++)
  13.       {
  14.             set_adc_channel(ADC_Chan[i]);
  15.             delay_us(20);
  16.             for(j=0; j<MUESTRAS;j++) {
  17.                   ADC_Val[i] = read_adc();
  18.             }
  19.             ADC_Val[i] /= MUESTRAS;
  20.             ADC_Val[i] *= ADC_Cof[i];
  21.       }
  22. }

El #define CANT_CANALES nos permite que si por algun motivos no ponemos la cantidad correcta tengamos un error y todos los arrays tengan el mismo largo.
El pasar todos los punteros permite que no importa el nombre que le des vos a tus arrays siempre y cuando lo pases en orden.
Respecto a la proteccion para que se usen solo los valores dados y no entradas de mas que no estan contempladas en el array, esto depende de quien hace el codigo, ya que posee un campo de "tamaño"

Desconectado Abner_emanuel

  • PIC16
  • ***
  • Mensajes: 160
Re:Comunicación serie de 2 Pic a Diferente Frecuencia
« Respuesta #34 en: 30 de Mayo de 2017, 20:57:20 »
Gracias  ((:-)) muy bien explicado. Voy a pasarlo al compilador y veremos que pasa. Ten agradezco..
Como paso esa funcion dentro del while (true){


« Última modificación: 01 de Junio de 2017, 09:33:37 por Abner_emanuel »
El señor es mi pastor,  nada me faltará.

Desconectado Abner_emanuel

  • PIC16
  • ***
  • Mensajes: 160
Re:Comunicación serie de 2 Pic a Diferente Frecuencia
« Respuesta #35 en: 03 de Julio de 2017, 10:51:06 »
Killer JC.  No encontré como hacer la función void dentro del while para que me compile correctamente el code que pusiste de ejemplo:

Citar
#define MUESTRAS (1 << 3)
#define CANT_CANALES 5
 
float ADC_Values[CANT_CANALES];
const int8 ADC_Channels[CANT_CANALES] = {0,1,2,3,5};
const float ADC_Coef[CANT_CANALES] = {0.48875855327468230694037145650049,0.48875855327468230694037145650049,0.48875855327468230694037145650049,0.48875855327468230694037145650049,0.06109481915933528836754643206256};
 
void filtro_promediado(float * ADC_Val, const int8 * ADC_Chan, const float * ADC_Cof, int8 Asize)
{
 
      int8 i,j;
      for(i=0; i < Asize ; i++)
      {
            set_adc_channel(ADC_Chan);
            delay_us(20);
            for(j=0; j<MUESTRAS;j++) {
                  ADC_Val = read_adc();
            }
            ADC_Val /= MUESTRAS;
            ADC_Val *= ADC_Cof;
      }
}

Esto me marca error const int8 * ADC_Chan, Asize y que significa #define MUESTRAS (1<< 3)

Anexo el code en c.

« Última modificación: 05 de Julio de 2017, 02:52:50 por Abner_emanuel »
El señor es mi pastor,  nada me faltará.

Desconectado Abner_emanuel

  • PIC16
  • ***
  • Mensajes: 160
Re:Comunicación serie de 2 Pic a Diferente Frecuencia
« Respuesta #36 en: 19 de Julio de 2018, 10:40:31 »
Alguien sabe por que me aparece este error en el proteus al simular este filtro de medida móvil?

El mensaje del proteus es el siguiente:

Código: C++
  1. [PIC18 ADC] PC=0x0252. ADC conversion started before 'wait' time has expired following previous conversion or channel change. [U1]

Dice algo de los tiempos de carga del canal, pero donde poner esos retardos o es el proteus el que no funciona bien?. El pic es el 4550 y lo estoy utilizando a 48Mhz.
« Última modificación: 19 de Julio de 2018, 10:43:00 por Abner_emanuel »
El señor es mi pastor,  nada me faltará.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Comunicación serie de 2 Pic a Diferente Frecuencia
« Respuesta #37 en: 19 de Julio de 2018, 12:07:07 »
cuando vos cambias de canal, o vas a comenzar otra muestra, dependiendo del ADC necesita un pequeño tiempo para cargarse al voltaje correcto, y mientras mayor la resistencia a la entrada del ADC mayor el tiempo a esperar. Es lo que se conoce como tiempo de adquisicion. Algunos PICs permiten modificar el tiempo de adquisicion, otros es fijo, y asi varian con cada familia.

En resumen el proceso es un tiempo de adquisicion (capacitor conectado al circuito), y un tiempo de conversion (capacitor conectado al ADC).
Luego de una conversion el capacitor se descarga, al cambiar de canal el capacitor necesita acomodar la tension que posee dentro, entonces necesitas esperar un tiempo ANTES de la proxima conversion.. Algo asi:

Código: C
  1. set_adc_channel(1)
  2. delay_us(10);           // Este tiempo es parte de la adquisicion.
  3. valor = read_adc();
  4. set_adc_channel(0)
  5. delay_us(10);           // Este tiempo es parte de la adquisicion.
  6. valor = read_adc();

Obviamente el tiempo de adquisicion va a depender de tu circuito. el datasheet explica bien como calcularlo. A su ves el tiempo de adquisicion se separa en otros mas.
Y el tiempo de adquisicion debe cumplirse para que los valores del datasheet del ADC se cumplan.

Desconectado Abner_emanuel

  • PIC16
  • ***
  • Mensajes: 160
Re:Comunicación serie de 2 Pic a Diferente Frecuencia
« Respuesta #38 en: 19 de Julio de 2018, 12:22:59 »
KILLER_JC, Siempre atento a responder nuestras dudas. Un agradecimiento.

E visto la hoja de datos, sin embargo, en este caso no se donde colocar bien el o los delay para esto:

Código: C++
  1. .   int8 i,j;
  2.  
  3.          for(i=0; i < Asize ; i++)
  4.  
  5.          {
  6.             set_adc_channel(ADC_Chan[i]);
  7.  
  8.             delay_us(20);
  9.             for(j=0; j<MUESTRAS;j++) {
  10.                   ADC_Val[i] = read_adc();
  11.             }
  12.  
  13.             ADC_Val[i] /= MUESTRAS;
  14.             ADC_Val[i] *= ADC_Cof[i];
  15.          }


Por que al ser array la lectura de los canales es diferente estar colocando el de delay para cada canal por separado.

Quizás sera que se deberá utilizar algúna bandera ?. O algún timer del pic para tomar las muestras.

Pero si es como bien dices KILLER, ahora con el pic a 4 MHz trabaja bien y no muestra el warning, sin embargo  lo pretendo tener trabajando a 48Mhz.
« Última modificación: 19 de Julio de 2018, 12:48:55 por Abner_emanuel »
El señor es mi pastor,  nada me faltará.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Comunicación serie de 2 Pic a Diferente Frecuencia
« Respuesta #39 en: 19 de Julio de 2018, 15:38:23 »
Código: C
  1. delay_us(20);
  2.             for(j=0; j<MUESTRAS;j++) {
  3.                   ADC_Val[i] = read_adc();
  4.             }

por esto:
         
Código: C
  1. for(j=0; j<MUESTRAS;j++) {
  2.                   delay_us(20);
  3.                   ADC_Val[i] = read_adc();
  4.             }

tal ves no afecte (hay que calcularlo), pero si queres sacar ese warning que te da el proteus es asi.

Desconectado Abner_emanuel

  • PIC16
  • ***
  • Mensajes: 160
Re:Comunicación serie de 2 Pic a Diferente Frecuencia
« Respuesta #40 en: 20 de Julio de 2018, 09:52:06 »
 ((:-)) :-/ :mrgreen:  excelente!!!
El señor es mi pastor,  nada me faltará.

Desconectado Abner_emanuel

  • PIC16
  • ***
  • Mensajes: 160
Re:Comunicación serie de 2 Pic a Diferente Frecuencia
« Respuesta #41 en: 05 de Agosto de 2018, 10:28:41 »
Ahora puedo ver correctamente las lecturas de los canales seleccionados. Ahora me surge una pregunta.

Es posible lograr que este algoritmo lea los ADC a 10ks/s (10kilo muestras por segundo). Si estoy a 48Mhz y un cristal externo de 4Mhz?. Y leyendo 10 canales analógicos?. AN0 a AN9 del 18f4550.
El señor es mi pastor,  nada me faltará.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Comunicación serie de 2 Pic a Diferente Frecuencia
« Respuesta #42 en: 05 de Agosto de 2018, 11:06:10 »
La velocidad maxima del ADC esta definida en el datasheet.

para un PIC, su ciclo TAD, y donde su reloj sea:
- alimentado por FOSC tenes que el TAD debe ser de un minimo de 0.7us y maximo de 25us
- alimentado por el RC que posee 1us maximo, el minimo no esta definido. (oscilador interno del ADC)

En resumen se podria decir que el oscilador del mismo ADC ya le da un tiempo suficiente.
Ahora... necesitamos saber cuantos ciclos TAD necesitas.

Para la conversion son entre 11 y 12 TAD, supongamos 12.
Para la adquisicion depende de tu circuito, si no posee una gran impedancia de entrada, podrias seleccionar el minimo. El minimo,maximo permitido por el hardware son:
- FOSC: 0TAD y 12TAD
- RC AD: 1TAD y 12TAD  (podes seleccionar 0, pero le incluye 1 si o si)
0.2us del tiempo de descarga del capacitor.

En el peor de los casos serian 12TAD conversion + 12TAD adquisicion + 0.2us, suponiendo 1us = TAD, tenes que 24.2us de conversion. Por simplicidad omitimos los cambios de canal, el for, etc, que depende del compilador como lo tradusca pero masomenos seria 1 salto, 1 incremento, 1 de comparacion, 2,3 o 4 para cambiar de canal, 1 incio de conversion, 1 salto espera  , aproximadamente unos 0.8us mas quedado asi unos 25us para redondear.

A 25us cada conversion, tenes que podes samplear maximo 40Ks/s, en 10 entradas son 4Ks/s.  ( retirando el delay que hay puesto )
Aunque disminuyas el tiempo de adquisicion a 1 TAD para el caso del RC, tendrias un maximo de 70Ks/s ( suponiendo que puedas disminuirlo )

Esto es lo que puedo asegurar con el datasheet.
La otra es unicamente tomar 8 bits, usar el FOSC para que el TAD sea menor de lo que especifica el datasheet, supongamos 0.5us, y ver si los resultados son conformes, discriminando los ultumos 2 bits de menos peso. Ya aca entramos en un terreno donde las especificaciones del datasheet no se cumplen, por no utilizarlo correctamente.