Autor Tema: Problema con el modo Sleep + RS232  (Leído 4027 veces)

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

Desconectado Chenao

  • PIC18
  • ****
  • Mensajes: 414
Problema con el modo Sleep + RS232
« en: 07 de Enero de 2014, 18:16:27 »
Saludos a todos

Resulta que estoy haciendo una pequeña aplicación en la cual estoy comunicando unos equipos vía inalámbrica, estos equipos se comunican cada cierto tiempo, y por lo tanto, el tiempo restante es deseable que los equipos se encuentren consumiendo la menor cantidad de energía posible, estos equipos se encuentran conformados básicamente por un microcontrolador PIC16F886 y un modulo Xbee pro, la primera parte del problema que estoy atacando es optimizar el consumo energético del microcontrolador después atacaré el problema del consumo de energía del equipo Xbee.

Según el datasheet del PIC16F886 más exactamente en la sección AUTO - WAKE -UP ON BREAK (página 166) explican un método de despertar el microcontrolador por medio de una interrupción en la transmisión o recepción del USART, de lo anterior he construido el siguiente código el cual realiza una tarea muy sencilla, en forma resumida el código trasmite un dato cada vez que recibe por la USART el carácter 'y', el objetivo del programa es que el micro se despierte cuando reciba algún dato por el USART y si el dato recibido es el correcto entonces trasmite el respectivo dato por el mismo canal, posteriormente el micro entra en modo sleep hasta que vuelva a recibir un nuevo dato.

Código: [Seleccionar]
#if defined(__PCM__)
#include <16f886.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock = 4000000)
#use rs232(baud = 9600, xmit = PIN_C6, rcv = PIN_C7)
#use standard_io(c)

int dato;
float contador,caudal;

// Función de interrupción por recepción en modo asíncrono
#INT_RDA
void recepcion()
 {
   // Se captura el valor del dato transmitido
   dato = getch();
   // Si el dato recibido es y entonces transmite el caudal
   if (dato == 0x79)
    {
     caudal = 10*contador;
     printf("%f", caudal);
     contador = 0;
    }
 }
 
// Función de interrupción por cambio de flanco en RB0
#INT_EXT
void externa()
 {
   // Si entra a la interrupción se incrementa el contador que lleva la cuenta
   // de los pulsos enviados por el medidor de caudal en respectivo tiempo de
   // Muestreo
   contador = contador + 1;
 }

void main()
  {
    //float caudal;
    // Puerto a y b como entradas digitales
    set_tris_b(0xff);
    set_tris_a(0xff);
    // Se configuran las interrupciones por recepción en Rs232 y por cambio de flancon en RB0
    enable_interrupts(INT_RDA);
    enable_interrupts(INT_EXT);
    enable_interrupts(GLOBAL);
    // Se configura el flanco de activación de la interrupción externa
    ext_int_edge(H_TO_L );
    // Se inicializan las variables de interés
    caudal = 0;
    contador = 0;
    // Se actival la pull-up en el puerto B del micro
    port_b_pullups(TRUE);
    setup_uart(UART_WAKEUP_ON_RDA);
    do
     {
      sleep();    // Se queda dormido hasta que ocurra la interrupción por trasmisión o recepción en la USART
     }while(true);
  }

El programa lo he simulado en el proteus 7.2 y funciona sin problema alguno, pero cuando lo implemento en físico no funciona, es decir, el micro se queda dormido, además, he concluido que si se queda dormido por que al eliminar la instrucción sleep() del código el programa hace lo requerido en el circuito físico.

Agradecería cualquier tipo de consejo, comentario, recomendación para sacar adelante el proyecto.              
Un saludo desde Pereira - Colombia

Desconectado HJG

  • PIC12
  • **
  • Mensajes: 77
Re: Problema con el modo Sleep + RS232
« Respuesta #1 en: 07 de Enero de 2014, 19:33:38 »
El problema, me parece, está en esta parte del código.

Código: [Seleccionar]

  do
     {
      sleep();    // Se queda dormido hasta que ocurra la interrupción por trasmisión o recepción en la USART
     }while(true);

