# Conversor ADC del PIC



## adrii (Sep 29, 2010)

Hola!
Estoy con un proyecto con PIC especificamente el 16F877a.
he leido mucho y ahora programo en lenguaje ensablador, estoy utilizando el conversor ADC del pic pues mi proyecto sensa temperatura y presion.
probe los dos programas por separado.
el de temperatura funciono muy bien, el sensor estaba en la primera entrada del conversor 
(AN0) y mostraba por la LCD la temperatura actual. el sensor de humedad a pesar de que su programa estaba terminado lo conecte a la segunda entrada del ADC (AN1) y probe temperatura y humedad a la vez y temperatura daba bien y humedad no.

asi que revise mil veces el programa y ahi no estaba el error. probe humedad por separado en la primera entrada del ADC reemplazando el sensor de temperatura por el de humedad y funciono perfecto.

PROBLEMA:
no puedo jugar con los dos canales del ADC creo que estoy obviando algo o nose pero necesito que alguien me diga como hacer para sensar con dos canales en el mismo programa.
no puedo utilizar ese cambio de canal para pasar a medir de un sensor a otro. solo por seprado.



ademas quiero agragar que para el primer sensor el voltaje de referencia yo lo he determinado. y para el segundo estoy usando el mismo del PIC 5v


----------



## ByAxel (Sep 29, 2010)

En el datasheet del PIC16F877A
Registros de configuración:
*ADCON0, ADCON1*
Registros del puerto:
*TRISA*
Registros de resultado:
*ADRESH, ADRESL*

Sigue el problema entonces sube el código o parte de él.
El resto lo encuentras en el foro; usa el Buscador
saludos.


----------



## FBustos (Sep 29, 2010)

Editlvide que necesitas el codigo en ensamblador.. lo siento.
-----------------------------------------------------------
Debes decirle al micro que pines usaras como a/d, en css eso se hace asi:

setup_adc(ADC_CLOCK_INTERNAL); //puedes usar distintas bases de tiempo
setup_adc_ports(AN0_TO_AN1_ANALOG ); // ra0 y ra1 como analogo
set_adc_channel(0); // elijo el ra0 analog
delay_us(10);
temp = (5.0*(FLOAT)read_adc()*100)/1024.0;
set_adc_channel(1);//elijo puerto ra1 como analogo
delay_us(10);
humedad=read_adc();

printf(lcd_putc,"\nTEMP :%1.1f",temp); //muestra en el lcd con un decimal

y asi sucesivamente..
saludos


----------



## Dedust (Sep 30, 2010)

Debes configuarar que pines usaras como convertidor A/D En ensambldor lo haces con los registros ADCON0 y ADCON1 como lo dijo el compañero *ByAxel*. Luego en tu programa debes activar la lectura de un conversor A/D y luego la del otro y repetir. No te explico mejor la programacion ya que el lenguaje ensamblador no lo manejo desde hace ya un buen tiempo y no recuerdo mucho pero lee el datasheet y ahi encontraras lo que te digo. Espero que te ayude. 
Saludos.


----------



## adrii (Mar 12, 2011)

bueno... ya tengo el problema de mi conversor.... solo necesitaba un retardo muy largo para darle tiempo de cambiarle el canal


----------



## BKAR (Sep 6, 2011)

hola soy nuevo en esto del ADC del pic...
como debo tratar en pin ADC del pic....
como si fuera una entrada HI-Z (algo asi como un opamp??)
o por seguridad un resistencia en serie?


----------



## Chico3001 (Sep 7, 2011)

Preferentemente se le debe poner un operacional en modo seguidor, pero practicamente nunca se hace por cuestiones de espacio y precio...

Dependiendo del circuito que tengas se tiene que buscar la solucion mas adecuada, si solo quieres hacer pruebas y medir un puente de resistencias (Siempre y cuando el voltaje no exceda los limites) puedes colocar la señal directamente al ADC sin ningun problema...


----------



## buitre (Dic 8, 2011)

hola Chico3001.

Estoy tratando re realizar un programa para controla cuatro entradas analogicas(por el momento), mediante un menu seleccionable con 4 pulsadores up,down, enter y esc, bueno el control del menu mas una entrada AN0 funciona simulado en proteus, pero cunado agrego AN1,AN2,AN3. Al compilar me dice que no se reconoce AN1,AN2,AN3. Porfa si pueden ayudarme, estoy colocando el programa: Los pulsadores (RB0-RB7).Les agradezco de antemano......


