TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: wannaky en 08 de Mayo de 2011, 19:12:12

Título: Problema con interrupción del puerto serie. [Solucionado]
Publicado por: wannaky en 08 de Mayo de 2011, 19:12:12
Buenas a todos,

tengo un problemilla con un código que estoy haciendo... el programa lee un valor del ADC y lo envía al puerto serie y a un LCD, y a su vez, cuando recibe algo por el puerto serie, se ejecuta la interrupción del puerto serie, lee el valor y lo muestra por el LCD.

pues resulta que todo funciona bien hasta que le envío un carácter por el puerto serie, que se queda colgado al entrar en la interrución...    :5] :5] :5]

este es el código, a ver si alguien me puede echar una mano y ve algún fallo


//Incluimos la libretia del PIC
#include "16F877A.h"

#device adc=10
//Configuramos el reloj a 4MHz
#use delay(clock=4000000)
#include "lcd.c"
//Configuramos los parámetros del puerto RS-232
#use rs232(baud=9600,parity=N,bits=8,stop=1,xmit=PIN_C6,rcv=PIN_C7)//,enable=PIN_D5)

#byte porta=0x05
#byte portb=0x06
#byte portc=0x07
#byte portd=0x08

//Configuramos los fuses adecuados
#fuses XT,NOWDT,NOPROTECT,PUT,NOLVP,BROWNOUT

#define PULSADOR pin_b6

int keypress=0, dato=0;

void borrar_lcd()
{
   lcd_gotoxy(1,1);
   printf(lcd_putc,"                ");
   lcd_gotoxy(1,2);
   printf(lcd_putc,"                ");
   lcd_gotoxy(1,1);
}

//directiva para interrupción del puerto serie
#int_rda
void rda_isr()
{
   dato=1;
}
void config(void)
{
   enable_interrupts(INT_RDA); //indicamos que queremos usar la int del serial
   enable_interrupts(GLOBAL); //habilitamos las interrupciones
}

//Programa principal
void main(void)
{
   int16 valor=0;
   float result=0;
   set_tris_b(0b01111111); //Configuramos el puerto B de entrada de B0-B6
   setup_adc_ports(ALL_ANALOG);
   setup_adc(ADC_CLOCK_INTERNAL);
   set_adc_channel(0);

   config();
   lcd_init();
   borrar_lcd();
   lcd_gotoxy(1,1);
   printf(lcd_putc,"Tension=");
  
   while(TRUE)
   {
      valor=read_adc();
      result=(valor/168.4);
      lcd_gotoxy(9,1);
      printf(lcd_putc,"%2.2fv \n",result);
      delay_ms(100);
      printf("%2.2f v \n\r"result);
      if(dato==1)
      {
         keypress=getc();
         lcd_gotoxy(1,2);
         printf(lcd_putc,"%u",keypress);
         dato=0;
      }
   }
}


supongo que no debo estar configurando bien la interrupción, pero yo no veo el fallo...
espero haberme explicado,

un saludo y gracias...
Título: Re: Problema con interrupción del puerto serie.
Publicado por: wannaky en 08 de Mayo de 2011, 19:14:26
otra cosa, utilizo un programilla que se llama "ComPort Library example" para monitorizar el puerto COM (lo adjunto aquí...)  lo comento por si pudiese ser problema del programa este...

gracias
Título: Re: Problema con interrupción del puerto serie.
Publicado por: PalitroqueZ en 08 de Mayo de 2011, 19:27:58
una idea:

cuando dato==1 haz disabled_interrupts(int_rda) y antes de salir del condicional, haz enabled_interrups(int_rda)
Título: Re: Problema con interrupción del puerto serie.
Publicado por: wannaky en 09 de Mayo de 2011, 07:25:13
una idea:

cuando dato==1 haz disabled_interrupts(int_rda) y antes de salir del condicional, haz enabled_interrups(int_rda)

Hola PalitroqueZ, he probado lo que me has comentado y nada de nada...

Código: [Seleccionar]
#int_rda
void rda_isr()
{
   disable_interrupts(GLOBAL);
   dato=1;
   printf(lcd_putc,"P");
   enable_interrupts(GLOBAL);
}
también he hecho que envíe una 'P' al LCD para ver si entra o no entra a la interrupción, y he visto que si, pero me llena el LCD de PPPPPPPPPPPPPPPPPPPPPPP, como si al entrar la primera vez se quedase colgado y entrando siempre...

alguien tiene idea de que puede ser?!?!?!  :huh: :huh: :huh:
Título: Re: Problema con interrupción del puerto serie.
Publicado por: AngelGris en 09 de Mayo de 2011, 10:02:02
  Creo que Palitroquez se refiere al "if (dato == 1)" que tenés en el bucle principal, y no a la rutina de interrupción
Título: Re: Problema con interrupción del puerto serie.
Publicado por: wannaky en 09 de Mayo de 2011, 10:38:36
aaaahhh... vale vale... jejeje... :z) :z) :z)   esta tarde cuando llegué lo probaré, a ver que tal

