Autor Tema: Comunicación serial PIC 16F1827  (Leído 4053 veces)

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

Desconectado joseluislo12

  • PIC10
  • *
  • Mensajes: 20
Comunicación serial PIC 16F1827
« en: 13 de Julio de 2015, 14:37:04 »
Tengo un problema con un programa que hace uso de interrupciones por recepción serial
El programa lo que hace es recibir cierta información desde un XBee hasta otro XBee (puede ser PIC-PIC o PC-PIC) y hacer algo dependiendo de lo que recibe

Parte del programa original es el siguiente:

Código: [Seleccionar]
#include <16F1827.h>
#device WRITE_EEPROM = NOINT
#FUSES WDT, NOPUT, PROTECT, NOMCLR, NOCLKOUT, NOCPD, NOBROWNOUT, PLL, INTRC_IO,
#use delay(clock=32M)
#use RS232(BAUD=9600, XMIT=PIN_B2, RCV=PIN_B1, stream=com,errors)

...

void main (void){
   int temp;
...
   ext_int_edge(L_TO_H);
   setup_timer_0(T0_INTERNAL|T0_DIV_4);
   enable_interrupts(global);
   enable_interrupts(int_ext);
   enable_interrupts(INT_TIMER0);
   while(true){     
      RESTART_WDT();
      if(kbhit(com)){
         RESTART_WDT();
         temp=recepcion_datos();  // -> -> Devuelve un entero
         ejecucion(temp);         // -> -> Actúa dependiendo del valor de la anterior función
      }
...
   }
}

En la función donde se reciben los datos se está haciendo siempre esto:

Código: [Seleccionar]
rx=getc(com);

Ahora, modificando el código para tener interrupción quedó de esta forma:

Código: [Seleccionar]
#include <16F1827.h>
#device WRITE_EEPROM = NOINT
#FUSES WDT, NOPUT, PROTECT, NOMCLR, NOCLKOUT, NOCPD, NOBROWNOUT, PLL, INTRC_IO,
#use delay(clock=32M)
#use RS232(BAUD=9600, XMIT=PIN_B2, RCV=PIN_B1, stream=com,errors)

...

#int_RDA
void RDA_isr(void){
   RESTART_WDT();
   OUTPUT_BIT(LED2,LON);
   temp[br]=getc(com);
   br++;
   if(br==1){
      dato=temp[0];
      if(dato!=0x7E){
         temp[0]=0;
         br=0;
         recep=0;
      }
   }
   if(br==3){
      tam_tram=temp[2];
      tamano=tam_tram+3;
   }
   if(br<tamano){recep=0;}
   else if(br==tamano){recep=1;}
}
...

void main (void){
...
   ext_int_edge(L_TO_H);
   setup_timer_0(T0_INTERNAL|T0_DIV_4);
   enable_interrupts(global);
   enable_interrupts(int_ext);
   enable_interrupts(int_rda);         // Interrupción comunicación serial
   enable_interrupts(INT_TIMER0);
   while(true){
      RESTART_WDT();
// VALIDACIÓN DE RECEPCIÓN
      if(recep==1){
         RESTART_WDT();
         for(pos=0;pos<=br-1;pos++){decodificar_trama(pos,temp[pos]);}
         for(pos=0;pos<=32;pos++){temp[pos]=0;}
         temp2=recepcion_datos();
         ejecucion(temp2);
         br=0;
         temp2=0;
         tam_tram=0;
         recep=0;
      }
...
   }
}

Se creó una función para pasar la información del programa "principal" a la librería:

Código: [Seleccionar]
void decodificar_trama(int cn,int dato){
brr[cn]=dato;
}

Y en la función de recepción ahora se hace lo siguiente:

Código: [Seleccionar]
rx=brr[0];
Esto con el fin de que  se pueda estar ejecutando una acción sin esperar que todos los datos necesarios para una nueva instrucción lleguen al tiempo.

Anteriormente si llegaba un dato, se paraba lo que estuviera haciendo y solamente se dedicaba a recibir todo.
Ahora la idea es que mientras reciba todos los datos que está esperando, esté ejecutando algo y luego al acabar "revise" si tiene algo pendiente por hacer (llegaron todos los datos) o se quede esperando que lleguen los datos restantes.

El problema es que con el programa modificado jamás hace nada de lo que se le envía por XBee. No se dónde pueda ser el problema porque la recepción está funcionando correctamente (como se comprobó con el ejemplo que dio inicio a este post)

Espero que me puedan ayudar

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Comunicación serial PIC 16F1827
« Respuesta #1 en: 13 de Julio de 2015, 18:48:32 »
Probaste desactivando el WDT al menos para hacer las pruebas?, tambien probaste la rutina de interrupcion solamente ?
Para que hacer una funcion asi?

Código: C
  1. decodificar_trama(pos,temp[pos])
y llamarla asi:
Código: C
  1. for(pos=0;pos<=br-1;pos++){decodificar_trama(pos,temp[pos]);}

Cuando directamente podes poner

Código: C
  1. for(pos=0;pos<br;pos++){brr[pos]=temp[pos];}

---------------------

Tu rutina de interrupcion me parece que esta mal, hay varias cosas que no me convencen

