Autor Tema: Ayuda Programación ADCs del PIC16F877-20/P + interrupción + integrador  (Leído 6468 veces)

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

Desconectado danipic19

  • PIC10
  • *
  • Mensajes: 15
Buenas,

Me presento, soy nuevo en el foro, y aunque llevo un par de meses que os visito nunca había escrito ningún post. Tengo un problema: a principios de la semana que viene tengo que entregar el proyecto final de carrera y no consigo programar el PIC16F877-20/p (el de 40 pines).

A continuación descrivo los problemas y adjunto el código que he hecho. Por cierto, los comentarios no estan muy bien hechos...

1. ADCs. Necesito leer 3 señales analógicas, y diría que lo consigo pero creo que tarda mucho, ya que para realizar el programa después de leer estas señales me tarda unos 40 segundos... Creo que el ADC está mal configurado.


#include <16f877A.h>

#device ADC=8 // ADC devuelven 8 bits
#fuses NOPROTECT,NOCPD,NOLVP,NOWDT,XT,PUT //Configuracion de timers, reloj, proteccion de datos...

#use fast_io (A) //Input y output sin reprogramar los pines, como lo haria el #use standard_io
#use fast_io (B)
#use delay(clock=20000000) //Reloj de 4MHz
#use standard_io(A)
#use standard_io(B)
#use standard_io(C)
#use standard_io(D)
#use standard_io(E)

#int_rtcc //rutina que até a interrupció

int8 sensor1, sensor2, consigna, sortida; //Variables para el resultado de la conversión AD
float sens1d, sens2d, consd;
float K1, K2, K3, vh1pt, vh2pt, conspt, vpt;
float incvh1, incvh2, incvcons, incK1, incK2, incK3, invconsfinal, out1, inputact=0, integrador;
float inputant=0, integant=0, out2, outfinal;

void main()
{
//Se activa el ADC y se selecciona el canal RA0/AN0. Frecuencia de trabajo Fosc/32
set_tris_b(0x00);   //portb como salida(RB0,las demas desactivadas)
set_tris_e(0x07);
set_tris_d(0x00);
disable_interrupts(GLOBAL);   //todas las interrupciones desactivadas
output_b(0x00);
output_d(0x00);
setup_adc(ADC_CLOCK_DIV_16); //Ajusta frecuencia de muestreo del ADC

setup_adc_ports(AN0);

K1=-0.443;
K2=-2.129;
K3=-22.76;
vh1pt=3.06;
vh2pt=3.95;
conspt=vh2pt;
vpt=7.8;

//PROGRAMA PRINCIPAL

while(1)
{

set_adc_channel(0); //Selección del canal 0 (RA0)
delay_us(10); //Temporiza 10uS
sensor1=read_adc(); //Inicia la conversión y lee el resultado
sens1d=sensor1;

set_adc_channel(1); //Selección del canal 0 (RA0)
delay_us(10); //Temporiza 10uS
sensor2=read_adc(); //Inicia la conversión y lee el resultado
sens2d=sensor2;

set_adc_channel(2); //Selección del canal 0 (RA0)
delay_us(10); //Temporiza 10uS
consigna=read_adc(); //Inicia la conversión y lee el resultado
consd=consigna;

incvh1=sens1d-vh1pt;
incvh2=sens2d-vh2pt;
incvcons=consd-conspt;
invconsfinal=incvh2-incvcons;
incK2=K2*incvh1;
incK3=K3*incvh2;
out1=incK1+incK2;

inputact=invconsfinal;
integrador=integant+((inputact+inputant)*(1/2));//1=3.138 si interrupció
inputant=inputact;
integant=integrador;

out2=invconsfinal*K1*integrador;
outfinal=out2+out1+vpt;
sortida=outfinal*256/10;
output_b(sortida);
}
}


De esta manera cre que hacen algo. Si los configuro como he visto en numerosos ejemplos me dice que no reconoce AN1 y AN2:

setup_adc_ports(AN0); //RA0 entrada analógica
set_adc_channel(0); //Selección del canal 0 (RA0)
delay_us(10); //Temporiza 10uS
sensor1=read_adc(); //Inicia la conversión y lee el resultado
sens1d=sensor1;

setup_adc_ports(AN1); //RA1 entrada analógica
set_adc_channel(1); //Selección del canal 1 (RA1)
delay_us(10); //Temporiza 10uS
sensor2=read_adc(); //Inicia la conversión y lee el resultado
sens2d=sensor2;

setup_adc_ports(AN2); //RA2 entrada analógica
set_adc_channel(2); //Selección del canal 2 (RA2)
delay_us(10); //Temporiza 10uS
consigna=read_adc(); //Inicia la conversión y lee el resultado
consd=consigna;