```
#INCLUDE "C:\Archivos de programa\PICC\Devices\16F877A.H"
#DEVICE ADC=16
#USE DELAY(CLOCK=8M)
#FUSES HS,NOLVP,NOWDT,NOPROTECT,NODEBUG
#INCLUDE "C:\Archivos de programa\PICC\Drivers\LCD.C"
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
#use fast_io(D)
#INT_RB
void main(void){
    unsigned char menu;
    float d,x;
    port_b_pullups(TRUE);
    setup_adc_ports(ALL_ANALOG);
    setup_adc(ADC_CLOCK_INTERNAL);
    lcd_init();
    enable_interrupts(INT_EXT);
    enable_interrupts(GLOBAL);
    lcd_putc("\f**TEXTO1**\n***TEXTO2***");
    delay_ms(1000);
menu_inicio:
    menu=1;
    lcd_gotoxy(1,1);
    printf(lcd_putc,"\fTENSION_1");
    lcd_gotoxy(1,2);
    printf(lcd_putc,"\TENSION_2");
while(TRUE){
    if(menu==01){
        if(input(PIN_B4)){
            delay_ms(20);
            menu=2;
            lcd_gotoxy(1,1);
            printf(lcd_putc,"\fTENSION_2");
            lcd_gotoxy(1,2);
            printf(lcd_putc,"TENSION_3");
    }else if(input(PIN_B5)){
            delay_ms(20);
            menu=4;
            lcd_gotoxy(1,1);
            printf(lcd_putc,"\fTENSION_4");
            lcd_gotoxy(1,2);
            printf(lcd_putc,"TENSION_5");
    }else if(input(PIN_B6)){
            delay_ms(20);
            setup_adc_ports(AN0);
            set_adc_channel(0);
            delay_ms(30);
    while(TRUE){
                d=read_adc();
                x=(30*d)/1024.00;
                printf(lcd_putc,"\fTENSION_1= %fV",x);
                delay_ms(100);
                if(input(PIN_B7)){
                    delay_ms(20);
                    goto menu_inicio;
                            }
                }

            }
        
        }
    if(menu==02){
        if(input(PIN_B4)){
            delay_ms(10);
            menu=3;
            lcd_gotoxy(1,1);
            printf(lcd_putc,"\fTENSION_3");
            lcd_gotoxy(1,2);
            printf(lcd_putc,"TENSION_4");
    }else if(input(PIN_B5)){
            delay_ms(10);
            menu=1;
            lcd_gotoxy(1,1);
            printf(lcd_putc,"\fTENSION_1");
            lcd_gotoxy(1,2);
            printf(lcd_putc,"TENSION_2");
    }else if(input(PIN_B6)){
            delay_ms(20);
            //setup_adc_ports(ALL_ANALOG);
            //setup_adc(ADC_CLOCK_INTERNAL);
            setup_adc_ports(AN1);
            set_adc_channel(1);
            delay_ms(30);
    while(TRUE){
            d=read_adc();
            x=(30*d)/1024.0;
            printf(lcd_putc,"\fTENSION_2= %fV",x);
            delay_ms(100);
            if(input(PIN_B7)){
                delay_ms(20);
                goto menu_inicio;
                            }    
            }    

        }
    }
    if(menu==03){
        if(input(PIN_B4))
            delay_ms(20);
            menu=4;
            lcd_gotoxy(1,1);
            printf(lcd_putc,"\fTENSION_4");
            lcd_gotoxy(1,2);
            printf(lcd_putc,"\TENSION_1");
    }else if(input(PIN_B5)){
            delay_ms(20);
            menu=2;
            lcd_gotoxy(1,1);
            printf(lcd_putc,"\fTENSION_2");
            lcd_gotoxy(1,2);
            printf(lcd_putc,"\TENSION_3");
    }else if(input(PIN_B6)){
            delay_ms(20);
            setup_adc_ports(AN2);
            set_adc_channel(2);
            delay_ms(30);    
    while(TRUE){
            d=read_adc();
            x=(30*d)/1024.0;
            printf(lcd_putc,"\fTENSION_3= %fV",x);
            delay_ms(100);
            if(input(PIN_B7)){
                delay_ms(20);
                goto menu_inicio;
                            }    
            }    
    }
    if(menu==04){
        if(input(PIN_B4))
            delay_ms(20);
            menu=4;
            lcd_gotoxy(1,1);
            printf(lcd_putc,"\fTENSION_1");
            lcd_gotoxy(1,2);
            printf(lcd_putc,"\TENSION_2");
    }else if(input(PIN_B5)){
            delay_ms(20);
            menu=2;
            lcd_gotoxy(1,1);
            printf(lcd_putc,"\fTENSION_3");
            lcd_gotoxy(1,2);
            printf(lcd_putc,"\TENSION_4");
    }else if(input(PIN_B6)){
            delay_ms(20);
            setup_adc_ports(AN3);
            set_adc_channel(3);
            delay_ms(30);    
    while(TRUE){
            d=read_adc();
            x=(30*d)/1024.0;
            printf(lcd_putc,"\fTENSION_3= %fV",x);
            delay_ms(100);
            if(input(PIN_B7)){
                delay_ms(20);
                goto menu_inicio;
                            }    
            }    
    
        }

    }

}
```


----------



## luispepe24 (Oct 20, 2012)

si alguien me podria dar una idea de como hacer uin temporizador progamable atraves de un potenciometro analogo que vaya desde cero hasta 60 segundo y  que a suvez me active un relay gracias


----------



## ricbevi (Oct 21, 2012)

luispepe24 dijo:


> si alguien me podria dar una idea de como hacer uin temporizador progamable atraves de un potenciometro analogo que vaya desde cero hasta 60 segundo y  que a suvez me active un relay gracias



Hola...Al menos que tengas alguna razón especial lo mas sencillo es un temporizador en base a NE555 y no con un PIC y ADC. Si aun persistes debes conectar el potenciomentro al ADC del PIC y hacer el programa en el lenguaje que sepas para que dependiendo de la lectura del ADC sea el tiempo a transcurrir antes de activar al relay. 
Saludos.
Ric.


----------



## chango107 (Jun 27, 2016)

Hola a todos, 

