Conversor ADC del PIC

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.
 

Adjuntos

  • Circuito.jpg
    Circuito.jpg
    153.2 KB · Visitas: 23
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

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 :confused:

---- Actualizado ----

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

Código:
#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
 
Última edición por un moderador:
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.
 
Última edición:
Código:
#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.
 
Última edición:
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
Código:
#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? :cry:
 

Adjuntos

  • Circuito.jpg
    Circuito.jpg
    98 KB · Visitas: 9
he realizado estos cambios pero persiste el inconveniente, que otro cambio podria realizar?

Código:
#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)
   {

   }
}
 
Última edición:
El inconveniente me parece proviene de aquí,
Código:
#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?
Código:
while(true)
   {

   }
 
Última edición:
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

Código:
#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
 
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);
 
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

Código:
#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?
 

Adjuntos

  • Circuito.jpg
    Circuito.jpg
    105.3 KB · Visitas: 6
Tienes muchos errores de sintaxis,
Código:
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]
   }
...
 
Última edición:
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 :cry:
 

Adjuntos

  • Circuito.JPG
    Circuito.JPG
    130.9 KB · Visitas: 6
puedes intentar algo asi si no requieres mucha presicion

PHP:
#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
 

Adjuntos

  • capture-1.avi.zip
    1.8 MB · Visitas: 8
  • Screenshot 1.jpg
    Screenshot 1.jpg
    132 KB · Visitas: 12
  • Screenshot 2.jpg
    Screenshot 2.jpg
    134 KB · Visitas: 12
  • Screenshot 3.jpg
    Screenshot 3.jpg
    133.3 KB · Visitas: 8
  • Screenshot 4.jpg
    Screenshot 4.jpg
    133.4 KB · Visitas: 8
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.
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).
 
Última edición:
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 :aplauso:

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

Adjuntos

  • Circuito.jpg
    Circuito.jpg
    103.7 KB · Visitas: 9
  • Cto disparo.zip
    62.4 KB · Visitas: 12
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.
 
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.

ADC16.jpg
 
Atrás
Arriba