gracias...
Título: Re: Problema con interrupción del puerto serie.
Publicado por: wannaky en 09 de Mayo de 2011, 11:03:33
una idea:

cuando dato==1 haz disabled_interrupts(int_rda) y antes de salir del condicional, haz enabled_interrups(int_rda)

pero no entiendo porqué tendría que funcionar así?!?!?!  no le veo la lógica :shock: :shock: :shock: :shock:  pero lo probaré, que no pierdo nada y ya os comentaré...
Título: Re: Problema con interrupción del puerto serie.
Publicado por: AngelGris en 09 de Mayo de 2011, 11:06:00
  Es para evitar que haya otra llamada a la interrupción, mientras estás escribiendo el dato en el LCD.
Título: Re: Problema con interrupción del puerto serie.
Publicado por: PalitroqueZ en 09 de Mayo de 2011, 12:25:36
si es como dice Angelgris,

pues si que esta raro wannaky, entonces intenta enviar y recibir solo datos y no utilices la lcd a ver como va
Título: Re: Problema con interrupción del puerto serie.
Publicado por: Tisco en 09 de Mayo de 2011, 15:10:56
Hola,
yo no he usado nunca CCS, pero no veo que borres el flag de interrupcion de recepcion del puerto serie (a no ser que lo haga automaticamente el compilador al entrar en la rutina de interrupcion) Si no borras el flag, es normal que este a entrar y salir seguido de la misma. Supongo que si usas getc(); en la propia rutina de interrupcion ya te borrara el flag (habria que ver como funciona en ese compilador exactamente), si no hazlo de forma manual.
un saludo!
Título: Re: Problema con interrupción del puerto serie.
Publicado por: wannaky en 10 de Mayo de 2011, 11:10:10
Buenas,

he probado de deshabilitar al entrar en el if(dato==1) i habilitar al salir y me continua fallando... yo creo que ha de ser problema de lo que comenta Tisco, que no le digo al pic mediante un flag que la interrupción ya se ha procesado, y por eso se queda continuamente ejecutando el código que hay en la interrupción.

Alguien sabe que bit es el que he de setear para indicarle al pic que ya se ha ejecutado el código de la interrupción y de esta forma solo se haga una vez.
programa en CCS

gracias y un saludo...
Título: Re: Problema con interrupción del puerto serie.
Publicado por: jukinch en 10 de Mayo de 2011, 13:29:59
Probaste sacar de la interrupción la escritura del LCD? Postea el código de la interrupción Para ver como quedó.
Saludos.
              Jukinch
Título: Re: Problema con interrupción del puerto serie.
Publicado por: Tisco en 10 de Mayo de 2011, 14:48:11
Hola de nuevo,
el bit que te indica que hay un nuevo dato en el buffer de recepcion se setea automaticamente por hardware, tu lo que tienes es que resetearlo por software.
En el 16F877A dicho bit es el RCIF del registro PIR1.
De todas formas estaria bien que pusieses el codigo como dice Jukinch para ver que estas haciendo.
un saludo!
Título: Re: Problema con interrupción del puerto serie.
Publicado por: wannaky en 10 de Mayo de 2011, 16:05:35
Buenas, este es el código que he probado ahora mismo...
Código: [Seleccionar]
//Incluimos la libretia del PIC
#include "16F877.h"

#device adc=10
//Configuramos el reloj a 4MHz
#use delay(clock=4000000)
#include "lcd.c"
//Configuramos los parámetros del puerto RS-232
#use rs232(baud=9600,parity=N,bits=8,stop=1,xmit=PIN_C6,rcv=PIN_C7)//,enable=PIN_D5)

#byte porta=0x05
#byte portb=0x06
#byte portc=0x07
#byte portd=0x08

//Configuramos los fuses adecuados
#fuses NOWDT, XT, NOPUT, NOPROTECT, NOBROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG

char keypress=0;
int dato=0;

void borrar_lcd()
{
   lcd_gotoxy(1,1);
   printf(lcd_putc,"                ");
   lcd_gotoxy(1,2);
   printf(lcd_putc,"                ");
   lcd_gotoxy(1,1);
}

//directiva para interrupción del puerto serie
#int_rda
void rda_isr()
{
   dato=1;
   keypress=getc();
   printf(lcd_putc,"%c",keypress);
}
void config(void)
{
   enable_interrupts(GLOBAL); //habilitamos las interrupciones
   enable_interrupts(INT_RDA); //indicamos que queremos usar la int del serial
}

//Programa principal
void main(void)
{
   int16 valor=0;
   float result=0;
   set_tris_b(0b01111111); //Configuramos el puerto B de entrada de B0-B6
   setup_adc_ports(ALL_ANALOG);
   setup_adc(ADC_CLOCK_INTERNAL);
   set_adc_channel(0);

   config();
   lcd_init();
   borrar_lcd();
   printf(lcd_putc,"Tension=");
   
   while(TRUE)
   {
      valor=read_adc();
      result=(valor/168.4);
      lcd_gotoxy(9,1);
      printf(lcd_putc,"%2.2fv \n",result);
      delay_ms(100);
      printf("%2.2f v \n\r"result);
      if(dato==1)
      {
         dato=0;
      }
   }
}


