Autor Tema: Como conmutar entradas ADC 16f877  (Leído 8073 veces)

0 Usuarios y 2 Visitantes están viendo este tema.

Desconectado kanaryes

  • PIC10
  • *
  • Mensajes: 8
Como conmutar entradas ADC 16f877
« en: 01 de Mayo de 2008, 14:48:37 »
Hola a todos,
quisiera saber como puedo ir activando las distintas entradas analogas(AN0,AN1,AN2....) para que el conversor analogico digital me vaya transformando estas entradas anlogicas una a una, ya que por el momento solo puedo transformar una (AN0).

Con los bits CHS2 ~ CHS0 del registro ADCON0 (000 = AN0 .... 111 = AN7) selecciono al principio del programa con que entrada empiezo la conversion, pero al acabarla, debo volver a configurar el ADCON0 ??.
Dejo esquema del ciruito a implementar.

Gracias y un saludo :)

Desconectado ales

  • PIC10
  • *
  • Mensajes: 33
Re: Como conmutar entradas ADC 16f877
« Respuesta #1 en: 03 de Mayo de 2008, 23:19:07 »
No se en que lenguaje quieres que te ayuden, pero por lo que hablas debe ser ensamblador.
Con el CCS es muy facil cambiar el multiplexor de las entradas analógicas.
 En la ayuda está muy claro.

saludos.

Desconectado MLO__

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4581
Re: Como conmutar entradas ADC 16f877
« Respuesta #2 en: 03 de Mayo de 2008, 23:51:17 »
Hola.

En CCS se debe hacer uso de la funcion set_adc_ports() ... para saber que combinacion de puertos analogicos se puede hacer debes ver en el datasheet. Ya en el bucle de conversion se escoge el canal con set_adc_channel() y se guarda el resultado con el read_adc().

Otra manera es con los registros ADCON0 y ADCON1, pero hay que definirlos con anterioridad con #byte ADCON0=xxx y se carga el valor igualando el registro con el valor correspondiente: ADCON0 = 0x01; por ejemplo. Si quieres modificar un bit del ADCONx se define con #bit ADON=ADCONx.xxx y listo. Las direcciones de los registros estan en el datasheet.

Chao
El papel lo aguanta todo

Desconectado firepic

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1130
    • JC Servicios
Re: Como conmutar entradas ADC 16f877
« Respuesta #3 en: 04 de Mayo de 2008, 03:38:46 »
Saludos!

Con los bits CHS2 ~ CHS0 del registro ADCON0 (000 = AN0 .... 111 = AN7) selecciono al principio del programa con que entrada empiezo la conversion, pero al acabarla, debo volver a configurar el ADCON0 ??.

En efecto, con los bits CHS2:CHS0 de ADCON0 selecciones que canal vas a leer... así que si por ejemplo, terminaste de leer AN0 y quieres pasar a AN1, colocas CHS2:CHS0 en 001 (es decir, sólo pones en 1 CHS0) y listo, ya has seleccionado AN1 para la próxima lectura... y así sucesivamente... repito, no tienes que modificar todo el registro ADCON0, sólo esos bits en particular.
Eso sí, recuerda que entre una conversión y otra debes hacer una pequeña espera, de unos 40 o 50us... para que la conversión pueda comenzar de nuevo... para más detalles lee la datasheet... aunque no especificaste el pic que usas, pero creo que ese es un valor típico...

Bueno espero que sirvan los comentarios que te hemos dado, trata de ser más específico y decir qué lenguaje usas y el pic con el que trabajas para poder ayudarte mejor.

Ok nos leemos!  :mrgreen:
"Por la presunción solo se ocasiona una lucha, pero con los que consultan juntos hay sabiduría" (Proverbios 13:10).
Visita Mi Sitio Web

Desconectado kanaryes

  • PIC10
  • *
  • Mensajes: 8
Re: Como conmutar entradas ADC 16f877
« Respuesta #4 en: 06 de Mayo de 2008, 13:11:12 »
Hola,
Gracias por las respuestas; Como el título del post y el propio foro indican, es lenguaje C y el pic16f877 :mrgreen:
Probare con los bits CH1:CH2 haber que tal.
Gracias y un saludo