Tengo un problema con el ADC de PIC ya que he probado en dos PIC diferentes 16F676 y 12F675, el inconveniente es que en algunos rangos de voltaje el micro al parecer no los tomara esos cambios, es decir si vario entre 3.3V y 3.9V la salida que requiero es la misma, lo que estoy buscando es hacer un disparador controlado para un triac pero en ciertos puntos los saltos que realiza son muy grandes el código que estamos implementando es el siguiente: 
	
	



```
#include<16f676.h>
#device adc=10
#fuses NOWDT, NOPROTECT, NOBROWNOUT, NOMCLR, HS, PUT 
#use delay (clock=20000000)
#use standard_io(C)
#INT_EXT
#define LED  PIN_C1
  
void EXT_isr(void)
{
   float q,Vin;
   int16 Dfase,Dfase2;
   set_adc_channel(0);
   q=read_adc();
   Vin=(5*q)/1023;
   if (Vin <= 2.5)
   {
      Dfase=(Vin*3100);
      delay_us(Dfase);
      delay_us(200);
      Output_high(LED);
      delay_us(250);
      Output_low(LED);
      Dfase2=(7730-Dfase);
      delay_us(Dfase2);
      Output_high(LED);
      delay_us(250);
      Output_low(LED);}
    else 
    {
      delay_us(200);
      Dfase=(Vin*3150);
      delay_us(Dfase);
      Output_high(LED);
      delay_us(250);
      Output_low(LED);}
}
 
void main()
{
 
   setup_comparator(NC_NC_NC_NC);
   enable_interrupts(INT_EXT);
   ext_int_edge(L_TO_H);
   enable_interrupts(GLOBAL);
   Output_low(PIN_C0);
   setup_adc_ports(sAN0|VSS_VDD);
   setup_adc(ADC_CLOCK_DIV_2);

   while(true)
   {

   }
}
```

El voltaje que tomamos para leer con el micro viene de una tarjeta de National Instruments y tiene una resolución de 0.01mV, de antemano les agradezco su colaboración en como puedo solucionar este problema ya que en la simulación no realiza estos saltos. ...


----------



## juanma2468 (Jun 27, 2016)

La tensión que intentas medir es una señal alterna de red? 50 o 60 Hz?


----------



## D@rkbytes (Jun 27, 2016)

Con tantos retardos dentro del servicio de interrupción, es muy normal que el programa no funcione correctamente.


----------



## chango107 (Jun 27, 2016)

Hola juanma2468, Gracias por tu pronta respuesta, la tensión que estoy midiendo con el PIC es una señal DC de 0V a 5V, la señal con la que estoy sincronizando el micro es la señal de la red, 60Hz de la cual me sincronizo con un detector de cruce por cero, adjunto una imagen de como estoy realizando las conexiones





D@rkbytes dijo:


> Con tantos retardos dentro del servicio de interrupción, es muy normal que el programa no funcione correctamente.



Hola, D@rkbytes gracias por tu participación, pero no entiendo es porque es solo en algunos rangos de voltaje que presenta esos inconvenientes, los presenta alrededor de los 2V, los de 3.3V a 3.9V y alrededor de los 4.5


----------



## D@rkbytes (Jun 27, 2016)

¿Por qué quieres medir una tensión de 5 V por medio del cruce por cero?
Saca la lectura del conversor de la rutina de interrupción y todo lo que tenga que ver con retardos.


----------



## chango107 (Jun 27, 2016)

D@rkbytes dijo:


> ¿Por qué quieres medir una tensión de 5 V por medio del cruce por cero?
> Saca la lectura del conversor de la rutina de interrupción y todo lo que tenga que ver con retardos.



lo que quiero hacer es un disparador controlado para un Triac, el voltaje que tengo en la entrada analógica de 0V-5V va a representar cuanto voy a desfasar el disparo para que el Triac comience a conducir, el cruce por cero lo utilizo para sincronizar ese disparo a la frecuencia de la red, es decir que si el voltaje que tengo a la entrada es cero la onda no va a presentar ningún recorte, pero si por el contrario el voltaje que lee el micro es de 2.5V voy a tener la onda recortada a la mitad, es algo similar a un dimmer


----------



## D@rkbytes (Jun 27, 2016)

Pues si, así es como funciona un dimmer con potenciómetro controlado por microcontrolador.

Pero la forma en la que lo estás implementando no es la correcta.


----------



## chango107 (Jun 27, 2016)

D@rkbytes dijo:


> Pues si, así es como funciona un dimmer con potenciómetro controlado por microcontrolador.
> 
> Pero la forma en la que lo estás implementando no es la correcta.



Ok, disculpa entonces me podrias dar una idea de como podria realizar esta operación?


----------



## juanma2468 (Jun 27, 2016)

Yo acomodaria el codigo de la siguiente forma para comenzar.