Cuando se despierta, el mismo lazo lo vuelve a dormir... Ojo que lo digo desde mi desconocimiento del lenguaje que utilizas, pero no veo nada que lo saque del lazo Do...While.

Saludos
HJ
« Última modificación: 07 de Enero de 2014, 20:23:58 por HJG »

Desconectado Chenao

  • PIC18
  • ****
  • Mensajes: 414
Re: Problema con el modo Sleep + RS232
« Respuesta #2 en: 07 de Enero de 2014, 22:09:32 »
Gracia por responder HJG

No creo que ese sea el problema ya que cuando el microcontrolador se interrumpe por recepción en la USART se ejecuta la función asociada al respectivo evento que la genera es decir, la función.
Código: [Seleccionar]
void recepcion()
En teoría el micro se despierta ya que existe un cambio de estado en los terminales RX/TX generando un petición de interrupción por recepción en la USART.

Creo que el problema es de configuración, voy a seguir leyendo a ver con que me encuentro.
« Última modificación: 07 de Enero de 2014, 22:19:39 por Chenao »
Un saludo desde Pereira - Colombia

Desconectado HJG

  • PIC12
  • **
  • Mensajes: 77
Re: Problema con el modo Sleep + RS232
« Respuesta #3 en: 08 de Enero de 2014, 00:09:02 »
Hola, puedo estar equivocado, pero tengo entendido que el micro, cuando despierta de un SLEEP por una interrupción, siempre ejecuta al siguiente instrucción al SLEEP, ya que el PC pasa a valer PC+1, al menos en ASM... pero al desconocer como trabaja tu compilador, no se que se estará ejecutando.


Desconectado sander

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 624
Re: Problema con el modo Sleep + RS232
« Respuesta #4 en: 08 de Enero de 2014, 00:30:51 »
Creo que se cual es el problema, recuerdo que la funcionalidad de despertar al recibir un caracter por el puerto serial solo se puede realizar con micros que traen el EUSART, el PIC16F886 lo trae, pero aqui viene el detalle primero tiene que enviarle al micro el caracter BREAK ,es decir 0x00, no puede tomar el primer caracter como valido, creo que ahi esta su error.

En la hoja de datos en la seccion AUTO-WAKE-UP ON BREAK se encuentran los pasos a seguir para salir del SLEEP, la verdad no se como lo hara el CCS, talvez deba declarar los registros y los bits involucrados para hacerlo a mano.

Saludos.
La electrónica es el arte de manipular señales eléctricas que transportan información
Jan Davidse

Visita mi blog
Visita mi canal de youtube

Desconectado Chenao

  • PIC18
  • ****
  • Mensajes: 414
Re: Problema con el modo Sleep + RS232
« Respuesta #5 en: 08 de Enero de 2014, 14:07:23 »

Saludos a todos gracias por responder

Citar
pero tengo entendido que el micro, cuando despierta de un SLEEP por una interrupción, siempre ejecuta al siguiente instrucción al SLEEP, ya que el PC pasa a valer PC+1

Sinceramente nunca había trabajado con el modulo sleep de los microcontroladores pero según entiendo el micro puede salir de tal estado a producirse ciertas interrupciones ya sean por hardware o por software (esto depende del micro), una vez la rutina de interrupción se ejecuta el microcontrolador retorna al PC +1 pero tengo entendido que primeramente ejecuta las instrucciones que se encuentra en la respectiva interrupción que lo saco de tal estado.

Citar
Creo que se cual es el problema, recuerdo que la funcionalidad de despertar al recibir un caracter por el puerto serial solo se puede realizar con micros que traen el EUSART, el PIC16F886 lo trae, pero aqui viene el detalle primero tiene que enviarle al micro el caracter BREAK ,es decir 0x00, no puede tomar el primer caracter como valido, creo que ahi esta su error.

En la hoja de datos en la seccion AUTO-WAKE-UP ON BREAK se encuentran los pasos a seguir para salir del SLEEP, la verdad no se como lo hara el CCS, talvez deba declarar los registros y los bits involucrados para hacerlo a mano.