Desconectado Gonzalo_BlackHawk

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 519
Re: Como conmutar entradas ADC 16f877
« Respuesta #5 en: 06 de Mayo de 2008, 14:26:33 »
Hola Kanaryes, No hace falta escribir sobre llos bits CH1:CH2 para cambiar el canal del ADC, puedes hacerlo muy facil con la instrucción  set_adc_channel(). CCS recomienda evitar escribir sobre los registros en memoria directamente, puede haber conflicto si la aplicación intenta leerlos o escribirlos por su cuenta, solo hazlo si estas completamente seguro de que el compilador no esta tambíen interviniendo sobre los mismos bytes.

Con respecto al tema del tiempo de multiplexado de la entrada analógica 50 us es un valor que te puede andar en la mayoria de los casos y en otros no, si eres tan quisquilloso como yo y no te gusta desperciar ni un us de tiempo puedes leerte el PIC mid-range reference manual de Microchip, en el apartado del ADC de 10 bits esta como calcular los tiempos del ADC del 16F877.

Un saludo.
"Siempre piensa si el jugo vale la exprimida..."

"La muerte esta tan segura de vencer que nos da toda una vida de ventaja."

Desconectado firepic

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1130
    • JC Servicios
Re: Como conmutar entradas ADC 16f877
« Respuesta #6 en: 06 de Mayo de 2008, 14:54:36 »
Saludos!
Pues como dice Gonzalo, no tienes que escribir en CH1:CH2 porque CCS lo hace por tí cuando usas la instrucción set_adc_channel()...
Ok nos leemos!  :mrgreen:
"Por la presunción solo se ocasiona una lucha, pero con los que consultan juntos hay sabiduría" (Proverbios 13:10).
Visita Mi Sitio Web

Desconectado kcire

  • Colaborador
  • PIC12
  • *****
  • Mensajes: 84
Re: Como conmutar entradas ADC 16f877
« Respuesta #7 en: 13 de Mayo de 2008, 11:26:02 »
Hola, respondiendo a tu pregunta mi solución seria:
#include <16F877A.h>
#device adc = 8
#fuses XT,....
#use delay(clock = 4000000)

#byte trisa=0x85

float V1,V2;

void Leer_ADC1(void){
   setup_port_a( ALL_ANALOG );
   setup_adc( ADC_CLOCK_INTERNAL );
   set_adc_channel( 0 );
   V1 = read_adc();
   delay_ms(20);
   setup_adc (adc_off);
}

void Leer_ADC2(void){
   setup_port_a( ALL_ANALOG );
   setup_adc( ADC_CLOCK_INTERNAL );
   set_adc_channel( 1 );
   V2 = read_adc();
   delay_ms(20);
   setup_adc (adc_off);
}

void main(){
   set_tris_a(0x0F);
   while (TRUE){
      Leer_ADC1();
      lcd_gotoxy(1,1);
      printf(lcd_putc,"Volt= %5.2f",V1);
     
      Leer_ADC2();
      lcd_gotoxy(2,1)
      printf(lcd_putc,"Volt= %5.2f",V1);
   }
}

Puede que exista algun error de mala escritura pero si tengo mas tiempo, prometo enviar el codigo y la simulación.
Espero haya sido de ayuda el comentario....Saludos
"La imaginación es más rica que el lenguaje... sugiere con palabras, la imaginación podrá hacer el resto."

Desconectado Gonzalo_BlackHawk

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 519
Re: Como conmutar entradas ADC 16f877
« Respuesta #8 en: 13 de Mayo de 2008, 13:28:32 »
Kcire, algunas consideraciones acerca de tu código, no necesariamente son errores pues el programa andaria de todas formas, solo voy a indicar algunas cosillas que pueden cambiarse para estilizar y optimizar un poco el código. He salteado los errores de sintaxis pues no vienen al caso:

1) No es necesario escribir en el registro trisa para configurar los puertos del ADC como entradas, salvo que estes utilizando el preprocesador #use fast_io, lo cual no es tu caso. La instrucción set_adc_channel configura el registro tris automáticamente.
2) Seleccionar todos los canales del puerto A como analógicos no es lo mejor. Hay que tratar de elegir la configuración de pines (Las diferentes posibilidades estan contempladas en el archivo de cabecera ".h") que más se adecue a la cantidad de canales que necesitamos, de lo contrario estamos facilitando que ingrese ruido al ADC, aparte del hecho de que desperdiciamos pines de nuestro puerto A.
3) No hay que utilizar el reloj interno del ADC si estamos trabajando con el PIC despierto y a frecuencias de cristal mayores a 1 MHz. Ya lo he explicado en otros mensajes y puede que sea pesado con ese tema  :mrgreen:, pero no obtendras lecturas correctas si no cambias la instrucción setup_adc.
4) Estas apagando y configurando el ADC mas veces de lo estrictamente necesario, esto no es critico, pero no aporta a tu codigo mas que perdida de valiosos microsegundos. Recomiendo configurar el ADC solo durante la carga del pic y luego seleccionar el canal del ADC cuando necesitamos leer los mismos. Es más, si se puede seleccionar el canal varios ciclos de reloj antes de la lectura del ADC, nos evitamos tener que esperan con un delay justo antes de convertir la tensión.
5) La función read_adc() retorna el valor convertido en un tipo de datos int (para tu caso ya que #device adc=8) asi que asignarle una variable tipo float (y sobretodo es global, por lo que ocupa memoria en forma permanente) no es lo correcto. Si tienes que mostrarla luego en el printf en formato decimal, utiliza una sola variable  float local (asi ocupa memoria tan solo un periodo corto de tiempo) que tome los valores de las variables int leidas del ADC.
6) El delay de 20 ms tiene varios problemas, primero, deberia estar antes de la función read_adc y despues de la instruccion set_adc_channel para poder dar tiempo al capacitor del Sample&Hold poder cargarse adecuadamente. Segundo, si cumple esta función, el retardo es excesivamente largo, con algunas decenas de microsegundos basta.

Kanaryes, esperamos tu respuesta acerca de como te ha quedado el código. Un saludo.
"Siempre piensa si el jugo vale la exprimida..."

"La muerte esta tan segura de vencer que nos da toda una vida de ventaja."

Desconectado firepic

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1130
    • JC Servicios
Re: Como conmutar entradas ADC 16f877
« Respuesta #9 en: 13 de Mayo de 2008, 13:54:08 »
Saludos!  :-)

Como siempre, excelente observaciones Dr. Gonzalo!
Ahora bien, tengo algunas cosas que quisiera me confirmaras...
1- En cuanto a lo de configurar el trisa, tengo entendido que cuando no se usa fast_io, el compilador escribe los valores en el tris cada vez que hay una instrucción que usa alguno de los pines del porta... lo cual hace que el programa final sea más largo... no es recomendable usar siempre fast_io, definir uno mismo el tris mediante set_tris_x y así el compilador no tiene que hacer la definición del tris repetidas veces?
2- En cuanto a esto:

void Leer_ADC1(void){
   setup_port_a( ALL_ANALOG );
   setup_adc( ADC_CLOCK_INTERNAL );
   set_adc_channel( 0 );
   V1 = read_adc();
   delay_ms(20);
   setup_adc (adc_off);
}

void Leer_ADC2(void){
   setup_port_a( ALL_ANALOG );
   setup_adc( ADC_CLOCK_INTERNAL );
   set_adc_channel( 1 );
   V2 = read_adc();
   delay_ms(20);
   setup_adc (adc_off);
}

No es mejor hacer una sola función para la lectura a/d, pasándole como parámetro el canal que se desea leer?
Por ejemplo, yo lo haría así:

int conversion (int canal)
{
   int value;
   set_adc_channel(canal);
   delay_us(20);
   value=read_adc();
   return(value);


y luego llamar a la función desde el main, por ejemplo:
V1=conversion(0);
V2=conversion(1);

3- Esta parte:

   setup_port_a( ALL_ANALOG );
   setup_adc( ADC_CLOCK_INTERNAL );

No debería estar dentro del main, antes del while(TRUE)?

Bueno son solo algunas cosas... no sé que tan "detalles" serán... pero pienso que un buen programa debe ser lo más compacto posible... y evitar la repetición de instrucciones mientras no sea necesario... es así Dr. Gonzalo?

Ok espero las respuestas... y gracias kcire, por el aporte... bienvenido al foro! :)
Nos leemos!  :mrgreen:
« Última modificación: 13 de Mayo de 2008, 14:13:42 por firepic »
"Por la presunción solo se ocasiona una lucha, pero con los que consultan juntos hay sabiduría" (Proverbios 13:10).
Visita Mi Sitio Web