```
#include <16f676.h> 
#device adc=10 
#fuses NOWDT, NOPROTECT, NOBROWNOUT, NOMCLR, HS, PUT  
#use delay (clock=20000000) 
#use [COLOR=Red]fast_io(C)[/COLOR] 
#INT_EXT 
#define LED  PIN_C1   
[COLOR=Red]// Definiciones de variables
float q,Vin; 
long Dfase,Dfase2;[/COLOR]

void EXT_isr(void) 
{    
   if (Vin <= 2.5)    
   {       
       Dfase=(Vin*3100);       
       delay_us(Dfase);       
       delay_us(200);       
       Output_high(LED);       
       delay_us(250);       
       Output_low(LED);       
       Dfase2=(7730-Dfase);       
       delay_us(Dfase2);       
       Output_high(LED);       
       delay_us(250);       
       Output_low(LED);
   }     
   else      
   {       
       delay_us(200);       
       Dfase=(Vin*3150);       
       delay_us(Dfase);       
       Output_high(LED);       
       delay_us(250);       
       Output_low(LED);
    } 
}   

void main() 
{    
   Output_low(PIN_C0);    
   setup_adc_ports(sAN0|VSS_VDD);    
   setup_adc(ADC_CLOCK_DIV_2);    
   set_adc_channel(0);
   ext_int_edge(L_TO_H);    
   enable_interrupts(INT_EXT);   
   enable_interrupts(GLOBAL);   
   while(true)    
   {       
       [COLOR=Red]q=read_adc();       
       Vin=(5*q)/1023;[/COLOR]    
   } 
}
```
Modifique algunas instrucciones y el orden de las instrucciones para optimizarlo. Fijate si asi mejora.


----------



## chango107 (Jun 27, 2016)

Ok, ya podré realizarlo el día de mañana a primera hora les comunicaré como me fue con este nuevo código.

Hola!!, pues hasta el momento he quedado peor de lo que estaba antes, en el momento intento realizar la simulación y ahora no anda no muestra ningún pulso como lo hacia antes, realicé algunos cambios en el código nuevamente como regresar a la configuración standad_io(C), agregar un delay_us(20) luego de la lectura del ADC pero nada lo único que me sirvió es declarar las variables dentro de la interrupción, no se si se deban declarar entonces de otro modo


----------



## D@rkbytes (Jun 28, 2016)

chango107 dijo:


> ¿Me podrías dar una idea de cómo podría realizar esta operación?


Mira el programa adjunto.
No he verificado su funcionamiento físicamente, pero te puede servir de orientación.


----------



## juanma2468 (Jun 28, 2016)

Encontre un error en tu esquema, fijate que la señal de ingreso la estas poniendo en el pin A1, pero para que ocurra un interrupcion, debe estar conectado en el pin A2. Adjunto un imagen con la modificacion que debes realizar. Y vuele a verificar el funcionamiento.


----------



## chango107 (Jun 28, 2016)

juanma2468 dijo:


> Encontre un error en tu esquema, fijate que la señal de ingreso la estas poniendo en el pin A1, pero para que ocurra un interrupcion, debe estar conectado en el pin A2. Adjunto un imagen con la modificacion que debes realizar. Y vuele a verificar el funcionamiento.



fue mi error al subir la imagen no me fije que la conexión estaba en el pin erroneo, en fisico esta sobre el pin que me indicas el pin 11, pero si fue mi error al subir la imagen con esa conexión pido disculpas por eso, y en cuanto a 



D@rkbytes dijo:


> Mira el programa adjunto.
> No he verificado su funcionamiento físicamente, pero te puede servir de orientación.



en el momento estoy usando proteus 8 y de compilador ccs, no se porque cuando guardo el proyecto que me enviaste deja de funcionar, si lo ejecuto en el formato en que viene funciona de maravilla, pero si lo guardo en archivos para esta versión comienza a fallar.

en general e intentado colocar la variable de manera global pero me sigue presentando fallas en cuanto a que el programa no funciona, no he manejado mucho las interrupciones por timer, pero me parece una muy optima opción asi que comenzaré a trabajar con este módulo, y espero que asi se solucione el problema 

---- Actualizado ----

Hola D@rkbytes, tomando en base el código que me aconsejaste de guia lo modifique y realicé el siguiente programa :


```
#include <16f676.h>
#fuses   NOMCLR
#device adc=10
#use     delay(crystal = 20MHz)
long fase;

#INT_EXT
void sd_externa_rb0 (void)
{
   set_timer0(fase);
   enable_interrupts(INT_TIMER0);   
}

#INT_TIMER0
void sdi_desborde_timer0 (void)
{
   disable_interrupts(INT_TIMER0);
   output_high(PIN_A1);
   delay_us(250);
   output_low(PIN_A1);
}

void main()
{
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(sAN0);
   set_adc_channel(0);
   delay_us(22);
   
   enable_interrupts(GLOBAL);
   setup_timer_0 (T0_INTERNAL|T0_DIV_256);
   enable_interrupts(INT_EXT);
   
   while(true)
   {
      fase = ((((157 * read_adc()) / 1024)) + 93);
   }
}
```
hasta el momento he podido realizar simulaciones pero no me  genera algún desfase, corroboro que ingresa a las interupciones dado que  si genera un pulso pero como si el ADC leyera siempre el valor de 0


----------



## D@rkbytes (Jun 28, 2016)

Para lo que requieres, no es necesario que uses el conversor a 10 bits.
Antes de que modifiques el programa, primero comprueba que funcione con el ADC a 8 bits.


----------



## juanma2468 (Jun 29, 2016)

