Autor Tema: ¿Qué hago mal en este sencillo programa?  (Leído 5119 veces)

0 Usuarios y 3 Visitantes están viendo este tema.

Desconectado ariznaf

  • PIC10
  • *
  • Mensajes: 23
¿Qué hago mal en este sencillo programa?
« en: 19 de Marzo de 2010, 07:04:44 »
Estimados foreros, este es mi primer mensaje en el foro.

Así que empiezo por presentarme: soy ingeniero de minas y profesor de Universidad (en la rama de Geotecnia).

El caso es que estamos desarrollando un proyecto sobre medida de convergencias en túneles, y hemos decidido utilizar encoders para hacerlo y pics para realizar las medidas proporcionadas por ellos.

El caso es que tengo experiencia en programación C (bastante) y alguna pequeña experiencia previa con pics (pequeña y hace años).

Pues el caso es que tengo bastantes problemas para hacer algo tan sencillo como que el pic se interrumpa cuando recibe un caracter de la puerta serie, establezca un flag para advertirlo y luego procese ese caracter en el programa principal (en el programa de ejemplo simplemente lo vuelve a escribir en el puerto serie).

A ver si ustedes me pueden ayudar, por que la verdad es que ya llevo más de una semana peleando con esto, pensando que era problema del depurador o que el pic estaba estropeado... está claro que soy yo el estropeado  :D

Mi entorno de trabajo es:
Compilador CCS C 4.104
Entorno MPLAB 8.43 con plugin para compilar con CCS
Depurador: ICD-PIC clon compatible con Pickit2
PIC: PIC16F876A
Tarjeta de pruebas: PIC-School

Este es el programa (lo he simplificado al máximo) que no me funciona:
Código: [Seleccionar]
#include <16f876A.h>

//Ajusta los valores de la palabra de configuración durante el ensamblaje:
//Protección de código y datos=OFF, LVP=OFF, WDT=OFF y OSC=XT

#fuses NOPROTECT,NOCPD,NOLVP,NOWDT,XT

// Con estas directivas las funciones "input" y "output_bit" no reprograman
// el pin de la puerta cada vez que son utilizadas. Si no se indica el
// modo fast_io se asume por defecto standard_io el cual reprograma el pin
// siempre antes de ser utilizadas estas funciones.

#use fast_io (B)
#use fast_io (C)
#use delay(clock=4000000)

//Habilita las funciones RS232, velocidad a 9600 baudios

#use rs232(uart1,baud=9600)

int carRecibido;

#int_rda //Vector de interrupción al recibir por el UART

//Función de tratamiento de la interrupción al recibir

tratamiento()
{
carRecibido=1;
}

main()

carRecibido=0;
output_b(0x00); //Borra las salidas
set_tris_b(0x00); //Puerta B salida
set_tris_c(0b10111111); //RC7/Rx entrada, RC6/Tx salida
enable_interrupts(INT_RDA); //Activa interrupción en la recepción
enable_interrupts(global); //Habilita interrupciones

while(1)
{
if( carRecibido) {
carRecibido=0;
int dato; //Variable para almacena el dato recibido
dato=getc(); //Lee el dato recibido
output_b(dato); //Lo saca por la puerta B
putc(dato); //Lo transmite vía RS232
}
}
}
En él simplemente establezco un flag en la interrupción de haber recibido un caracter y en el main si el flag está a on, leo el caracter y lo escribo.

Si eso lo hago todo en la interrupción, el programa funciona correctamente ¿a qué se debe?
Muchas gracias por su orientación

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: ¿Qué hago mal en este sencillo programa?
« Respuesta #1 en: 19 de Marzo de 2010, 07:30:49 »
No sé cuál será la explicación lógica de que no te funcione pero, ¿no puedes dejar el getc() dentro de la interrupción y sacar el resto al bucle de tu programa?.
Siempre que he usado la int_rda he metido el getc() dentro y hasta ahora no he tenido problemas.

Por cierto, bienvenido al foro. Tu mensaje es un ejemplo de duda bien planteada.

Desconectado ariznaf

  • PIC10
  • *
  • Mensajes: 23
Re: ¿Qué hago mal en este sencillo programa?
« Respuesta #2 en: 19 de Marzo de 2010, 08:09:31 »
Gracias por tu amable respuesta.

Sí, eso que comentas es la opción obvia.

Pero el tema de programar se complica entonces.

La cosa es que el pic ha de recibir mensajes más o menos largos por la puerta serie, de longitud variable y que ha de "descodificar" y procesar.

Eso es fácil hacerlo con un scanf.
Pero a base de getc la cosa se complica sin usar buffers intermedios (cuya longitud no conozco a priori bien).