Desconectado pocher

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 2568
Re: Como conmutar entradas ADC 16f877
« Respuesta #10 en: 13 de Mayo de 2008, 14:11:00 »
Hola Gonzalo, yo soy otro que usa el setup_adc( ADC_CLOCK_INTERNAL ); para frecuencias mayores de 1Mhz.

No te digo que no tengas razón, porque lo habrás comprobado, yo lo hago así porque se lo ví hacer a los de CCS. Este es un ejemplo ... y hay más:

Código: [Seleccionar]
/////////////////////////////////////////////////////////////////////////
////                        EX_ADMM10.C                              ////
////                                                                 ////
////  This program displays the min and max of 30 A/D samples over   ////
////  the RS-232 interface.  The process is repeated forever.        ////
////  This version uses a 10 bit ADC.                                ////
////                                                                 ////
////  Configure the CCS prototype card as follows:                   ////
////     Insert jumper from output of POT to pin A5                  ////
////     Use a 10K POT to vary the voltage.                          ////
////                                                                 ////
////  Jumpers:                                                       ////
////     PCM,PCH    pin C7 to RS232 RX, pin C6 to RS232 TX           ////
////                                                                 ////
////  This example will work with the PCM and PCH compilers.  The    ////
////  following conditional compilation lines are used to include a  ////
////  valid device for each compiler.  Change the device, clock and  ////
////  RS232 pins for your hardware if needed.                        ////
/////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996,2003 Custom Computer Services         ////
//// This source code may only be used by licensed users of the CCS  ////
//// C compiler.  This source code may only be distributed to other  ////
//// licensed users of the CCS C compiler.  No other use,            ////
//// reproduction or distribution is permitted without written       ////
//// permission.  Derivative programs created using this software    ////
//// in object code form are not restricted in any way.              ////
/////////////////////////////////////////////////////////////////////////


#if defined(__PCM__)
#include <16F877.h>
#device ADC=16
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#elif defined(__PCH__)
#include <18F452.h>
#device ADC=16
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#endif

void main() {

   int i;
   long value, min, max;

   printf("Sampling:");

   setup_port_a( ALL_ANALOG );
   setup_adc( ADC_CLOCK_INTERNAL );
   set_adc_channel( 0 );

   do {
      min=0xffff;
      max=0;
      for(i=0; i<=30; ++i) {
         delay_ms(100);
         value = Read_ADC();
         if(value<min)
            min=value;
         if(value>max)
            max=value;
      }
      printf("\n\rMin: %4LX  Max: %4LX\n\r",min,max);

   } while (TRUE);
}

Un saludo

Desconectado Gonzalo_BlackHawk

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 519
Re: Como conmutar entradas ADC 16f877
« Respuesta #11 en: 13 de Mayo de 2008, 19:45:28 »
Hola firepic, gracias por el cumplido  :-/ :-/ :-/

Vamos a analizar lo que has comentado en tu ultimo mensaje. Con respecto a lo que has dicho en el punto 1, no puedo estar mas de acuerdo contigo, utilizar #use fast_io ahorra tiempo al procesador ya que las instrucciones y funciones que vienen incluidas con el CCS (conocidas comunmente como built-in functions) no pierden tiempo configurando el registro tris cada vez que son llamadas. La unica desventaja (por asi decirlo, aunque realmente no lo sea) que esto conlleva es que la persona que realiza el programa debe tener pleno control del estado de los puertos durante cada instante del programa, y configurar los mismos mediante set_tris cuando se lo requiera.

El metodo #use fixed_io es otro método tambien muy útil sobretodo si la direcciones de los puertos no cambian mucho durante el transcurso del programa. El problema del fixed_io es que la mayoria de la gente malinterpreta su función y lo asimila mucho a la configuración #use standart_io, cuando en realidad es muy similar, sino identica, a la fast_io cuando en tiempo de ejecución hablamos. La confusión se da, a mi entender, porque en la ayuda de CCS no se explica adecuamente el tema (para variar  :?) lo que da lugar a malinterpretaciones del mismo. No se a ustedes que les parece, pero no quiero explayarme mas sobre el fixed_io porque deformaria la temática original del post, asi que sigamos con el ADC  :-).