```
#include <16f676.h>  
#device adc=10  
#fuses NOWDT, NOPROTECT, NOBROWNOUT, NOMCLR, HS, PUT   
#use delay (clock=20000000)  
#use [COLOR=Red]fast_io(C)[/COLOR]  
#define LED  PIN_C1

[COLOR=Red]// Definiciones de variables
float Vin; 
long Dfase,Dfase2;
[/COLOR] 
#INT_EXT  
void EXT_isr(void)  
{
[COLOR=Red]   Vin=(5*[/COLOR][COLOR=Red][COLOR=Red]read_adc()[/COLOR])/1023;[/COLOR]    
   if (Vin <= 2.5)        
  {               
      Dfase=(Vin*3100);
      delay_us(Dfase);
      delay_us(200);
      Output_high(LED);               
      delay_us(250);               
      Output_low(LED);               
      Dfase2=(7730-Dfase);               
      delay_us(Dfase2);               
      Output_high(LED);               
      delay_us(250);               
      Output_low(LED);    
   }         
   else
   {               
       delay_us(200);
       Dfase=(Vin*3150);               
       delay_us(Dfase);               
       Output_high(LED);               
       delay_us(250);               
       Output_low(LED);     
    }  
}     

void main()  
{        
    setup_comparator (NC_NC_NC_NC);
    Output_low(PIN_C0);        
    setup_adc_ports(sAN0|VSS_VDD);        
    setup_adc(ADC_CLOCK_DIV_2);        
    set_adc_channel(0);    
    ext_int_edge(L_TO_H);        
    enable_interrupts(INT_EXT);       
    enable_interrupts(GLOBAL);       
    while(true)        
    {               
    }  
}
```
Verifique el codigo que te habia modificado y encontre que el problema era la etiqueta que declara la interrupción, esta quedo mal ubicada, lo simule y si entraba en la interrupción, luego tendras que ver si lo los tiempos son correctos o no.


----------



## chango107 (Jun 29, 2016)

juanma2468 por el momento ya he dejado de lado los retardos con el delay y estoy usando las interrupciones del Timer tiene mas presentación y al parecer funciona mejor, solamente que ahora cambia el problema que vengo presentando el cambió ya que el código que implemento es el siguiente 

```
#include<16f676.h>
#fuses NOWDT, NOPROTECT, NOBROWNOUT, NOMCLR, HS, PUT 
#device adc=8
#use delay (clock=20000000)

int8 fase;

#INT_EXT
void sd_externa_rb0 (void)
{
   set_timer0(fase);
   enable_interrupts(INT_TIMER0);   
}

#INT_TIMER0
void sdi_desborde_timer0 (void)
{
   disable_interrupts(INT_TIMER0);
   output_high(PIN_A1);
   delay_us(200);
   output_low(PIN_A1);
}


void main()
{
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(sAN0);
   set_adc_channel(0);
   delay_us(22);
   enable_interrupts(GLOBAL);
   setup_timer_0 (T0_INTERNAL|T0_DIV_256);
   enable_interrupts(INT_EXT);
   
   while(true)
   {
      fase = 250-((157*read_adc())/255);
      delay_us(20);
   }
}
```

la interrupción se genera y el timer0 se activa pero no cambia el valor dependiendo la lectura del ADC siempre se queda en el mismo punto como muestra la imagen, en que puedo estar fallando?


----------



## chango107 (Jul 1, 2016)

he realizado estos cambios pero persiste el inconveniente, que otro cambio podria realizar?


```
#include<16f676.h>
#fuses NOWDT, NOPROTECT, NOBROWNOUT, NOMCLR, HS, PUT 
#device adc=8
#use delay (clock=20000000)



#INT_EXT
void sd_externa_rb0 (void)
{
int8 fase;
   fase = 250-((157*read_adc())/255);
   delay_us(20);
   set_timer0(fase);
   enable_interrupts(INT_TIMER0);   
}

#INT_TIMER0
void sdi_desborde_timer0 (void)
{
   disable_interrupts(INT_TIMER0);
   output_high(PIN_A1);
   delay_us(200);
   output_low(PIN_A1);
}


void main()
{
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(sAN0);
   set_adc_channel(0);
   delay_us(22);
   enable_interrupts(GLOBAL);
   setup_timer_0 (T0_INTERNAL|T0_DIV_256);
   enable_interrupts(INT_EXT);
   
   while(true)
   {

   }
}
```


----------



## ruben90 (Jul 1, 2016)

El inconveniente me parece proviene de aquí,

```
#INT_TIMER0
void sdi_desborde_timer0 (void)
{
   disable_interrupts(INT_TIMER0);
   output_high(PIN_A1);
   delay_us(200);
   output_low(PIN_A1);
}
```

El pulso siempre durara 200uS.

Para que te sirve la sentencia *while* vacía?

```
while(true)
   {

   }
```


----------



## chango107 (Jul 1, 2016)

Hola ruben90, gracias por tu pronta respuesta, la duración del pulso debe ser siempre de 200uS, lo que quiero que se modifique es el tiempo del timer, el cual lo asigno en 


```
#INT_EXT
void sd_externa_rb0 (void)
{
int8 fase;
   fase = 250-((157*read_adc())/255);
   delay_us(20);
   set_timer0(fase);
   enable_interrupts(INT_TIMER0);   
}
```

y el while vacio es mas para que el micro no ingrese en modo sleep, solo por prevención, no se que me puedas aconsejar para que el código sea funcional


----------



## juanma2468 (Jul 1, 2016)

Creo que hay otro problema, Chango107 estas haciendo set_timer0 (fase); donde "fase" es supongamos para Vin de referencia del preset a la mitad 2,5V ==> fase = 172. Al setear el timer con dicho valor, significa que la interrupción va a ocurrir cuando el timer desborde, o sea cuando sobrepasa 255, por lo que van a ocurrir 84 pasos del timer hasta que eso ocurra, con un valor de 51,2 useg cada paso del incremento del timer. Si el valor que realmente quiere que ocurra para la interrupción es 172, entonces debes hacer set_timer (255 - fase);