He vuelto a leer la sección AUTO - WAKE - UP ON BREAK y en efecto primeramente se necesita enviar en token BREAK gracias por el dato voy a realizar las respectivas modificaciones y luego les cuento.   
Un saludo desde Pereira - Colombia

Desconectado HJG

  • PIC12
  • **
  • Mensajes: 77
Re: Problema con el modo Sleep + RS232
« Respuesta #6 en: 08 de Enero de 2014, 16:55:48 »

Citar
pero tengo entendido que el micro, cuando despierta de un SLEEP por una interrupción, siempre ejecuta al siguiente instrucción al SLEEP, ya que el PC pasa a valer PC+1

Sinceramente nunca había trabajado con el modulo sleep de los microcontroladores pero según entiendo el micro puede salir de tal estado a producirse ciertas interrupciones ya sean por hardware o por software (esto depende del micro), una vez la rutina de interrupción se ejecuta el microcontrolador retorna al PC +1 pero tengo entendido que primeramente ejecuta las instrucciones que se encuentra en la respectiva interrupción que lo saco de tal estado.
Fijate en la imagen que te mostré, cuando el micro se despierta primero se ejecuta la instrucción de PC+1 y luego va ha la interrupción, tal como o aclara la Nota 1, por eso en ASM siempre se coloca un NOP después de un SLEEP.

Saludos
HJ

Desconectado Chenao

  • PIC18
  • ****
  • Mensajes: 414
Re: Problema con el modo Sleep + RS232
« Respuesta #7 en: 10 de Enero de 2014, 23:22:33 »

Saludos a todos

Citar
Fijate en la imagen que te mostré, cuando el micro se despierta primero se ejecuta la instrucción de PC+1 y luego va ha la interrupción, tal como o aclara la Nota 1, por eso en ASM siempre se coloca un NOP después de un SLEEP.

En efecto HJG lo he comprobado experimentalmente aunque ya da señales de vida todavía no lo he podido poner a funcionar como debe ser. Siguiendo el método que se enseña en el respectivo datasheet primeramente se debe enviar el token break, es decir, que desde el dispositivo coordinador se debe enviar 0x00 seguidamente se debe enviar el token para reiniciar el bit WUE (0xff), una vez estos token han sido enviados correctamente el microcontrolador se debe despertar y la USART debe funcionar normalmente. Los resultados que obtengo son algo frustrantes debido a que algunas veces funciona durante un par de minutos después de eso el microcontrolador se duerme y no hay quien lo haga despertar otras veces desde el inicio se queda dormido si respuesta alguna y casos similares. Sigo dando la pelea creo estar cerca de la solución, toca seguir leyendo y probando.

Acá el código, aunque en esencia es el mismo (un par de modificaciones) el que he cambiado significativamente es el programa que se encarga de enviar datos al microcontrolador el cual esta hecho en python.

Código: [Seleccionar]
#if defined(__PCM__)
#include <16f886.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock = 4000000)
#use rs232(baud = 9600, xmit = PIN_C6, rcv = PIN_C7)
#use standard_io(c)

int dato,Envia;
float contador,caudal;

// Función de interrupción por recepción en modo asíncrono
#INT_RDA
void recepcion()
 {
   // Se captura el valor del dato transmitido
   dato = getch();
   //setup_uart(UART_WAKEUP_ON_RDA);
   // Si el dato recibido es y entonces transmite el caudal
   if (dato == 0x79)
    {
     Envia = 1;
    }
 }
 
// Función de interrupción por cambio de flanco en RB0
#INT_EXT
void externa()
 {
   // Si entra a la interrupción se incrementa el contador que lleva la cuenta
   // de los pulsos enviados por el medidor de caudal en respectivo tiempo de
   // Muestreo
   contador = contador + 1;
 }

