TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado 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...
-
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
-
una idea:
cuando dato==1 haz disabled_interrupts(int_rda) y antes de salir del condicional, haz enabled_interrups(int_rda)
-
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...
#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:
-
Creo que Palitroquez se refiere al "if (dato == 1)" que tenés en el bucle principal, y no a la rutina de interrupción
-
aaaahhh... vale vale... jejeje... :z) :z) :z) esta tarde cuando llegué lo probaré, a ver que tal
gracias...
-
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é...
-
Es para evitar que haya otra llamada a la interrupción, mientras estás escribiendo el dato en el LCD.
-
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
-
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!
-
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...
-
Probaste sacar de la interrupción la escritura del LCD? Postea el código de la interrupción Para ver como quedó.
Saludos.
Jukinch
-
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!
-
Buenas, este es el código que he probado ahora mismo...
//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]
#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... ;-) ;-) ;-)
-
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.
-
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
-
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...
-
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()
-
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!!! :-) :-) :-)