----------



## chango107 (Jul 1, 2016)

Pues viendo sus consejos me he puesto en el trabajo de mirar mas las operaciones que esta realizando el micro, para eso separe operación por operación para validar si es algún problema en esos puntos, de lo cual tengo el siguiente programa 


```
#include<16f676.h>
#fuses NOWDT, NOPROTECT, NOBROWNOUT, NOMCLR, XT, PUT 
#device adc=8
#use delay (clock=4000000)

int8 fase=0,fase1;
int16 q, q1;

#INT_EXT
void sd_externa_rb0 (void)
{
   set_timer0(fase);
   enable_interrupts(INT_TIMER0);   
}

#INT_TIMER0
void sdi_desborde_timer0 (void)
{
   output_high(PIN_A1);
   delay_us(200);
   output_low(PIN_A1);
   disable_interrupts(INT_TIMER0);
}


void main()
{
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(sAN0);
   enable_interrupts(GLOBAL);
   setup_timer_0 (T0_INTERNAL|T0_DIV_32);
   enable_interrupts(INT_EXT);
   
   while(true)
   {
   set_adc_channel(0);
   delay_us(20);
   fase1 = read_adc();
   delay_us(20);
   q=(157*fase1);
   q1=q/255;
   fase=250-q;
   }
}
```

y simulando paso a paso con ayuda de proteus me di cuenta que las operaciones de multiplicación y división no se están ejecutando de manera correcta ya que la multiplicación se esta quedando con un valor de máximo 8 bits, y la división siempre da 0. ¿Que podría hacer?


----------



## ruben90 (Jul 1, 2016)

Tienes muchos errores de sintaxis,

```
int8 fase=0,fase1;
int16 q, q1;
...
while(true)
   {
   set_adc_channel(0);
   delay_us(20);
   fase1 = read_adc();
   delay_us(20); [B]//Según el datasheet del PIC16F877A, el tiempo typ. de adquisición es de 40uS.[/B]
   q=(157*fase1); [B]//Numero de 16 bits, OK.[/B]
   q1=q/255 [B]//Haces la operacion, pero a donde aplicas q1?[/B]
   fase=250-q; [B]//Restas un numero de 8 bits con uno de 16 bits?[/B]
   }
...
```


----------



## chango107 (Jul 1, 2016)

> delay_us(20); *//Según el datasheet del PIC16F877A, el tiempo typ. de adquisición es de 40uS.*



en cuanto al tiempo de adquisición si no lo tenia claro, ya lo subi a 40uS pero igual pues antes no me presentaba inconvenientes por esta adquisición. 



> q=(157*fase1); *//Numero de 16 bits, OK.*



la operación de q=(157*fase1); es un número de 16 bits, pero igual el resultado de la operación no es correcto dado que fase1 en el momento tiene un valor de 115 lo cual se multiplica por 157 y da 135 como muestra la imagen lo cual no es correcto.



> fase=250-q; *//Restas un numero de 8 bits con uno de 16 bits?*



 la variable q1 va es en la siguiente línea pido disculpas por mi error, pero al igual siempre el resultado de esa división me esta dando cero.

subo nuevamente la imagen pero mas detallada hacia las variables en simulación ya que antes no se veía muy bien


----------



## carferper (Jul 1, 2016)

puedes intentar algo asi si no requieres mucha presicion 


```
#include <16f688.h>
#include <stdint.h>
#device adc = 8
#use delay (internal = 8000000)

uint8_t flag = 0;

#INT_EXT
void ext_isr ()
	{
	flag = 1;
	}

void main()	
	{
	int16 c;
	setup_oscillator(OSC_8MHZ);

	output_low (PIN_C1);

	setup_adc (ADC_CLOCK_DIV_16);
	setup_adc_ports (sAN0, VSS_VDD);
	set_adc_channel (0);

	ext_int_edge (L_TO_H);
	enable_interrupts (INT_EXT);
	enable_interrupts (GLOBAL);

	setup_timer_0 (T0_DIV_64);

	while (TRUE)
		{
		if (flag)
			{
			read_adc (ADC_START_ONLY);
			delay_us(100);
			c = read_adc (ADC_READ_ONLY);

			if (c > 240) c = 240;
			if (c > 15)
				{
				set_timer0 (c);
				while (get_timer0());
				output_high (PIN_C1);
				delay_us(200);
				output_low (PIN_C1);
				}
			flag = 0;
			}
		}
	}
```

saludos


----------



## ruben90 (Jul 1, 2016)

chango107 dijo:


> la operación de q=(157*fase1); es un número de 16 bits, pero igual el resultado de la operación no es correcto dado que fase1 en el momento tiene un valor de 115 lo cual se multiplica por 157 y da 135 como muestra la imagen lo cual no es correcto.


Desconozco el porque, no tienes que declarar la librería _math.h_ o _stdint.h_ (para operaciones matemáticas) en este compilador? Como yo utilizo _mikroC_, no sabría decirte.


chango107 dijo:


> la variable q1 va es en la siguiente línea pido disculpas por mi error, pero al igual siempre el resultado de esa división me esta dando cero.


q1  = 135/255 = *0.53* _//como es variable entera solo muestra el cero._