2. Interrupción: Todo mi porograma debería estar dentro de una interrupción, ya que lo quiero "ejecutar" cada 5 segundos:

Con el código que pongo a continuación obtengo una interrupción cada 3,138 segundos aproximadamente y lo que hago es cambiar de estado el puerto_b, cosa que veo imposible con un TIMER0 de 8 bits y el valor de preescaler que le doy:

#include <16f877.h>

#fuses NOPROTECT,NOCPD,NOLVP,NOWDT,XT,PUT //Configuracion de timers, reloj, proteccion de datos...

#use fast_io (A) //Input y output sin reprogramar los pines, como lo haria el #use standard_io
#use fast_io (B)
#use delay(clock=20000000) //Reloj de 4MHz
#use standard_io(A)
#use standard_io(B)
#use standard_io(C)
#use standard_io(D)
#use standard_io(E)

byte puerto_b;

#int_rtcc //rutina que até a interrupció

void interrupcion()
{
puerto_b=~puerto_b;
output_b(puerto_b);
set_RTCC(0);
}

void main()
{
set_tris_b(0x00);
puerto_b=0x00;
output_b(puerto_b);

setup_counters (RTCC_INTERNAL, RTCC_DIV_4); //programació timer0
set_RTCC(0);
enable_interrupts(INT_RTCC); // Habilita interrupcion timer0.
enable_interrupts(GLOBAL); // Habilita todas las interrupciones.

while(1)
{
}
}


Sé que hago algo mal, que no configuro bien el timer o lo que sea, lo he probado con el TIMER1 que es de 16 bits y tampoco consigo que funcione...


3. Integrador: Quien tenga conocimientos de regulación automàtica lo conocerà mejor. La fórmula bàsica del integrador es:

integrador=integant+((inputact+inputant)*(T/2));

donde:

integant=integrador anterior
inputact=entrada actual
inputant=entrada anterior
T=periodo que pasa entre que hace el cálculo hasta que lo vuelve a realizar.

El problema que tengo es que no sé como encontrar el valor de T... Si lo hiciera dentrro de una interrupción de 5 segundos pues T sería 5 segundos aproximadamente.

Alguien me puede ayudar?

Gracias de antemano.

Saludos!

Desconectado danipic19

  • PIC10
  • *
  • Mensajes: 15
Re: Ayuda Programación ADCs del PIC16F877-20/P + interrupción + integrador
« Respuesta #1 en: 14 de Enero de 2010, 12:20:20 »
Por cierto, para la configuración de los ADCs si lo hago de la segunda forma, como los ejemplos que he visto, y en vez de incluir la libreria del 16F877 añado la del 16F877A no me da errores al compilar, pero entonces no creo que pueda programar el PIC...

Desconectado jhozate

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1698
Re: Ayuda Programación ADCs del PIC16F877-20/P + interrupción + integrador
« Respuesta #2 en: 14 de Enero de 2010, 13:15:40 »
cuando usas cristal de 20Mhz el fuse debe ser HS.
Saludos
Ser Colombiano es un Premio, Saludos desde CALI-COLOMBIA

Desconectado danipic19

  • PIC10
  • *
  • Mensajes: 15
Re: Ayuda Programación ADCs del PIC16F877-20/P + interrupción + integrador
« Respuesta #3 en: 14 de Enero de 2010, 13:28:16 »
Hola jhozate,

Te refieres a cambiar esto:

#fuses NOPROTECT,NOCPD,NOLVP,NOWDT,XT,PUT //Configuracion de timers, reloj, proteccion de datos...

Por esto?

#HS NOPROTECT,NOCPD,NOLVP,NOWDT,XT,PUT //Configuracion de timers, reloj, proteccion de datos...

Desconectado danipic19

  • PIC10
  • *
  • Mensajes: 15
Re: Ayuda Programación ADCs del PIC16F877-20/P + interrupción + integrador
« Respuesta #4 en: 14 de Enero de 2010, 13:34:58 »
O esto?

#fuses NOPROTECT,HS,NOCPD,NOLVP,NOWDT,XT,PUT //Configuracion de timers, reloj, proteccion de datos...

Desconectado jhozate

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1698
Re: Ayuda Programación ADCs del PIC16F877-20/P + interrupción + integrador
« Respuesta #5 en: 14 de Enero de 2010, 13:40:32 »
si, pero elimina el XT.
Adicionalmente te falta configurar tus canales analogos, necesitas tres y solo has puesto AN0.
Si quieres lograr 5 segundos puedes hacer una base de tiempo y sobre esa contar multiples interrrupciones hasta lograr 5 segundos.
Ser Colombiano es un Premio, Saludos desde CALI-COLOMBIA

Desconectado danipic19

  • PIC10
  • *
  • Mensajes: 15