Y hacer un scanf en una interrupción no es una buena idea, ya que llevan un tiempo demasiado largo, en el que no atenderían otras interrupciones (tendré que atender interrupciones externas en las puertas RB4-7 y la finalización de conversiones A/D).

Además, ya que los sucesos serán lentos en el tiempo, y los comandos llegarán espaciados (pero en cualquier momento) pensaba dormir el pic hasta que se generara una de las interrupciones: recepción de un comando, finalización de una conversión A/D o interrupción por movimiento de los encoders (puerta RB).

Una solución momentánea puede ser que en el cuerpo del programa esté haciendo un polling continuo para ver si llega un comando, sin usar la interrupción RDA y sin dormir el pic.

A ver si alguien sabe decirme qué hago mal, por que la verdad es que no acabo de verlo, por más vueltas que le doy.

Desconectado Suky

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: ¿Qué hago mal en este sencillo programa?
« Respuesta #3 en: 19 de Marzo de 2010, 08:12:33 »
En la interrupción int_rda si o si necesitas implementar el getc() para que se borre el flag de la interrupción, entonces lee el dato recibido guardándolo en una variable global y indicas el dato llegado mediante la bandera.


Saludos!
No contesto mensajes privados, las consultas en el foro

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: ¿Qué hago mal en este sencillo programa?
« Respuesta #4 en: 19 de Marzo de 2010, 08:33:32 »
Bueno, si es un problema del flag de interrupción también se puede borrar a mano, con el bit5 del PIR1.

Pones esto al principio del programa:
#byte PIR1=0x0C
#bit RCIF = PIR1.5

Y esto dentro de tu interrupción:
tratamiento()
{   
   carRecibido=1;
        RCIF=0;
}   

A ver si te funciona así.





Desconectado MarkKnopfler81

  • PIC12
  • **
  • Mensajes: 64
    • PICs, Electrónica y Robótica
Re: ¿Qué hago mal en este sencillo programa?
« Respuesta #5 en: 19 de Marzo de 2010, 08:47:01 »
La variable dato la deberias definir justo despues de main() y sería recomendable que delante de main() y tratamiento() le pusieras un void.....

y yo en lugar de

Código: [Seleccionar]
#use rs232(uart1,baud=9600)0
pondría

Código: [Seleccionar]
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
y también definiría  carRecibido como un int1

saludos.
« Última modificación: 19 de Marzo de 2010, 08:56:05 por MarkKnopfler81 »

Desconectado ariznaf

  • PIC10
  • *
  • Mensajes: 23
Re: ¿Qué hago mal en este sencillo programa?
« Respuesta #6 en: 19 de Marzo de 2010, 09:09:54 »
Bien, gracias a todos.
A ver si he entendido bien (algo he leido también en el foro respecto a que no se borra el bit de interrupción RB si no se lee el puerto B, es posible que ese sea el problema también con la RDA, que si no leo el caracter no se lee el puerto y la interrupción no se borra).

Con esa solución sí funciona.

Código: [Seleccionar]

#include <16f876A.h>

//Ajusta los valores de la palabra de configuración durante el ensamblaje:
//Protección de código y datos=OFF, LVP=OFF, WDT=OFF y OSC=XT

#fuses NOPROTECT,NOCPD,NOLVP,NOWDT,XT

// Con estas directivas las funciones "input" y "output_bit" no reprograman
// el pin de la puerta cada vez que son utilizadas. Si no se indica el
// modo fast_io se asume por defecto standard_io el cual reprograma el pin
// siempre antes de ser utilizadas estas funciones.

#use fast_io (B)
#use fast_io (C)
#use delay(clock=4000000)

//Habilita las funciones RS232, velocidad a 9600 baudios

#use rs232(uart1,baud=9600)

int1 carRecibido;
char dato;


#int_rda //Vector de interrupción al recibir por el UART

//Función de tratamiento de la interrupción al recibir

tratamiento()
{
carRecibido=1;
dato= getc();
}

void main()

carRecibido=0;
output_b(0x00); //Borra las salidas
set_tris_b(0x00); //Puerta B salida
set_tris_c(0b10111111); //RC7/Rx entrada, RC6/Tx salida
enable_interrupts(INT_RDA); //Activa interrupción en la recepción
enable_interrupts(global); //Habilita interrupciones

while(1)
{
if( carRecibido) {
carRecibido=0;
output_b(dato); //Lo saca por la puerta B
putc(dato); //Lo transmite vía RS232
}
}
}