La cuestión es que así funciona y de esta otra manera no --->  :5] :5] :5] :5]

Código: [Seleccionar]
#include "16F877.h"

#device adc=10
//Configuramos el reloj a 4MHz
#use delay(clock=4000000)
#include "lcd.c"
//Configuramos los parámetros del puerto RS-232
#use rs232(baud=9600,parity=N,bits=8,stop=1,xmit=PIN_C6,rcv=PIN_C7)//,enable=PIN_D5)

#byte porta=0x05
#byte portb=0x06
#byte portc=0x07
#byte portd=0x08

//Configuramos los fuses adecuados
#fuses NOWDT, XT, NOPUT, NOPROTECT, NOBROWNOUT, NOLVP, NOCPD, NOWRT, NODEBUG

//#define PULSADOR pin_b6

char keypress=0;
int dato=0;

void borrar_lcd()
{
   lcd_gotoxy(1,1);
   printf(lcd_putc,"                ");
   lcd_gotoxy(1,2);
   printf(lcd_putc,"                ");
   lcd_gotoxy(1,1);
}

//directiva para interrupción del puerto serie
#int_rda
void rda_isr()
{
   dato=1;
}
void config(void)
{
   enable_interrupts(GLOBAL); //habilitamos las interrupciones
   enable_interrupts(INT_RDA); //indicamos que queremos usar la int del serial
}

//Programa principal
void main(void)
{
   int16 valor=0;
   float result=0;
   set_tris_b(0b01111111); //Configuramos el puerto B de entrada de B0-B6
   setup_adc_ports(ALL_ANALOG);
   setup_adc(ADC_CLOCK_INTERNAL);
   set_adc_channel(0);

   config();
   lcd_init();
   printf(lcd_putc,"Tension=");
   
   while(TRUE)
   {
      valor=read_adc();
      result=(valor/168.4);
      lcd_gotoxy(9,1);
      printf(lcd_putc,"%2.2fv \n",result);
      delay_ms(100);
      printf("%2.2f v \n\r"result);
      if(dato==1)
      {
         keypress=getc();
         lcd_gotoxy(1,2);
         printf(lcd_putc,"%c",keypress);
         dato=0;
      }
   }
}

Lo único que he hecho ha sido en lugar de leer el carácter enviado por el serie desde el main, lo he leído directamente en la interrupción, pero así no me gusta, porque quiero ejecutar el mínimo código posible dentro de la interrupción, quiero que todo se ejecute en el main...

pero no se comoooooooooooo!!!!!!!!! :? :? :? :? :? :? :? :?

Tisco, como trabajo en CCS sobre ese bit o ese registro?!?!?! en ASM si que lo he hecho, pero en CCS no se como... sabes de algún manual?!?!!?!

gracias, y nos vemos... ;-) ;-) ;-)
Título: Re: Problema con interrupción del puerto serie.
Publicado por: AngelGris en 10 de Mayo de 2011, 19:45:59
  Es que si no lees el dato dentro de la rutina de interrupción no se te va a borrar el flag de la misma y por lo tanto vas a estar reentrando constantemente.
Título: Re: Problema con interrupción del puerto serie.
Publicado por: MLO__ en 10 de Mayo de 2011, 23:24:48
Hola.

Debes usar, como ya te dijeron, la función getc() en la interrupción.

Para que el código se procese en el main, asigna un flag en la interrupción, luego de recibir el dato. No es recomendable tener funciones que tomen mucho tiempo dentro de la interrupción (como ese printf) ... me imagino que al compilar, te salen algunos warning's.

Saludos
Título: Re: Problema con interrupción del puerto serie.
Publicado por: wannaky en 11 de Mayo de 2011, 05:31:04
ok ok, gracias MLO_ y AngelGris, ya funciona :-/ :-/ :-/ :-/   Lo que no sabia es que era el getc() el que automáticamente borraba el flag de la interrupción.

saludos... 
Título: Re: Problema con interrupción del puerto serie.
Publicado por: AngelGris en 11 de Mayo de 2011, 08:33:50
ok ok, gracias MLO_ y AngelGris, ya funciona :-/ :-/ :-/ :-/   Lo que no sabia es que era el getc() el que automáticamente borraba el flag de la interrupción.

saludos... 

  El bit RCIF (que es el flag de interrupción por recepción) se borra automáticamente al leer el registro RCREG, que es lo que hace getc()
Título: Re: Problema con interrupción del puerto serie.
Publicado por: wannaky en 11 de Mayo de 2011, 08:37:59
  El bit RCIF (que es el flag de interrupción por recepción) se borra automáticamente al leer el registro RCREG, que es lo que hace getc()

ok, entendido!!! :-) :-) :-)