Re: Ayuda Programación ADCs del PIC16F877-20/P + interrupción + integrador
« Respuesta #6 en: 14 de Enero de 2010, 13:43:53 »
Los canales analògicos en teoria se confuguran como muestro a continuación, pero al compilar me dice que no reconoce AN1 y AN2, en cambio para AN0 no dice nada:

setup_adc_ports(AN0); //RA0 entrada analógica
set_adc_channel(0); //Selección del canal 0 (RA0)
delay_us(10); //Temporiza 10uS
sensor1=read_adc(); //Inicia la conversión y lee el resultado
sens1d=sensor1;

setup_adc_ports(AN1); //RA1 entrada analógica
set_adc_channel(1); //Selección del canal 1 (RA1)
delay_us(10); //Temporiza 10uS
sensor2=read_adc(); //Inicia la conversión y lee el resultado
sens2d=sensor2;

setup_adc_ports(AN2); //RA2 entrada analógica
set_adc_channel(2); //Selección del canal 2 (RA2)
delay_us(10); //Temporiza 10uS
consigna=read_adc(); //Inicia la conversión y lee el resultado
consd=consigna;


Lo de crear la base de tiempo de 5 segundos no lo entiendo (soy muy novato)...

Gracias por la ayuda!

Desconectado jhozate

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1698
Re: Ayuda Programación ADCs del PIC16F877-20/P + interrupción + integrador
« Respuesta #7 en: 14 de Enero de 2010, 13:59:07 »
Si no me equivoco no puedes escoger arbitrariamente el canal analogo, verifica la hoja de datos del pic y te daras cuenta q hay restricciones con ello. Asi que debes definirlo, si quieres 3 canales
entonces podria ser asi:
Código: [Seleccionar]
setup_adc(adc_clock_div_16);
setup_adc_ports(AN0_AN1_AN3)  //obligado si solo quieres 3 canales, hoja de datos

y cuando necesites leerlos solo haces
Citar
set_adc_channel(0);
valor=read_adc();
delay_us(10);
set_adc_channel(1);
valor1=read_adc();
delay_us(10);
set_adc_channel(3);
valor3=read_adc();

la base de tiempo puedes generarla con el timer0, por ejemplo para lograr 100mS, puedes hacer una de base de tiempo de 50mS, y contarla dos veces:

Citar
#int_timer0
void timer0_isr()
{
i++;
if(i==2) // verificas si ya pasaron dos interrupciones de 50mS
  {
  ....aqui lo q quieres hacer
  }
set_timer(cargar_del_timer);

}
Ser Colombiano es un Premio, Saludos desde CALI-COLOMBIA

Desconectado fidodido18

  • PIC18
  • ****
  • Mensajes: 312
Re: Ayuda Programación ADCs del PIC16F877-20/P + interrupción + integrador
« Respuesta #8 en: 14 de Enero de 2010, 14:24:20 »
revisa el archivo 16f877A.h ahí te indican cuales son las posibilidades que tienes para configurar el puerto analógico y todo lo demás.

Desconectado danipic19

  • PIC10
  • *
  • Mensajes: 15
Re: Ayuda Programación ADCs del PIC16F877-20/P + interrupción + integrador
« Respuesta #9 en: 14 de Enero de 2010, 14:28:15 »
Gracias a todos por la ayuda.

Acabo de ir a comprar un cristal de 4MHz por si acaso (el que usáis la mayoría de vosotros).

Ahora voy a probar lo que me habéis enseñado. SI no funciona le cambio el cristal al PIC y vuelvo a probar.

Agradezco muchísimo vuestra ayuda.

Si acaba funcionando os tendré que invitar a unas birras!

Desconectado danipic19

  • PIC10
  • *
  • Mensajes: 15
Re: Ayuda Programación ADCs del PIC16F877-20/P + interrupción + integrador
« Respuesta #10 en: 14 de Enero de 2010, 14:51:27 »
Os comento,

El ADC funciona pero programando con el siguiente código me da la misma salida en el puerto_b tanto si entro la entrada analógica por AN0, como por AN1, como por AN3,  y sólo le doy orden de que de salida al puerto_b con AN3. :S

Por qué pasa esto?