void main()
  {
    //float caudal;
    // Puerto a y b como entradas digitales
    set_tris_b(0xff);
    set_tris_a(0xff);
    // Se configuran las interrupciones por recepción en Rs232 y por cambio de flancon en RB0
    enable_interrupts(INT_RDA);
    enable_interrupts(INT_EXT);
    enable_interrupts(GLOBAL);
    // Se configura el flanco de activación de la interrupción externa
    ext_int_edge(H_TO_L );
    // Se inicializan las variables de interés
    caudal = 0;
    contador = 0;
    // Se actival la pull-up en el puerto B del micro
    port_b_pullups(TRUE);
    //setup_uart(UART_WAKEUP_ON_RDA);
    do
     {
      setup_uart(UART_WAKEUP_ON_RDA);
      sleep();    // Se queda dormido hasta que ocurra la interrupción por trasmisión o recepción en la USART
      delay_ms(5);
      if(Envia == 1)
       {
        caudal = 10*contador;
        printf("%f", caudal);
        contador = 0;
        Envia = 0;
       }
     }while(true);
  }
         
Un saludo desde Pereira - Colombia

Desconectado sander

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 624
Re: Problema con el modo Sleep + RS232
« Respuesta #8 en: 11 de Enero de 2014, 01:27:13 »
Ahora que lei con calma el auto-wake-up o break, y  analice la figura 12-8, creo que no lo hace bien, yo lo haria de la siguiente forma:

-  primero definiria el bit wue haciendo  #bit  WUE = 0x187.1  (creo que asi se hacia en CCS).
-  declararia una bandera micro_on_sleep, para indicar que el micro estaba durmiendo. En la interrupcion haria:

Código: C
  1. #INT_RDA
  2. void recepcion()
  3.  {
  4.      if(micro_on_sleep)
  5.      {
  6.           while(WUE == 1);       //Espera que WUE se ponga en cero (Segun la hoja de datos sucede cuando
  7.                                            //el tiempo de duracion del caracter break termino y la linea de recepcion va a uno)
  8.           micro_on_sleep = 0;   //Indica que el micro esta despierto.
  9.           dato = getch();          //Limpia la bandera RCIF
  10.       }
  11.       else
  12.       {
  13.                                            //Ahora estamos recibiendo datos validos
  14.           dato = getch();
  15.           if (dato == 0x79)
  16.          {
  17.             Envia = 1;
  18.            }
  19.        }
  20.  }

La parte del sleep seria asi:

Código: C
  1. micro_on_sleep = 1;
  2. do
  3.      {
  4.      
  5.       setup_uart(UART_WAKEUP_ON_RDA);  // creo que es Equivalente a WUE = 1
  6.       sleep();    // Se queda dormido hasta que ocurra la interrupción por trasmisión o recepción en la USART
  7.      
  8.       delay_us(2);       //para que se ejecute la interrupcion del break
  9.  
  10.      while(micro_on_sleep == 0)
  11.      {                         //Espera a recibir carateres , se puede colocar un timeout para que no se quede esperando
  12.       if(Envia == 1)
  13.        {
  14.         caudal = 10*contador;
  15.         printf("%f", caudal);
  16.         contador = 0;
  17.         Envia = 0;
  18.         micro_on_sleep = 1;
  19.        }
  20.      }
  21.      }while(true);

Segun lo que entendi esa seria una manera correcta de hacerlo, una recomendacion mas el programa de la computadora deberia esperar un tiempo antes de enviar el caracter 0x79, ya que el oscilador debe estar estable para que la recepcion sea correcta.

Saludos
La electrónica es el arte de manipular señales eléctricas que transportan información
Jan Davidse

Visita mi blog
Visita mi canal de youtube

Desconectado Chenao

  • PIC18
  • ****
  • Mensajes: 414
Re: Problema con el modo Sleep + RS232
« Respuesta #9 en: 13 de Enero de 2014, 22:09:25 »
Saludos a todos

Al fin funciona como se quería, habían varios problema, el primero era el que comentaba el compañero sander en el post anterior, el otro era un problema con el programa que se encargaba de enviar los datos al microcontrolador (se estaba configurando mal el canal RS232), y el otro si que era un error inocente, resulta que la batería de 9 v ya se había agotado y pues claro el circuito funcionaba a veces si a veces no. Pongo el programa completo por si alguien en el futuro le sirve.