firepic, con respecto a lo que has expuesto en el segundo y tercer punto, tambien estoy complementamente de acuerdo contigo y te aplaudo de pie, pues has explicado en forma breve y concisa como debería realizarse correctamente el programa.
Con respecto a los "detalles" los he subestimado de tal forma para no parecer un maniatico obsesivo por la optimización, limpieza y orden de codigo, que, en realidad lo soy  :D :D. El problema de programar en lenguaje C ,y en realidad cualquier lenguaje que no sea ASM, es que es muy fácil colocar cosas de mas y derrochar recursos de nuestro PIC, a veces a tal punto de necesitar uno más potente o con más memoria que el esencialmente requerido.

Pocher, a mi me gusta mucho CCS, creo que dentro de todo es un buen programa, pero he aprendido con las malas que ni la ayuda ni los ejemplos que ofrecen son del todo correctos, uno puede darse cuenta de ello dandose una vueltita por el foro de la pagina del compilador donde los usuarios cuentan realmente la verdad de las cosas (extraña coincidencia, lo de fixed_io es un claro ejemplo de ello). Microchip hace referencia a las limitaciones del oscilador RC interno del ADC en muchas de sus Application Notes y reference manual's. Puedes leer este tema si te interesa, a lo largo de el hablo varias veces sobre la configuración del oscilador del ADC:

Seguimiento a los voltajes de I/O de un trafo

Quiero terminar mostrando una taba sacada del Microchip PIC mid-range MCU reference manual, en el apartado del ADC de 10 bits:



Lean lo que dice la nota 4 que se aplica a la fila de la tabla que ocupa el oscilador RC interno, traduzco:

Citar
Para frecuencias del dispositivo por encima de 1 MHz, el dispositivo debe estar en modo Sleep durante toda la conversión, o la precisión del ADC puede estar fuera de las especificaciones.

En otros articulos el tema se trata con un poco más de profundidad, sin embargo queria exponer esa simple consideración.

Nos estamos escribiendo.
"Siempre piensa si el jugo vale la exprimida..."

"La muerte esta tan segura de vencer que nos da toda una vida de ventaja."

Desconectado firepic

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1130
    • JC Servicios
Re: Como conmutar entradas ADC 16f877
« Respuesta #12 en: 13 de Mayo de 2008, 23:47:23 »
Saludos!  :-)
Gracias Dr. Gonzalo por tus explicaciones!  :-/ Muy interesante lo del punto 4 que mencionas de la DS. En lo que tengas un chance me gustaría que abrieras un hilo explicándo eso mejor... puedes?  :?
Ok nos leemos!  :mrgreen:
"Por la presunción solo se ocasiona una lucha, pero con los que consultan juntos hay sabiduría" (Proverbios 13:10).
Visita Mi Sitio Web

Desconectado pocher

  • Moderador Local
  • DsPIC30
  • *****
  • Mensajes: 2568
Re: Como conmutar entradas ADC 16f877
« Respuesta #13 en: 14 de Mayo de 2008, 01:47:16 »
La Nota4 de Microchip es muy directa, entonces en el ejemplo de CCS donde utilizan una fosc=20Mhz, sí ó sí debieran de haber usado un adc_div_32, sin embargo mirando la tabla el TAD está justo en la frontera del TADmín=1,6us ... creo que la única forma de salir de dudas es comprobándolo prácticamente como tú has hecho y en próximos proyectos lo voy a tener en cuenta.

Desconectado kcire

  • Colaborador
  • PIC12
  • *****
  • Mensajes: 84
Re: Como conmutar entradas ADC 16f877
« Respuesta #14 en: 14 de Mayo de 2008, 21:59:17 »
Hola Gonzalo_BlackHawk, muchas gracias por el comentario la verdad que si concuerdo con lo que dices pues la verdad yo di el codigo sin considerar esos factores, y a primera mano, bueno tengo dudas sobre los puntos 3 y 4, ya que no me quedaron claros, y la verdad no quisiera quedar con esa ?, si podrias justificar eso que dices seria de mucha ayuda, gracias de antemano.

Adjunto la simulación en Proteus del ADC con 2 entradas espero lo vean todos quienes estan interesados, y espero sus comentarios que la verdad son de mucha ayuda.

Saludos Kcire
"La imaginación es más rica que el lenguaje... sugiere con palabras, la imaginación podrá hacer el resto."


 

anything