while(1)
{
setup_adc_ports(AN0_AN1_AN3); //RA0 entrada analógica
set_adc_channel(0); //Selección del canal 0 (RA0)
delay_us(10); //Temporiza 10uS
resultado1=read_adc(); //Inicia la conversión y lee el resultado
//output_b(resultado1);

set_adc_channel(1); //Selección del canal 0 (RA0)
delay_us(10); //Temporiza 10uS
resultado2=read_adc(); //Inicia la conversión y lee el resultado
//output_b(resultado2);

set_adc_channel(2); //Selección del canal 0 (RA0)
delay_us(10); //Temporiza 10uS
resultado3=read_adc(); //Inicia la conversión y lee el resultado
output_b(resultado3);

Desconectado danipic19

  • PIC10
  • *
  • Mensajes: 15
Re: Ayuda Programación ADCs del PIC16F877-20/P + interrupción + integrador
« Respuesta #11 en: 14 de Enero de 2010, 15:12:16 »
Perdón, tampoco hace lo de antes... Le digo que ponga en el port_b el resultado3, y para una entrada analógica en AN0 y en AN1 pone el resultado en el port_b (cosa que no tendría que hacer), y para entrada analógica en AN3 no hace nada... Me había equivocado en el código ya que en la última lectura había puesto set_adc_channel(2) y es set_adc_channel(3), pero aun así hace el tonto...

while(1)
{
setup_adc_ports(AN0_AN1_AN3); //RA0 entrada analógica
set_adc_channel(0); //Selección del canal 0 (RA0)
delay_us(10); //Temporiza 10uS
resultado1=read_adc(); //Inicia la conversión y lee el resultado
//output_b(resultado1);

set_adc_channel(1); //Selección del canal 0 (RA0)
delay_us(10); //Temporiza 10uS
resultado2=read_adc(); //Inicia la conversión y lee el resultado
//output_b(resultado2);

set_adc_channel(3); //Selección del canal 0 (RA0)
delay_us(10); //Temporiza 10uS
resultado3=read_adc(); //Inicia la conversión y lee el resultado
output_b(resultado3);

Desconectado danipic19

  • PIC10
  • *
  • Mensajes: 15
Re: Ayuda Programación ADCs del PIC16F877-20/P + interrupción + integrador
« Respuesta #12 en: 14 de Enero de 2010, 15:16:06 »
Ahora me pone en el port_b el resultado tanto si entro la entrada analògica en AN0 ó AN1 ó AN3. Pongo el código completo para ver si encontráis el error (yo no lo encuentro...):

#include <16f877.h>


#device ADC=8 // ADC devuelven 8 bits
#fuses NOPROTECT,HS,NOCPD,NOLVP,NOWDT //Configuracion de timers, reloj, proteccion de datos...


#use fast_io (A) //Input y output sin reprogramar los pines, como lo haria el #use standard_io
#use fast_io (B)
#use delay(clock=20000000) //Reloj de 20MHz

int8 resultado0, resultado1, resultado3; //Variable para el resultado de la conversión AD

void main()
{

//Se activa el ADC y se selecciona el canal RA0/AN0. Frecuencia de trabajo Fosc/32
set_tris_b(0x00);   //portb como salida(RB0,las demas desactivadas)
set_tris_d(0x00);
disable_interrupts(GLOBAL);   //todas las interrupciones desactivadas
output_b(0x00);
output_d(0x00);
setup_adc(adc_clock_div_8); //Ajusta frecuencia de muestreo del ADC

while(1)
{
setup_adc_ports(AN0_AN1_AN3); //RA0 entrada analógica
set_adc_channel(0); //Selección del canal 0 (RA0)
delay_us(10); //Temporiza 10uS
resultado0=read_adc(); //Inicia la conversión y lee el resultado
//delay_us(10); //Temporiza 10uS
//output_b(resultado0);

set_adc_channel(1); //Selección del canal 0 (RA0)
delay_us(10); //Temporiza 10uS
resultado1=read_adc(); //Inicia la conversión y lee el resultado
//delay_us(10); //Temporiza 10uS
//output_b(resultado1);

set_adc_channel(3); //Selección del canal 0 (RA0)
delay_us(10); //Temporiza 10uS
resultado3=read_adc(); //Inicia la conversión y lee el resultado
//delay_us(10); //Temporiza 10uS
output_b(resultado3);

}
}
« Última modificación: 14 de Enero de 2010, 15:55:42 por danipic19 »

Desconectado danipic19

  • PIC10
  • *
  • Mensajes: 15
Re: Ayuda Programación ADCs del PIC16F877-20/P + interrupción + integrador
« Respuesta #13 en: 14 de Enero de 2010, 15:31:47 »
Si entro 3 entradas analógicas a los pines AN0, AN1 y AN3 al mismo tiempo, manda la primera entrada que entro, es decir, que en el port_b obtengo la primera entrada que he conectado... :S
« Última modificación: 14 de Enero de 2010, 15:36:35 por danipic19 »

Desconectado danipic19

  • PIC10
  • *
  • Mensajes: 15
Re: Ayuda Programación ADCs del PIC16F877-20/P + interrupción + integrador
« Respuesta #14 en: 14 de Enero de 2010, 15:52:09 »
Punto 1 resuelto!

El problema es que no se pueden dejar las entradas analógicas al aire! Hay que conectarlas como mínimo a masa!

Ahora a por el punto 2!


 

anything