Desconectado MarkKnopfler81

  • PIC12
  • **
  • Mensajes: 64
    • PICs, Electrónica y Robótica
Re: ¿Qué hago mal en este sencillo programa?
« Respuesta #7 en: 19 de Marzo de 2010, 09:17:44 »
Ese codigo que pusiste debería funcionar bien!
Si no te funciona prueba a poner el fuse NOBROWNOUT, puedes que tengas un poco baja la alimentacion y el PIC no salga del Reset...

saludos.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: ¿Qué hago mal en este sencillo programa?
« Respuesta #8 en: 19 de Marzo de 2010, 09:21:09 »
Es recomendable dejar el getc() dentro de la interrupción también por otra razón: si en la interrupción te limitas a subir un flag de aviso, y el PIC está ocupado haciendo otras cosas y no recoge el dato del buffer, corres el riesgo de desbordarlo y comenzar a perder caracteres.

Desconectado ariznaf

  • PIC10
  • *
  • Mensajes: 23
Re: ¿Qué hago mal en este sencillo programa?
« Respuesta #9 en: 19 de Marzo de 2010, 09:34:57 »
Bueno, pues no me funciona ni haciendo lo de borrar el flag de interrupción, ni probando a leer el puerto C ni haciendo las dos cosas.

Había leido en este hilo sobre bugs del compilador: http://www.todopic.com.ar/foros/index.php?topic=21226.0 que era obligado leer el portB aunque sus valores no interesasen, pues si no no se limpiaba el flag.

Pensé que podría ser algo parecido, pero no.

También he probado a deshabilitar el brownot (NOBROWNOUT) y tampoco lo soluciona.

Lo único que parece funcionar es leer el caracter dentro de la interrupción.

La verdad es que no entiendo por qué, yo también creía que sería suficiente con levantar un flag y leerlo en el proceso normal.

Si alguien sabe el por qué, le agradecería mucho que lo explicara.

Desconectado MarkKnopfler81

  • PIC12
  • **
  • Mensajes: 64
    • PICs, Electrónica y Robótica
Re: ¿Qué hago mal en este sencillo programa?
« Respuesta #10 en: 19 de Marzo de 2010, 10:19:56 »
No funcionan ni borrandolo manualmente ni sin borrarlo porque antes de salir de la interrupcion el CCS C lo borra

Código: [Seleccionar]
BCF    0C.5

y el getc() se queda en un bucle hasta que RCIF se ponga a 1

Código: [Seleccionar]
BTFSS  0C.5
GOTO   05B

pero como la interrupcion ya lo borro nunca sucede. Por eso es que getc() tiene que estar en la atención de la interrupción como dijo nocturno. Aparte es la forma de no perder caracteres.

saludos.

Desconectado ariznaf

  • PIC10
  • *
  • Mensajes: 23
Re: ¿Qué hago mal en este sencillo programa?
« Respuesta #11 en: 19 de Marzo de 2010, 10:32:20 »
Bueno, pues muchas gracias a todos.

Me ha quedado claro: los caracteres hay que leerlos en la interrupción.

Ahora tendré que pensar cómo voy a ir procesando los comandos recibidos, si los almaceno en un buffer (no me gusta por no desperdiciar tanta memoria) o si hago una especie de máquina de estado que los vaya interpretando sobre la marcha, y una vez que el comando ha sido recibido y procesado, levanto un flag para que el programa principal lo procese.

¿algún ejemplo?

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: ¿Qué hago mal en este sencillo programa?
« Respuesta #12 en: 19 de Marzo de 2010, 10:57:28 »
Ejemplos de procesado mediante buffer hay bastantes en el foro. Mira en el subforo de Lenguaje C porque los vas a encontrar con toda seguridad magníficamente explicados y redactados por el maestro RedPic.

Desconectado MarkKnopfler81

  • PIC12
  • **
  • Mensajes: 64
    • PICs, Electrónica y Robótica
Re: ¿Qué hago mal en este sencillo programa?
« Respuesta #13 en: 19 de Marzo de 2010, 11:17:10 »
Sino revisa este link de RedPic que lo explica a la perfección.

http://picmania.garcia-cuervo.net/picc.php#COMBUF232

saludos.

Desconectado ariznaf

  • PIC10
  • *
  • Mensajes: 23
Re: ¿Qué hago mal en este sencillo programa?
« Respuesta #14 en: 19 de Marzo de 2010, 13:13:34 »
Pues muchísimas gracias, me aplico a ello.

Ya tengo el prototipo funcionando, aunque sin la interrupción RDA ni el procesador de comandos.

Me lo estudiaré bien a ver si consigo que me funcione todo correctamente y pronto.