Código: C
  1. void RDA_isr(void){
  2.    RESTART_WDT();
  3.    OUTPUT_BIT(LED2,LON);
  4.    temp[br]=getc(com);
  5.    br++;
  6.    if(br==1){
  7.       dato=temp[0];
  8.       if(dato!=0x7E){
  9.          temp[0]=0;
  10.          br=0;
  11.          recep=0;
  12.       }
  13.    }
  14.    if(br==3){
  15.       tam_tram=temp[2];
  16.       tamano=tam_tram+3;
  17.    }
  18.    if(br<tamano){recep=0;}
  19.    else if(br==tamano){recep=1;}
  20. }

Nunca pero NUNCA resetea br, el unico momento que resetea br es cuando el primer dato que llega es distinto a 0x7E, a partir de ahi cuando se cumple eso, br sigue y sigue y sigue y sigue incrementandose.
Hasta el punto de poder llegar hasta 255, haciendo temp[255] lo cual no es valido y recien ahi llegar a 0 Si es que en tu main se tarda mas de la cuenta.
PD: Veo que en tu main reseteas br, eso no lo podes hacer, por que si viene otra trama estarias dejandola pasar por ese "delay" hasta que se hacen todas las funciones del main y encima se procesan los datos.

Código: C
  1. if(br<tamano){recep=0;}
  2.    else if(br==tamano){recep=1;}

Reemplazar eso por un:

Código: C
  1. if(br==tamano){recep=1; copiar_datos(); br=0;}

Ahi cuando se termina de recibir deberias copiar tus datos al otro array ( asi tener los datos listos )  activar el flag como lo hiciste, para saber que hay datos a ver, y volver a poner a 0 br. Asi prepararse para la llegada de nuevos datos
el flag de recep te debe indicar si hay datos listos para "tratar",

Si no me entendiste te doy un ejemplo, imaginate la rutina de interrupcion como un cartero, Comienzan a llegar cartas(cada byte) de un envio(trama) (el sabe cuantas deben llegar) y solo te avisa cuando estan todas las cartas ahi de ese envio.
Mientras sigue recibiendo las cartas del otro envio (sabiendo que pertenece a otra trama).
Vos cuando estan te aviza que estan listas vas y retiras todo el pedido (trama).

Aca puede ocurrir que al seguir juntando cartas llegue a haber 2 pedidos enteros para vos y vos no pasate a buscarlo, pero solo tiene lugar para uno.. Vos le diras a ese cartero que debe hacer, si tirar el ultimo pedido completo, o dejar de recibir cartas, o hacerle espacio para 2 o mas.

Dejando de lado las analogias, otra cosa mas, hay muchas variables y operaciones sin sentido que quitandolas quedo algo como esto:

Código: C
  1. void RDA_isr(void){
  2.    RESTART_WDT();
  3.    OUTPUT_BIT(LED2,LON);
  4.    temp[br]=getc(com);
  5.    br++;
  6.    if(br==1 && temp[0]!=0x7E) br=0;   //Compruebo que sea inicio de trama, no hago temp[0]=0, total en la proxima interrupcion se va a borrar al ser br=0.
  7.    if(br==3) tamano=temp[2] + 3;     // Obtengo el largo de la trama +3 por el br++,
  8.    if(br==tamano)                            // Llego al final de la trama?, comienzo nuevamente
  9.    {
  10.       if(!recep){for(pos=0;pos<br;pos++){brr[pos]=temp[pos];}}            //Paso los datos al array que se va a usar
  11.       else {while(1);}                         // Aca entraria si hubiera un error, en el que llego una segunda trama por completo y todavia no se proceso la primera. Si queda atorado aca quiere decir que eso ocurrio. Se puede reemplazar por otro codigo, como un
  12.                                                      // led o algo por el estilo que te avise cuando eso ocurra. O directamente descartar la nueva trama que llego hasta que se termine de procesar la que ya habiamos copiado.
  13.       recep=1;                                  // Esto deberia ponerse a 0 en el programa principal, cuando se termina de tratar los datos
  14.       br=0;
  15.    }
  16. }

El codigo SUPONE que el tamaño de la trama JAMAS sea menor a 3 datos.
 
temp[] = buffer de datos para la llegada
brr[] = array que usas para mantener toda la trama una ves llegada y es lo que usas para "tratar" la trama.

Siguiendo con tu main:

Código: C
  1. if(recep==1){
  2.          RESTART_WDT();
  3.          for(pos=0;pos<=br-1;pos++){decodificar_trama(pos,temp[pos]);}        //Esto no tiene sentido aca
  4.          for(pos=0;pos<=32;pos++){temp[pos]=0;}                                       // Esto tampoco tiene sentido, ya que la nueva trama lo va a sobreescribir
  5.          temp2=recepcion_datos();                                                                 // Estas 2 funciones realmente no se que hacen, pero tampoco le veo mucho sentido trabajar con un byte de info cuando tenes un ARRAY de informacion
  6.          ejecucion(temp2);                                                                              // Imagino que aca realmente manejas el array
  7.          br=0;                                                                                            // Esta es una variable de la interrupcion, no de aca
  8.          temp2=0;                                                                                       // No tiene sentido ya que primero se asigna un valor a temp2 y luego se usa, asi que no importa el valor que tenga se va a sobreescribir
  9.          tam_tram=0;                                                                                 // Tampoco tiene sentido, esto lo sacas de brr[2]
  10.          recep=0;                                                                                      // Lo unico que vale xD

Deberia ser asi:

Código: C
  1. if(recep==1){
  2.          RESTART_WDT();
  3.          temp2=recepcion_datos();
  4.          ejecucion(temp2);
  5.          recep=0;
  6.       }

Y creo que directamente podrias haber realizado una sola funcion para esas 2, aunque no se realmente que hacen cada una.
« Última modificación: 13 de Julio de 2015, 19:42:55 por KILLERJC »

Desconectado joseluislo12

  • PIC10
  • *
  • Mensajes: 20
Re: Comunicación serial PIC 16F1827
« Respuesta #2 en: 14 de Julio de 2015, 10:17:20 »
...

Primero que todo muchas gracias por la ayuda y por el tiempo que te tomaste leyendo el código



La verdad no probé lo del WDT, en qué podría afectar eso al funcionamiento del programa ??? No lo entiendo muy bien

Lo de las interrupciones sí lo probé, y funciona siempre que haya una o dos funciones dentro de la interrupción, no si solamente se activa la bandera



Lo de la función es porque este programa hace parte de un módulo específico de un trabajo que agrupa varios módulos que hacen diferentes cosas, entonces se creó una librería general para todos los módulos y que cada módulo la trabaje como necesita
Entonces la función decodificar_trama lo que hace es pasar la información del programa principal, donde se efectúa la recepción serial, a la librería ya que es ahí donde se hace el procesado de dicha información que se recibe



No había pensado lo de resetear br, yo lo hacía dentro del main pero no era por una razón en específico  :D

En cuanto a lo de que el tamaño de la trama sea mayor a 3, hay dos escenarios:
  • Si es menor a 3, es porque hasta ahora está recibiendo
  • Si es mayor a 3, en el tercer dato que recibe ya sabe cuál es el tamaño que llegará
Jamás podrá llegar una trama de 1 o 2 datos, porque o está mal (el primero no es 0x7E) o está esperando a recibir más



Ahora en la parte del main:

Lo que yo hacía era enviar lo recibido a la librería dentro del main, pero ahora lo haré en la interrupción como me dices

Lo de hacer que todas las posiciones eran 0 era solamente para evitar que una trama de tamaño diferente fuera a quedar con información de una anterior, aunque realmente jamás se utilizará porque todo lo condiciona el tamaño de la trama. Era digamos sólo para tener ese arreglo siempre en 0 cuando no se esté utilizando (algo como mantener limpia las cosas que uno usa  :D)
Lo mismo sucede con el temp2, lo hago 0 solo para que esté "limpio" la próxima vez que se va a usar
Yo puse lo de hacer 0 la variable tam_trama porque cuando acabe de procesar una información y empieza a llegar otra, quería que ni por error pudiera pensar que ese es el tamaño de la actual.
Vamos, que todo es por lo mismo, para cuando llegue una nueva trama todo esté en 0  :D :D :D

Lo de las funciones es por lo que comenté anteriormente, porque todo va a una librería general en la cual cada módulo, y dependiendo de lo que le llegue, "decide" qué va a hacer, y como pueden haber varias posibilidades (por diferencia del módulo y por diferentes acciones que puede hacer) se dejaron dos funciones, la primera para saber qué es lo que se le pide que haga (y de paso guardar cierta información en la EEPROM) y la segunda para que lo haga

Desconectado joseluislo12

  • PIC10
  • *
  • Mensajes: 20
Re: Comunicación serial PIC 16F1827
« Respuesta #3 en: 14 de Julio de 2015, 14:41:44 »
Estuve haciendo algunas pruebas pero sigo teniendo problemas

El circuito que tengo montado es el siguiente:



  • PIC 1: Arriba
  • PIC 2: Abajo

Y tengo estos dos códigos:

Emisor
Código: [Seleccionar]
#include <16f1827.h>
#use     delay (internal = 32MHz)         // Fosc=32Mhz
// #use     delay (internal = 4MHz)          // Fosc=4Mhz, para simulación
#use     RS232(UART1)

#define NO_INTERRUPCION       PIN_B4
#define EXTERNO               PIN_B5

int FLAG_EXT=0;
#INT_EXT
void ext_int(){
   FLAG_EXT=1;
}

void main(){
   int c=0;
   int e=0;
   enable_interrupts(int_ext);
   ext_int_edge(L_TO_H);
   enable_interrupts(GLOBAL);
   output_high (EXTERNO);
   output_high (NO_INTERRUPCION);
   delay_ms(1000);
   output_low (EXTERNO);
   output_low (NO_INTERRUPCION);
   delay_ms(1000);
   output_high (EXTERNO);
   output_high (NO_INTERRUPCION);
   delay_ms(1000);
   output_low (EXTERNO);
   output_low (NO_INTERRUPCION);
   delay_ms(1000);
   output_high (EXTERNO);
   output_high (NO_INTERRUPCION);
   delay_ms(1000);
   output_low (EXTERNO);
   output_low (NO_INTERRUPCION);
   delay_ms(1000);
   while(TRUE){
      if(FLAG_EXT==1){
         output_low (NO_INTERRUPCION);
         FLAG_EXT=0;
         switch(c){
            case 0:
               e=0x7E;
            break;
            case 1:
               e=0x00;
            break;
            case 2:
               e=0x11;
            break;
            case 3:
               e=0x90;
            break;
            case 4:
               e=0x00;
            break;
            case 5:
               e=0x00;
            break;
            case 6:
               e=0x01;
            break;
            case 7:
               e=0x03;
            break;
            case 8:
               e=0x0A;
            break;
            case 9:
               e=0x02;
            break;
            case 10:
               e=0x00;
            break;
            case 11:
               e=0x00;
            break;
            case 12:
               e=0xFF;
            break;
            case 13:
               e=0xFE;
            break;
            case 14:
               e=0x01;
            break;
            case 15:
               e=0x01;
            break;
            case 16:
               e=0x20;
            break;
            case 17:
               e=0x83;
            break;
            case 18:
               e=0x0B;
            break;
            case 19:
               e=0x01;
            break;
            case 20:
               e=0xB1;
            break;
         }
         putc(e);
         output_high (EXTERNO);
         delay_ms(1000);
         output_low (EXTERNO);
         c++;
         if(c>20){c=0;}
      }
      else if(FLAG_EXT==0)
      {
         output_high (NO_INTERRUPCION);
         output_low (EXTERNO);
      }
   }
}

Receptor

Código: [Seleccionar]
#include <16f1827.h>
#use     delay (internal = 32MHz)         // Fosc=32Mhz
// #use     delay (internal = 4MHz)          // Fosc=4Mhz, para simulación
#use     RS232(UART1)

#define RECEPCION       PIN_B4
#define ERROR           PIN_B5
#define ESTADO          PIN_B6

/*
ESTADO
-> CONSTANTE: DISPONIBILE
-> APAGADO: OCUPADO
-> 2 INT: TAM_TRAMA
-> 3 INT: COMPLETO
*/

int temp[32]={0};
int br=0;
int recep=0;
int pos;
int tamano=0;

#int_RDA
void RDA_isr(void){
   output_low (ERROR);
   output_low (ESTADO);
   output_high (RECEPCION);
   temp[br]=getc();
   br++;
   if(br==1 && temp[0]!=0x7E){
      output_low (RECEPCION);
      output_high (ERROR);
      delay_ms(1000);
      output_low (ERROR);
      delay_ms(1000);
      output_high (ERROR);
      delay_ms(1000);
      output_low (ERROR);
      delay_ms(1000);
      br=0;
   }
   if(br==3){
      output_high (ESTADO);
      delay_ms(1000);
      output_low (ESTADO);
      delay_ms(1000);
      output_high (ESTADO);
      delay_ms(1000);
      output_low (ESTADO);
      delay_ms(1000);
      tamano=temp[2]+3;
   }
   if(br==tamano){
      output_high (ESTADO);
      delay_ms(1000);
      output_low (ESTADO);
      delay_ms(1000);
      output_high (ESTADO);
      delay_ms(1000);
      output_low (ESTADO);
      delay_ms(1000);
      output_high (ESTADO);
      delay_ms(1000);
      output_low (ESTADO);
      delay_ms(1000);
      for(pos=0;pos<=32;pos++){temp[pos]=0;}
      br=0;
      recep=1;
   }
}

void main(){
   enable_interrupts(int_rda);
   enable_interrupts(GLOBAL);
   output_high (RECEPCION);
   output_high (ERROR);
   output_high (ESTADO);
   delay_ms(1000);
   output_low (RECEPCION);
   output_low (ERROR);
   output_low (ESTADO);
   delay_ms(1000);
   output_high (RECEPCION);
   output_high (ERROR);
   output_high (ESTADO);
   delay_ms(1000);
   output_low (RECEPCION);
   output_low (ERROR);
   output_low (ESTADO);
   delay_ms(1000);
   output_high (RECEPCION);
   output_high (ERROR);
   output_high (ESTADO);
   delay_ms(1000);
   output_low (RECEPCION);
   output_low (ERROR);
   output_low (ESTADO);
   delay_ms(1000);
   while(TRUE){
      if(recep==1){
         recep=0;
      }
      else if(recep==0){
         output_high (ESTADO);
         output_low (ERROR);
         output_low (RECEPCION);
      }
   }
}

Lo primero que hace es encender y apagar 3 veces todos los LEDs (solamente para saber que ya está listo para empezar :lol:)
Luego, si no hay ninguna interrupción se encienden los LEDs ESTADO y NO_INTERRUPCIÓN

Todo comienza cuando hay una interrupción externa en el PIC 2, se enciende el LED SERIAL y se envía un dato al PIC 1 dependiendo de un valor que va aumentando desde 0 hasta 20 para volver a empezar en 0 y seguir
Esto lo hace perfectamente

En el PIC 1 se debería activar la interrupción por recepción serial y activar el LED RECEPCIÓN y dependiendo de lo que reciba hay unas secuencias de LED para finalmente volver a dejar encendido solamente el LED ESTADO, cuando todo el proceso acabe.

Ahora bien, en simulación y en físico el PIC 2 funciona correctamente, sin ningún problema
El PIC 1 tiene dos problemas:
Físico:
No enciende nunca ningún LED y al comienzo debería encender los tres LED en la misma secuencia que el PIC 2
* No es problema del PIC porque le cargué el programa emisor y funciona perfectamente, el problema es con el programa receptor
Simulación y Físico:
No se cumple correctamente la secuencia que debería en los LEDs correspondientes
« Última modificación: 14 de Julio de 2015, 14:44:56 por joseluislo12 »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Comunicación serial PIC 16F1827
« Respuesta #4 en: 15 de Julio de 2015, 04:10:00 »
No podes poner delays en las interrupciones, mas que no podes, es no debes. Ademas achicha un poco mas los programas.

Ejemplo el receptor con esto es suficiente:

Código: C
  1. int temp[32]={0};
  2. int br=0;
  3. int recep=0;
  4. int pos;
  5. int tamano=0;
  6.  
  7. #int_RDA
  8. void RDA_isr(void){
  9.    output_toggle(RECEPCION);
  10.    temp[br]=getc();
  11.    br++;
  12.    if(br==1 && temp[0]!=0x7E){
  13.       br=0;
  14.    }
  15.    if(br==3){
  16.       output_high(ERROR);
  17.       tamano=temp[2]+3;
  18.    }
  19.    if(br==tamano){
  20.       output_high(ESTADO);
  21.       for(pos=0;pos<=32;pos++){temp[pos]=0;}
  22.       br=0;
  23.       recep=1;
  24.    }
  25. }
  26.  
  27. void main(){
  28.    output_low (RECEPCION);
  29.    output_low (ERROR);
  30.    output_low (ESTADO);
  31.  
  32.    enable_interrupts(int_rda);
  33.    enable_interrupts(GLOBAL);
  34.  
  35.    while(TRUE){
  36.       if(recep==1){
  37.          recep=0;
  38.          output_low (RECEPCION);
  39.          output_low (ERROR);
  40.          output_low (ESTADO);
  41.       }
  42.    }
  43. }

Y el transmisor:

Código: C
  1. int FLAG_EXT=0;
  2. #INT_EXT
  3. void ext_int(){
  4.    FLAG_EXT=1;
  5.    output_toggle(NO_INTERRUPCION);
  6. }
  7.  
  8.  
  9. void main(){
  10.    int c=0;
  11.    int trama[21]={0x7E,0x00,0x11,0x90,0x00,0x00,0x01,0x03,0x0A,0x02,0x00,0x00,0xFF,0xFE,0x01,0x01,0x20,0x83,0x0B,0x01,0xB1};
  12.  
  13.    enable_interrupts(int_ext);
  14.    ext_int_edge(L_TO_H);
  15.    enable_interrupts(GLOBAL);
  16.  
  17.    while(TRUE){
  18.       if(FLAG_EXT==1){
  19.          FLAG_EXT=0;
  20.          putc(trama[c]);
  21.          output_toggle (EXTERNO);
  22.          delay_ms(1000);
  23.          c++;
  24.          if(c>20){c=0;}
  25.       }
  26.    }
  27. }

Desconectado joseluislo12

  • PIC10
  • *
  • Mensajes: 20
Re: Comunicación serial PIC 16F1827
« Respuesta #5 en: 15 de Julio de 2015, 17:21:36 »
Bueno, el ejemplo de la interrupción funcionó muy bien con estos dos códigos:

Emisor
Código: C
  1. #include <16f1827.h>
  2. #use     delay (internal = 32 MHz)         // Fosc=32Mhz
  3. #use     RS232(UART1)
  4.  
  5. #define NO_INTERRUPCION       PIN_B4
  6. #define EXTERNO               PIN_B5
  7.  
  8. void main(){
  9.    int c=0;
  10.    int e[21]={0x7E,0x00,0x11,0x90,0x00,0x00,0x01,0x03,0x0A,0x02,0x02,0x00,0xFF,0xFE,0x01,0x01,0x20,0x83,0x0B,0x01,0xB1};
  11.  
  12.    enable_interrupts(int_ext);
  13.    ext_int_edge(L_TO_H);
  14.    enable_interrupts(GLOBAL);
  15.    
  16.    output_high (EXTERNO);
  17.    output_high (NO_INTERRUPCION);
  18.    delay_ms(500);
  19.    output_low (EXTERNO);
  20.    output_low (NO_INTERRUPCION);
  21.    delay_ms(500);
  22.    output_high (EXTERNO);
  23.    output_high (NO_INTERRUPCION);
  24.    delay_ms(500);
  25.    output_low (EXTERNO);
  26.    output_low (NO_INTERRUPCION);
  27.    delay_ms(500);
  28.    output_high (EXTERNO);
  29.    output_high (NO_INTERRUPCION);
  30.    delay_ms(500);
  31.    output_low (EXTERNO);
  32.    output_low (NO_INTERRUPCION);
  33.    delay_ms(500);
  34.    
  35.    while(TRUE){
  36.       output_high (NO_INTERRUPCION);
  37.       delay_ms(500);
  38.       output_low (NO_INTERRUPCION);
  39.       putc(e[c]);
  40.       output_high (EXTERNO);
  41.       delay_ms(1000);
  42.       output_low (EXTERNO);
  43.       c++;
  44.       if(c>20){
  45.          c=0;
  46.          output_high (NO_INTERRUPCION);
  47.          delay_ms(500);
  48.          output_low (NO_INTERRUPCION);
  49.          delay_ms(500);
  50.          output_high (NO_INTERRUPCION);
  51.          delay_ms(500);
  52.          output_low (NO_INTERRUPCION);
  53.          delay_ms(500);
  54.          output_high (NO_INTERRUPCION);
  55.          delay_ms(500);
  56.          output_low (NO_INTERRUPCION);
  57.          delay_ms(500);
  58.       }
  59.    }
  60. }

Receptor
Código: C
  1. #include <16f1827.h>
  2. #use     delay (internal = 32MHz)         // Fosc=32Mhz
  3. //#use     delay (internal = 4MHz)          // Fosc=4Mhz, para simulación
  4. #use     RS232(UART1)
  5.  
  6. #define RECEPCION       PIN_B4
  7. #define ERROR           PIN_B5
  8. #define ESTADO          PIN_B6
  9.  
  10. /*
  11. ESTADO
  12. -> CONSTANTE: DISPONIBILE
  13. -> APAGADO: OCUPADO
  14. -> 2 INT: TAM_TRAMA
  15. -> 3 INT: COMPLETO
  16. */
  17.  
  18. int temp[32]={0};
  19. int br=0;
  20. int recep=0;
  21. int pos;
  22. int tamano=0;
  23. int err=0;
  24. int serial=0;
  25. int tam=0;
  26. int espera=0;
  27.  
  28. #int_RDA
  29. void RDA_isr(void){
  30.    temp[br]=getc();
  31.    br=br+1;
  32.    if(br==1 && temp[0]!=0x7E){
  33.       br=0;
  34.       err=1;
  35.    }
  36.    if(br<3 || br>3){tam=0;}
  37.    if(br==3){
  38.       tam=1;
  39.       tamano=temp[2]+4;
  40.    }
  41.    if(br<tamano){espera=1;}
  42.    if(br==tamano){
  43.       for(pos=0;pos<=32;pos++){temp[pos]=0;}
  44.       br=0;
  45.       recep=1;
  46.       tamano=0;
  47.    }
  48.    serial=1;
  49. }
  50.  
  51. void main(){
  52.    output_low (RECEPCION);
  53.    output_low (ERROR);
  54.    output_low (ESTADO);
  55.  
  56.    enable_interrupts(int_rda);
  57.    enable_interrupts(GLOBAL);
  58.    
  59.    output_high (RECEPCION);
  60.    output_high (ERROR);
  61.    output_high (ESTADO);
  62.    delay_ms(500);
  63.    output_low (RECEPCION);
  64.    output_low (ERROR);
  65.    output_low (ESTADO);
  66.    delay_ms(500);
  67.    output_high (RECEPCION);
  68.    output_high (ERROR);
  69.    output_high (ESTADO);
  70.    delay_ms(500);
  71.    output_low (RECEPCION);
  72.    output_low (ERROR);
  73.    output_low (ESTADO);
  74.    delay_ms(500);
  75.    output_high (RECEPCION);
  76.    output_high (ERROR);
  77.    output_high (ESTADO);
  78.    delay_ms(500);
  79.    output_low (RECEPCION);
  80.    output_low (ERROR);
  81.    output_low (ESTADO);
  82.    delay_ms(500);
  83.  
  84.    while(TRUE){
  85.       if(err==1){
  86.          err=0;
  87.          output_low (ERROR);
  88.          output_low (ESTADO);
  89.          output_low (RECEPCION);
  90.          output_high (ERROR);
  91.          delay_ms(1000);
  92.          output_low (ERROR);
  93.          delay_ms(1000);
  94.          output_high (ERROR);
  95.          delay_ms(1000);
  96.          output_low (ERROR);
  97.          delay_ms(1000);
  98.       }
  99.       if(serial==1){
  100.          output_low (ERROR);
  101.          output_low (ESTADO);
  102.          output_high (RECEPCION);
  103.          if(tam==1){output_high (ESTADO);}
  104.          if(espera==1){output_high (ERROR);}
  105.          serial=0;
  106.          delay_ms(1000);
  107.          tam=0;
  108.          espera=0;
  109.       }
  110.       if(recep==1){
  111.          recep=0;
  112.          output_low (ERROR);
  113.          output_low (ESTADO);
  114.          output_low (RECEPCION);
  115.          output_high (ESTADO);
  116.          delay_ms(500);
  117.          output_low (ESTADO);
  118.          delay_ms(500);
  119.          output_high (ESTADO);
  120.          delay_ms(500);
  121.          output_low (ESTADO);
  122.          delay_ms(500);
  123.          output_high (ESTADO);
  124.          delay_ms(500);
  125.          output_low (ESTADO);
  126.          delay_ms(500);
  127.       }
  128.       else if(recep==0){
  129.          output_low (RECEPCION);
  130.          output_low (ERROR);
  131.          output_high (ESTADO);
  132.       }
  133.    }
  134. }

View My Video





Ahora aún sigo teniendo problemas con el programa original

Así está en este momento:

Código: C
  1. #include <16F1827.h>
  2. #device WRITE_EEPROM = NOINT
  3. #FUSES WDT, NOPUT, PROTECT, NOMCLR, NOCLKOUT, NOCPD, NOBROWNOUT, PLL, INTRC_IO,
  4. #use delay(clock=32M)
  5. #use RS232(BAUD=9600, XMIT=PIN_B2, RCV=PIN_B1, stream=com,errors)
  6.  
  7. ...
  8.  
  9. int temp[32]={0};
  10. int br=0;
  11. int recep=0;
  12. int pos;
  13. int tam_tram=0;
  14. int temp2;
  15. int tamano=0;
  16.  
  17. ...
  18.  
  19. #int_RDA
  20. void RDA_isr(void){
  21.    temp[br]=getc(com);
  22.    br=br+1;
  23.    if(br==1 && temp[0]!=0x7E){br=0;}
  24.    if(br==3){tamano=tam_tram=temp[2]+4;}
  25.    if(br==tamano){
  26.       recep=1;
  27.       br=0;
  28.       tamano=0;
  29.    }
  30. }
  31.  
  32. ...
  33.  
  34. void main (void){
  35.    //VARIABLES MAIN
  36.    //INICIO MODULOS GENERAL
  37. ...
  38.    //INICIO MODULO DIMMER
  39.    port_b_pullups(0b01010001);
  40.    setup_wdt(WDT_ON|WDT_2S);
  41. ...
  42.    RESTART_WDT();
  43.    if(...
  44.       //CONFIGURACION INTERRUPCIONES
  45.       ext_int_edge(L_TO_H);
  46.       setup_timer_0(T0_INTERNAL|T0_DIV_4);
  47.       enable_interrupts(global);
  48.       enable_interrupts(int_ext);
  49.       enable_interrupts(int_rda);         // Interrupción comunicación serial
  50.       enable_interrupts(INT_TIMER0);
  51.       ...
  52.    }
  53.  
  54.    while(true){
  55.       RESTART_WDT();
  56.       // VALIDACIÓN DE RECEPCIÓN
  57.       if(recep==1){
  58.          RESTART_WDT();
  59.          for(pos=0;pos<=br-1;pos++){fun_1(pos,temp[pos]);}
  60.          for(pos=0;pos<=32;pos++){temp[pos]=0;}
  61.          temp2=fun_2();
  62.          fun_3(temp2);
  63.          temp2=0;
  64.          recep=0;
  65.       }
  66. ...
  67.    }
  68. }

Y en la librería está de esta forma:

Código: C
  1. ...
  2.  
  3. void fun_1(int cn,int dato){
  4.         brr[cn]=dato;
  5. }
  6.  
  7. int fun_2(){
  8.         int rx;
  9. ...
  10.         rx=brr[0];
  11. ...
  12. }
  13. ...

Ya está recibiendo datos, lo que sucede es que está haciendo algo que no debería

La función principal del código global es encender o apagar un bombillo de varias formas o a varios niveles (un dimmer)
La prueba la estoy haciendo con dos comandos básicos: encender o apagar
Cualquiera de los dos apaga el LED y lo enciende por algo menos de medio segundo
Solamente hace eso y no lo hace siempre, solo tras varios envíos del comando

No se si puede estar fallando a la hora de hacer la recepción o qué puede ser
« Última modificación: 15 de Julio de 2015, 17:32:05 por joseluislo12 »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Comunicación serial PIC 16F1827
« Respuesta #6 en: 15 de Julio de 2015, 22:58:13 »
Perdona pero hay varios cambios al codigo por lo que veo y ademas yo me olvide de responderte una cosa:

Citar
La verdad no probé lo del WDT, en qué podría afectar eso al funcionamiento del programa ??? No lo entiendo muy bien

El WDT hace que si no se resetea cada cierto tiempo ( es como un timer que esta corriendo siempre ) el micro se resetea. Tal ves en alguna parte  de todo el codigo necesite mas tiempo, y para quitar esto que podria servirte ya para un diseño final pero no en la fase de pruebas es que dije que deberias ponerlo como OFF. Asi descartas ya un posible problema.

Desconectado joseluislo12

  • PIC10
  • *
  • Mensajes: 20
Re: Comunicación serial PIC 16F1827
« Respuesta #7 en: 16 de Julio de 2015, 09:56:28 »
Varios cambios por hacer o varios cambios realizados ??? :huh: :huh: :huh:

Probaré lo del WDT haber cómo resulta todo

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Comunicación serial PIC 16F1827
« Respuesta #8 en: 16 de Julio de 2015, 10:02:55 »
Varios cambios por hacer o varios cambios realizados ??? :huh: :huh: :huh:

Varios cambios realizados  :D, no tuve tiempo de mirarlo, estoy con lo mio xD

Desconectado joseluislo12

  • PIC10
  • *
  • Mensajes: 20
Re: Comunicación serial PIC 16F1827
« Respuesta #9 en: 18 de Julio de 2015, 12:03:04 »
Al final todo ya funcionó correctamente !!!

 :-/ :-/ :-/

Código: C
  1. ...
  2.  
  3. #int_RDA
  4. void RDA_isr(void){
  5.    temp[br]=getc();
  6.    br=br+1;
  7.    if(br==1 && temp[0]!=0x7E){br=0;}
  8.    if(br==3){tamano=temp[2]+4;}
  9.    if(br==tamano){
  10.       br=0;
  11.       recep=1;
  12.       tamano=0;
  13.    }
  14. }
  15.  
  16. void main(){
  17.    ...
  18.  
  19.    enable_interrupts(int_rda);
  20.    enable_interrupts(GLOBAL);
  21.    
  22.    ...
  23.  
  24.    while(TRUE){
  25.       if(recep==1){
  26.          recep=0;
  27.          for(pos=0;pos<32;pos++){func_1(pos,temp[pos]);}
  28.          dato=func_2();
  29.          func_3(dato);
  30.       }
  31.       else if(recep==0){
  32.          ...
  33.       }
  34.    }
  35. }

De esa forma quedó finalmente el código

Muchas gracias a KILLERJC por la ayuda brindada

Ahora el siguiente reto es guardar cosas que lleguen durante la ejecución (porque solo "guarda" en este momento la última que recibe) y hacerlas todas al ir acabando lo primero que recibió

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Comunicación serial PIC 16F1827
« Respuesta #10 en: 18 de Julio de 2015, 12:40:46 »
Citar
Ahora el siguiente reto es guardar cosas que lleguen durante la ejecución (porque solo "guarda" en este momento la última que recibe) y hacerlas todas al ir acabando lo primero que recibió

Por eso decir de poner el

for(pos=0;pos<32;pos++){func_1(pos,temp[pos]);}

dentro de la interrupcion, no creo que tome tanto tiempo como para que se pierdan datos, ya que simplemente es pasar datos de un registro a otro, depende del PIC que sea, puede llevar 2 instrucciones como minimo por cada dato, a 4Mhz a solo tardaria 64us. xD

Desconectado joseluislo12

  • PIC10
  • *
  • Mensajes: 20
Re: Comunicación serial PIC 16F1827
« Respuesta #11 en: 22 de Julio de 2015, 09:45:38 »
Citar
Ahora el siguiente reto es guardar cosas que lleguen durante la ejecución (porque solo "guarda" en este momento la última que recibe) y hacerlas todas al ir acabando lo primero que recibió

Por eso decir de poner el

for(pos=0;pos<32;pos++){func_1(pos,temp[pos]);}

dentro de la interrupcion, no creo que tome tanto tiempo como para que se pierdan datos, ya que simplemente es pasar datos de un registro a otro, depende del PIC que sea, puede llevar 2 instrucciones como minimo por cada dato, a 4Mhz a solo tardaria 64us. xD

Pero esto solo me guarda un dato, porque si mientras está haciendo algo le llegan dos instrucciones, sobreescribe y pierde lo primero (realmente esto no es tan necesario, porque casi siempre será la última la más importante) pero es para que quede un poco más "robusto" el programa

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Comunicación serial PIC 16F1827
« Respuesta #12 en: 22 de Julio de 2015, 12:19:56 »
Eso lo habiamos tratado o en realidad nombrado antes. Por eso habia puesto ese codigo en la interrupcion:

Código: C
  1. if(br==tamano)                            // Llego al final de la trama?, comienzo nuevamente
  2.    {
  3.       if(!recep){for(pos=0;pos<br;pos++){brr[pos]=temp[pos];}}            //Paso los datos al array que se va a usar
  4.       else {while(1);}                         // Aca entraria si hubiera un error, en el que llego una segunda trama por completo y todavia no se proceso la primera. Si queda atorado aca quiere decir que eso ocurrio. Se puede reemplazar por otro codigo, como un
  5.                                                      // led o algo por el estilo que te avise cuando eso ocurra. O directamente descartar la nueva trama que llego hasta que se termine de procesar la que ya habiamos copiado.
  6.       recep=1;                                  // Esto deberia ponerse a 0 en el programa principal, cuando se termina de tratar los datos
  7.       br=0;
  8.    }

ese while se podria reemplazar por cualquier cosa, como encender un led, etc.
En la que habia realizado la analogia del cartero:
Citar
Aca puede ocurrir que al seguir juntando cartas llegue a haber 2 pedidos enteros para vos y vos no pasate a buscarlo, pero solo tiene lugar para uno.. Vos le diras a ese cartero que debe hacer, si tirar el ultimo pedido completo, o dejar de recibir cartas, o hacerle espacio para 2 o mas.

O para que se entienda:

- O haces otro buffer
- O detenes la interrupcion hasta que se procese todo
- O seguis con la interrupcion pero todo lo que llegue se descarta.
- O te aseguras que sea procesado la info antes que se termine otra trama por completo

La primer opcion es irreal... Por que si tu codigo no es capaz de procesar la primera trama antes que este lista la segunda entonces tenes un problema, por que esto quiere decir que esta llegando mas rapido de lo que se puede atender. Y eso significa que por mas que tengas 1000 buffer en algun momento todos se van a llenar.

Las demas son algo mas real y aplicable