El usuario _carferper_ te da una solución, pero si armas el circuito de seguro el LM7805 revienta (VImax = 25V). La resistencia de base para el transistor debera ser de 3W. Ademas recuerda que la frecuencia después del puente de diodos es el doble que el de la linea (120Hz).

*Debes tener precaución ya que es la red domestica (120V/220V).*


----------



## chango107 (Jul 1, 2016)

ruben90 dijo:


> Desconozco el porque, no tienes que declarar la librería math.h o stdint.h (para operaciones matemáticas) en este compilador? Como yo utilizo mikroC, no sabría decirte.]



Pues mira que lo habia intentado con anterioridad pero me presentaba inconvenientes al usar la declaración de _#device adc=8_, pero las declare nuevamente, elimine la línea que mencione anteriormente y ahora funciona sin ningún problema, hasta con el aporte del usuario _carferper_ complete la simulación 

Doy gracias a todos por la colaboración, interes y prontas respuestas, dejaré el código por aca para que otros puedan guiarse


----------



## Gerson strauss (May 23, 2022)

¿Alguno de nuestros queridos PIC tendrá ADC de 16 bits?


----------



## Scooter (May 23, 2022)

Mira en la web de microchip a ver.

Cuando un ADC tiene mucha resolución conlleva que el circuito de adaptación es caro y complejo.


----------



## Gerson strauss (May 24, 2022)

Scooter dijo:


> Mira en la web de microchip a ver.
> 
> Cuando un ADC tiene mucha resolución conlleva que el circuito de adaptación es caro y complejo.


Uso un 16f1827 y al parecer puede funcionar el ADC a 16 bits ... o casi. En Proteus el ADC tiene 65472 niveles de cuantificación (debería ser 65536) pero según entiendo el ADC solo es de 10 bits ¿entonces será de 10 o de 16? Gracias.


----------



## Eduardo (May 24, 2022)

Gerson strauss dijo:


> Uso un 16f1827 y al parecer puede funcionar el ADC a 16 bits ... o casi.



Es de *10bits.   *
Lo que tiene es justificación derecha --> lees un entero sin signo entre 0..1023
y justificación izquierda --> lees un entero sin signo entre 0..65472  pero en saltos de 64

 Me pregunto para qué necesitás de 16bit.


----------



## Gerson strauss (May 24, 2022)

Eduardo dijo:


> Es de *10bits. *
> Lo que tiene es justificación derecha --> lees un entero sin signo entre 0..1023
> y justificación izquierda --> lees un entero sin signo entre 0..65472 pero en saltos de 64


Entonces es mejor usarlo a 10 bits. 


Eduardo dijo:


> Me pregunto para qué necesitás de 16bit.


Para mas precisión. Gracias.


----------



## unmonje (May 24, 2022)

Gerson strauss dijo:


> Entonces es mejor usarlo a 10 bits.
> 
> Para mas precisión. Gracias.


Como te dicen, en la mayoría de los pics, los ADC llegan hasta 10 bits y  8/10, Cuando elijes 10 la administración es un poco mas engorrosa, pero sin problemas cuando te acostumbras.
Te tomas una tarde, escribes las rutinas una sola vez y las olvidas para siempre.
Yo las escribía para tener la opción de descartar los bits menos significativos y que así, no me baile el dígito inferior.   🤣
Para no volverse loco hay que ser bien prolijos en la estructura de las interrupciones, rutinas, subrutinas, saltos de página y sus retornos. Ojo al piojo.
Seguramente debe haber por ahí, controladores con ADC de mas bits, pero seguramente en gamas mas altas.


----------



## Dr. Zoidberg (May 24, 2022)

unmonje dijo:


> Seguramente debe haber por ahí, controladores con ADC de mas bits, pero seguramente en gamas mas altas.


Claro que hay, pero si con 16 bits usás una referencia de 5V eso significa que cada paso de conversión tiene 76 microvolts (5/65536)...te encargo  diseñar y construir un PCB que te permita aprovechar ese paso de conversión...


----------



## Lord Chango (May 24, 2022)

Pregunta @Gerson strauss, qué necesitas medir con tanta precisión?

Existe el HX711, es un ADC de 24bits, específico para celdas de carga, pero imagino que se podría adaptar para cualquier tipo de sensor tipo puente de Wheatstone. Este integrado se comunica por un protocolo serie similar a I2C, lo que ocuparía solamente dos pines del PIC.


----------



## Gerson strauss (May 24, 2022)

Lord Chango dijo:


> Pregunta @Gerson strauss, qué necesitas medir con tanta precisión?


Es que estoy haciendo un medidor de ESR con display LCD y pensé que con un ADC de 16 bits seria mas preciso,
pero a 10 bits igual funciona bien. Lo que hice fue unir en una variable word los registros ADRESL y ADRESH del
registro ADCON1 y justificar a la izquierda, y así leer el ADC en "16 bits" pero si tiene saltos entonces no me interesa.

En algún lado del foro leí que el usuario D@rkbytes había hecho un voltimetro con PIC que tenia resolución de 16 bits,
entonces pensé que también lo podía hacer en mi proyecto.

Nunca he usado un ADC externo... seria totalmente nuevo para mi. Gracias.


----------



## Scooter (May 24, 2022)

Gerson strauss dijo:


> Entonces es mejor usarlo a 10 bits.
> 
> Para mas precisión. Gracias.