Código: [Seleccionar]
#if defined(__PCM__)
#include <16f886.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock = 4000000)
#use rs232(baud = 9600, xmit = PIN_C6, rcv = PIN_C7)
#use standard_io(c)
#bit WUE = 0X187.1

int dato,Envia,duerme;
float contador,caudal;

// Función de interrupción por recepción en modo asíncrono
#INT_RDA
void recepcion()
 {
   // Se captura el valor del dato transmitido
   if(duerme)
    {
     while(WUE==1);
     duerme = 0;
     dato = getch();
    }
   else
    {
     dato = getch();
   //setup_uart(UART_WAKEUP_ON_RDA);
   // Si el dato recibido es y entonces transmite el caudal
     if (dato == 0x79)
      {
       Envia = 1;
      }
    }  
 }
 
// Función de interrupción por cambio de flanco en RB0
#INT_EXT
void externa()
 {
   // Si entra a la interrupción se incrementa el contador que lleva la cuenta
   // de los pulsos enviados por el medidor de caudal en respectivo tiempo de
   // Muestreo
   contador = contador + 1;
 }

void main()
  {
    int conta;
    //float caudal;
    // Puerto a y b como entradas digitales
    set_tris_b(0xff);
    set_tris_a(0xff);
    // Se configuran las interrupciones por recepción en Rs232 y por cambio de flancon en RB0
    enable_interrupts(INT_RDA);
    enable_interrupts(INT_EXT);
    enable_interrupts(GLOBAL);
    // Se configura el flanco de activación de la interrupción externa
    ext_int_edge(H_TO_L );
    // Se inicializan las variables de interés
    caudal = 0;
    contador = 0;
    // Se actival la pull-up en el puerto B del micro
    port_b_pullups(TRUE);
    duerme = 1;
    conta = 0;
    Envia = 0;
    do
     {
      setup_uart(UART_WAKEUP_ON_RDA);
      sleep();    // Se queda dormido hasta que ocurra la interrupción por trasmisión o recepción en la USART
      delay_us(8);
      while(duerme == 0)
      {
        if(Envia == 1)
         {
          caudal = 10*contador;
          printf("%f", caudal);
          contador = 0;
          Envia = 0;
          duerme = 1;
         }
       }
     }while(true);
  }

Ahora sigue el problema de minimizar el consumo de energía del equipo XBEE, cualquier inquietud por acá voy a estar preguntando, muchas gracias a los compañeros sander y HJG por sus amables sugerencias.
 
« Última modificación: 13 de Enero de 2014, 22:11:28 por Chenao »
Un saludo desde Pereira - Colombia

Desconectado sosa2008

  • PIC10
  • *
  • Mensajes: 1
Re:Problema con el modo Sleep + RS232
« Respuesta #10 en: 26 de Enero de 2016, 00:40:53 »
Hola tengo una duda respecto a salir del modo sleep con el rs232, yo debo enviarle un break, este break corresponde al 0x00 y este sale solo del modo sleep automaticamente. Saludos

Desconectado Chenao

  • PIC18
  • ****
  • Mensajes: 414
Re:Problema con el modo Sleep + RS232
« Respuesta #11 en: 26 de Enero de 2016, 12:49:09 »
Buen día

En parte, primero debes enviar el break y luego esperar a que responda el microcontrolador a través del bit WUE esta respuesta es una señal de que la máquina ha salido del modo bajo consumo energético. Luego ya puedes enviar el dato de interés por el canal.
Un saludo desde Pereira - Colombia

Desconectado al_peli

  • PIC10
  • *
  • Mensajes: 1
Re:Problema con el modo Sleep + RS232
« Respuesta #12 en: 03 de Noviembre de 2016, 07:40:02 »
Hola, estoy trabajando en un proyecto similar: comunicando un PIC18f45k20 por medio del módulo USART a un Xbee. Efectivamente, una vez duermes el pic no se despierta con la interrupción de RX usart, por lo que se debe implementar el mecanismo Auto-wake up. Para este, se debe mandar un caracter break que debe ser todo ceros.
Como podería hacer esto si estoy usando el modo API en los Xbee?

Muchas gracias.