Wenas a to2.
Os comento un problema que me ha surgido en una aplicacion que estoy desarrollando, 16F876A.
El PIC manda unos datos al PC para graficarlos -> Funciona (aplicacion en Visual Basic)
El PC manda codigos al PIC para configurarlo, le mando:
byte1 -> Cabecera que indica si es un check de conexion o cambio de modo, los cuales tengo programado PWM+ o PWM-
byte2 -> PWM_pos o PWM_neg
byte3 y byte4 -> Valor a cargar en el PWM:
duty_PWM2=make16(byte4,byte3);
El timer1 me indica el periodo de muestreo, para recojer los datos (encoder).
Tanto el timer como el PWM2 funcionan, estan bien configurados.
El problema es al recibir datos por USART, el PIC se me resetea de forma aleatoria. Quiero decir que esta recibiendo cambios de velocidad bien (mientras grafica) y de repente al recibir otro cambio de velocidad por USART se resetea (WDT activo).
He probado a recibir por interrupcion los 4 bytes seguidos, de 1 byte cada vez (codigo parecido al que tiene PACA en su web, gracias por compartirlo) o a recibir muestreando.
Incluso muestreando recibir 2 bytes, responder al PC y quedar a la espera de los otros 2 bytes.
Codigo:
#include <16F876A.h>
#fuses XT,WDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP,NOWRT
#use delay(clock=4000000)
#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7,BITS=8)
// Cabeceras que pueden llegar desde el HOST:
#define CHEQUEO 0xF0 // Chequeo de conexion, PIC responde ACK.
#define MODO_REF 0xF1 // Modo de control; velocidad, posicion, PWM
// En el main:
if(bit_test(PIR1,5)){
disable_interrupts(INT_TIMER1);
cabecera=getc();
restart_wdt();
switch(cabecera){
case CHEQUEO:
putc(0xFA); // Respondemos: "acknowledge" (FA)
break;
case MODO_REF: // Recibe modo + Referencias
modo=getc();
switch(modo){
case(PWM_pos):
case(PWM_neg):
putc(0xFA); // Respondemos: "acknowledge" (FA)
refer_h=getc(); // Recibimos parte alta y baja para referencia.
refer_l=getc();
duty_PWM2=make16(refer_h,refer_l);
break;
break;
}
enable_interrupts(INT_TIMER1);
}
Solicito de vuestra ayuda, no me quedan ideas y me niego a creer que no pueda recibir una trama de 4 bytes consecutivos.
En el caso de recepcion por interrupcion, algo de lo que he intentado es esto:
Codigo:
// --------------------------------------------------------------------------------------------------
// Rutina de atencion a la interrupcion por recepcion USART.
// Se recibe una trama de 4 bytes, el primero es la cabecera e indica que datos siguen.
// cabecera: CHEQUEO 0xF0
// MODO_REF 0xF1 + MODO + 2bytes(valor)
// PARAMETROS 0xF2 + Kn + 2bytes(valor)
// CONFIG_ROM 0xF3 + Kn + 2bytes(valor)
// --------------------------------------------------------------------------------------------------
#int_RDA
void serial_isr(){
disable_interrupts(INT_TIMER1);
// Si hay una trama pendiente de analizar se ignora lo recibido.
if (comm_ocupado==0){
comm_trama[0]=getc();
comm_trama[1]=getc();
comm_trama[2]=getc();
comm_trama[3]=getc();
// Indicamos que hay nuevos datos a tratar:
comm_ocupado=1;
}
enable_interrupts(INT_TIMER1);
}
Con el correspondiente enable_interrupts(int_rda);
No os aburro mas, que estoy muy quemao con la puta USART....
>Salu2<
adrian: El watchdog lo tengo por si se produce algun error en la comunicacion el pic se reinicie y tenerlo en un estado conocido. Es como seguridad ante fallos en la comunicacion.
Lo reseteo en el programa principal, eso funciona perfectamente pues solo se me reinicia el pic cuando se queda a la espera en un getc() y no regresa de la funcion de recepcion al main, que es donde reseteo el watchdog.
wqrtp: Espero recibir 4 bytes pues se los mando seguidos desde el PC y pensaba que el PIC los recibiria bien asi, pero no le gustaba...
Tambien probe recibir byte a byte, y al tener 4 activar un flag para tratar la trama, basado en el ejemplo que tenia pacalaconcurso en su web.
Codigo:
// --------------------------------------------------------------------------------------------------
// Rutina de atencion a la interrupcion por recepcion USART.
// Se recibe una trama de 4 bytes, el primero es la cabecera e indica que datos siguen.
// cabecera: CHEQUEO 0xF0
// MODO_REF 0xF1 + MODO + 2bytes(valor)
// PARAMETROS 0xF2 + Kn + 2bytes(valor)
// CONFIG_ROM 0xF3 + Kn + 2bytes(valor)
// --------------------------------------------------------------------------------------------------
#int_RDA
void serial_isr(){
if(comm_cuenta<4){
comm_trama[comm_cuenta]=getc();
// Cuando comm_cuenta==4, tendremos la trama completa lista para procesar.
comm_cuenta++;
}
}
Ahora mismo funciona bien haciendolo por muestreo, if(bit_test(PIR1,5)), he tenido que retocar un poco el programa del PC pero creo que ya recibe sin problemas cada dos por tres.
Leyendo otros post, vi este: http://miarroba.com/foros/ver.php?foroid=15353&temaid=1777135
Aqui dogflu66 comenta:
"para trabajar la usart + interrupciones yo no utilizo menos de 20Mhz, de esta forma me evito que se bloquee, ya que si no extraes los datos suficiente mente rápido se bloquea em Rx y entonces tienes que llevar el control de errores de la usart para detectar este fallo y obrar en consecuencia..."
Entonces ¿podria ser que al trabajar con un reloj a 4 Mhz no le de tiempo al PIC a recojer los bytes antes de que llegen mas, lo que produce un bloqueo del mismo?
Sigo sin ver claro la utilidad del Watchdog en tu programa, ahí está la causa de tu problema. De todas formas si insistes en mantenerlo no puedes utilizar la instrucción getc() tal como lo haces, porque siempre el sistema será reseteado por el Watchdog. Prueba con la sigueinte estructura, utilizando la función kbhit() y restart_wdt() en la rutina de atención a la interrupción y similar en el programa principal:
Codigo:
#int_RDA
void serial_isr()
{
if(comm_cuenta<4)
{
if (kbhit())
{
comm_trama[comm_cuenta]=getc();
comm_cuenta++;
}
else
restart_wdt();
}
}
Aunque, te insisto que yo deshabilitaría el Watchdog. Podiamos entrar en una discusión en la utilidad del mismo, pero yo lo tengo muy claro: para programas sencillos lo único que hace el Watchdog es complicar la vida al personal, te lo cuento por experiencia.
Salu2.
Adrian.