Estudia un poco y verás que mas precisión trae problemas y puede que no traiga ventajas.


----------



## switchxxi (May 24, 2022)

Gerson strauss dijo:


> Es que estoy haciendo un medidor de ESR con display LCD y pensé que con un ADC de 16 bits seria mas preciso.



Yo vería primero cual es la tensión máxima que tendrás que medir porque lo mas probable es que no necesites mas bits sino una tensión de referencia mas chica.


----------



## Gerson strauss (May 24, 2022)

switchxxi dijo:


> Yo vería primero cual es la tensión máxima que tendrás que medir porque lo mas probable es que no necesites mas bits sino una tensión de referencia mas chica.


Tensión máxima = 3.7v  uso la referencia interna de 4.096v. Lo dejare en 10 bits, ahí mide bien. En el display se puede ver en la primera
linea a la derecha. El oscilador es de 100khz pero la simulación no corre bien "Simulation is not running in real time due to excessive CPU load."


----------



## unmonje (May 24, 2022)

La emulación es una herramienta de gran ayuda, como una aproximación rápida a lo real, pero no le pongan tantas fichas a eso porque, se van a dar de cabeza, con la Física Cuántica Universal Real, me temo.    🥴  🤣 Que a mis ojos es bastante mas compleja que una imitación.


----------



## FelML (May 24, 2022)

Eduardo dijo:


> Es de *10bits.   *
> Lo que tiene es justificación derecha --> lees un entero sin signo entre 0..1023
> y justificación izquierda --> lees un entero sin signo entre 0..65472  pero en saltos de 64
> 
> Me pregunto para qué necesitás de 16bit.


Lo de la justificación me da una idea.
Con un ADC, un DAC de 8bits ambos y un operacional restador puedes implementar un ADC de 16 bits en 3 pasos en un principio
1- leer la V de muestra con el ADC
2- restar ese valor a la V de muestra con el DAC y el restador
3- leer el valor residual de nuevo con el ADC

Esto último tal vez no sea posible y se necesite otro ADC con otro valor de tensión de referencia, o usar el mismo ADC con otra referencia. "Tema para estudiar".
Si los conversores son de 10bits se obtendrá en teoría una precisión de 20bits.
Suerte


----------



## MaShicO (May 25, 2022)

Gerson strauss dijo:


> ¿Alguno de nuestros queridos PIC tendrá ADC de 16 bits?


De la nueva gama de microchip de 8 bits ahora traen ADC de 12 bits.

No te fíes de la simulación de Proteus, impleméntalo y a ver como anda ...


----------



## Gerson strauss (May 25, 2022)

MaShicO dijo:


> De la nueva gama de microchip de 8 bits ahora traen ADC de 12 bits.


Uyyy buenisimo!!


MaShicO dijo:


> No te fíes de la simulación de proteus, implementalo y a ver como anda ...


Si, ahora lo pongo a funcionar a ver como se comporta. Gracias.


----------



## Gerson strauss (May 25, 2022)

Bueno, funciona igual que en la simulación. Estoy haciendo pruebas y las cosas están algo desordenadas.
Mi idea es mostrar el valor en ohmios de la ESR y es lo que se ve en el display como OH= , pero falta hacer la letra omega 
para que se vea mejor. También quiero mostrar la escala en porcentaje y por eso se ve ahí después de ESR=.

La B= es el valor de la batería de 9v, pero el circuito funciona con 5v. Seguro falta ajustar la escala también ... y 
el protoboard le da algo de inestabilidad, pero las pruebas son prometedoras. 

El ADC parece funcionar bien comparado con el multimetro, solo cambia el tercer decimal.
Las fotos (disculpen el desorden).

Condensador de 4700uf / 35v = 0.043 ohm




Condensador 2.2uf /50v malo = 9.5 ohm





condensador 3.3uf / 350v  =0.67 ohm





Cortocircuito


----------



## MaShicO (May 25, 2022)

Gerson strauss dijo:


> pero falta hacer la letra omega


Creo que en el foro existe temas para realizar caracteres personalizados en una lcd. En todo caso si no encuentras, quizás te pueda dar una mano.


----------



## Gerson strauss (May 25, 2022)

MaShicO dijo:


> Creo que en el foro existe temas para realizar caracteres personalizados en una lcd. En todo caso si no encuentras, quizás te pueda dar una mano.


Uso PROTON IDE y este tiene una aplicación para crear caracteres especiales, pero cualquier ayuda es bienvenida. Gracias.


----------



## ricbevi (May 25, 2022)

Gerson strauss dijo:


> Uso PROTON IDE y este tiene una aplicación para crear caracteres especiales, pero cualquier ayuda es bienvenida. Gracias.


No hace falta crear, es el carácter 244 de la tabla que ya tiene el propio LCD(al menos si es el estándar Hitachi y no estoy equivocado)



Hace algunos años lo use en este proyecto


```
Print At 4,5, Dec2 RBat,244," " ' Muestro la resistencia de la
```


%11110100 = 244 = $F4


----------



## Gerson strauss (May 25, 2022)

ricbevi dijo:


> No hace falta crear, es el carácter 244 de la tabla que ya tiene el propio LCD(al menos si es el estándar Hitachi y no estoy equivocado)


Ese también sirve, gracias. Ya había hecho uno (aunque parece unos audífonos  )... incluso hice otro para la batería.


----------

