Autor Tema: XC8, forma de hacer polling  (Leído 3558 veces)

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

Desconectado Loudness

  • PIC16
  • ***
  • Mensajes: 147
XC8, forma de hacer polling
« en: 05 de Septiembre de 2018, 09:57:05 »
Hola de nuevo.

Despues de un par meses sin poder estudiar el xc8 ahora me he puesto de nuevo y me falla hasta lo mas basico :oops:

Sobre el tema del polling, para hacerlo en ensamblador utilizaba esta secuencia:

Código: [Seleccionar]

POLL

btfss flag_timer1 ; Testea si esta en 1 o en 0
goto POLL         ; Esta en 0, vuelve y espera el cambio indefinidamente
goto siguiente         ; Esta en 1, sigue con el programa


Para hacerlo por xc8, he leido que se puede hacer utilizando un while de esta manera(corregirme si me equivoco):

Código: [Seleccionar]

            while(flag_timer1)         // Espera sin hacer nada el cambio de estado de flag_timer1
                {
                }


El caso es que, al poner esta secuencia en un programa (os lo adjunto) no tiene los resultados esperados.

Segun el programa deseado

1) El timer1 cuenta un segundo (100 interrupciones x 10ms cada una = 1sg)
2) Pone a 1 un bit (bandera) llamado flag_timer1
3) Durante 1 segundo, hasta el cambio de bandera, el programa principal espera sin hacer nada
4) Al cambiar flag_timer1, el programa principal cambia el estado de un led en el PORTC2
5) Vuelve a hacer 1~4 hasta el infinito

Si embargo el resultado es que el led de PORTC2 se apaga y se enciende sin ningun significado (por lo menos para mi :shock:)
y no es problema del timer, eso esa comprobado.

Resumiendo, me gustaria saber si esta es la forma correcta de hacer polling en xc8?
Si no es asi, como se puede hacer polling en XC8?

Se que es una cuestion muy muy basica pero me tiene loco casi-todo el dia :?

Saludos

* main.c
(1.81 kB - descargado 200 veces)

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:XC8, forma de hacer polling
« Respuesta #1 en: 05 de Septiembre de 2018, 13:32:27 »
Tu problema es que flag esta activandose cada ves que entra a la interrupcion, es decir cada 10ms

Tu funcion:

Código: C
  1. void interrupt TMR1_ISR(void)
  2. {
  3.     if (PIR1bits.TMR1IF == 1)                       // Es interrupcion del timer1?
  4.     {
  5.         PIR1bits.TMR1IF = 0;                        // SI. Entonces limpia la bandera de interrupcion
  6.         flag_timer1 = 1;                            // Levanta la bandera para que actue el programa principal
  7.         TMR1H = 0xEC;                               // TMR1H 236;    
  8.         TMR1L = 0x78;                               // TMR1L 120;    
  9.                 if(registro >= 100)
  10.                 {
  11.                     registro = 0;                   // Ha pasado 1 segundo
  12.                     LATCbits.LATC1=~LATCbits.LATC1; // Cambia el del del PORTC1
  13.                 }  
  14.                 else
  15.                 {
  16.                      registro++;    // No ha pasado 1 segundo
  17.                 }
  18.     }
  19. }


Lo que deberias tener:


Código: C
  1. void interrupt TMR1_ISR(void)
  2. {
  3.     if (PIR1bits.TMR1IF == 1)                       // Es interrupcion del timer1?
  4.     {
  5.         PIR1bits.TMR1IF = 0;                        // SI. Entonces limpia la bandera de interrupcion
  6.         TMR1H = 0xEC;                               // TMR1H 236;    
  7.         TMR1L = 0x78;                               // TMR1L 120;    
  8.                 if(registro >= 100)
  9.                 {
  10.                     registro = 0;                   // Ha pasado 1 segundo
  11.                     LATCbits.LATC1=~LATCbits.LATC1; // Cambia el del del PORTC1
  12.                     flag_timer1 = 1;                            // Levanta la bandera para que actue el programa principal
  13.                 }  
  14.                 else
  15.                 {
  16.                      registro++;    // No ha pasado 1 segundo
  17.                 }
  18.     }
  19. }

Desconectado Loudness

  • PIC16
  • ***
  • Mensajes: 147
Re:XC8, forma de hacer polling
« Respuesta #2 en: 05 de Septiembre de 2018, 22:24:16 »
Gracias por la respuesta


Tu problema es que flag esta activandose cada ves que entra a la interrupcion, es decir cada 10ms


 :oops: :oops: :oops: es cierto, un error de falta de atencion jejejeje...

... sin embargo al corregirlo el programa sigue sin funcionar bien.
El led del PORTC1 sigue funcionando bien encendiendo y apagando cada segundo y, sin embargo, el led del PORTC2 sigue siendo intermitente :shock:

Pense que podria ser una "broma" del proteus (ya me ha pasado antes) pero parece que no.
Probando con el simulador del MPLAB X la parte del polling:

Código: [Seleccionar]
             flag_timer1 = 0;                // Baja la bandera de interrupcion
             while(flag_timer1)         // Espera sin hacer nada la interrupcion del timer1
                {
                }

se la salta o bien la hace de manera caotica... Esta parte esta bien escrita? Un polling tampoco puede ser tan complicado...

Te envio los archivos del programa y la simulacion del proteus, si tienes tiempo dale un vistazo.

Saludos
* 180906.zip
(22.43 kB - descargado 218 veces)

Desconectado Loudness

  • PIC16
  • ***
  • Mensajes: 147
Re:XC8, forma de hacer polling
« Respuesta #3 en: 06 de Septiembre de 2018, 05:08:57 »
Sigo con el tema pero cada vez lo entiendo menos :5] :5] :5]

En el programa anterior he cambiado esta parte:

Código: [Seleccionar]
void main(void)
{
    IO_CONFIG();                        // Solo la primera vez
    TMR1_Initialize();                  // Configura el timer1
    TMR1_StartTimer();                  // Empieza a contar
    while(1)     
    {
        flag_timer1 = 0;                              // Baja la bandera de interrupcion
             while(flag_timer1)                      // Espera sin hacer nada la interrupcion del timer1
                {
                }
        LATCbits.LATC2=~LATCbits.LATC2;   // Cuando hay interrupcion cambia el led del PORTC2
    }
}       


por esta otra opcion:

Código: [Seleccionar]
void main(void)
{
    IO_CONFIG();                        // Solo la primera vez
    Configuration_ADC_AN0();
    TMR1_Initialize();                  // Configura el timer1
    TMR1_StartTimer();                  // Empieza a contar
    while(1)     
    {
       flag_timer1 = 0;
        if(flag_timer1 == 1)                                    // Espera sin hacer nada la interrupcion del timer1
                {
                    LATCbits.LATC2=~LATCbits.LATC2; // Cuando hay interrupcion cambia el led del PORTC2
                    flag_timer1 = 0;                           // Baja la bandera de interrupcion
                } 
                else
                {
                _nop();                             // Si no hay interrupcion no hace nada
                }
    }
}     

Es decir, para hacer polling en flag_timer1 he utilizado if/else en vez de while y el programa ha funcionado, primero con el simulador de MPLAB X y luego en el proteus 8).

Bueno, hasta aqui todo bien verdad?.

Me llaman, me voy a hacer otra cosa, apago el ordenador un par de horas, vuelvo, lo enciendo de nuevo, pruebo el simulador del MPLAB y no funciona, me pasa como con el while, que hace lo que le viene en gana :shock:

Pruebo con el simulador del MPLAB y al llegar a

Código: [Seleccionar]

flag_timer1 = 0;


se salta la instruccion y me suelta este error

Citar

Break point at line 35 in file E:/Programas X C/Pruebas_C/main.c cannot be resolved to a valid program memory address"


La primera vez que lo veo :shock:. Buscando en la web parece que hay gente que ha tenido este error provocado por una version antigua de mplab o por el desborde del watchdog pero mi version es la 4.15 y no utilizo el watchdog :?...

Que puede ser? Me estoy volviendo loco? Tengo cura, doctor?

Desconectado Loudness

  • PIC16
  • ***
  • Mensajes: 147
Re:XC8, forma de hacer polling
« Respuesta #4 en: 06 de Septiembre de 2018, 05:18:32 »
Despues de escribir el mensaje anterior he compilado de nuevo (sin tocar nada del programa) y ya no ha salido ningun error, el programa funciona :8}

Decidido, lo dejo.

Voy a estudiar electronica analogica.
Pienso hacerlo todo a base de integrados, nada de programacion.

Que les vaya bien, los quiero.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:XC8, forma de hacer polling
« Respuesta #5 en: 06 de Septiembre de 2018, 08:29:29 »
Citar
Despues de escribir el mensaje anterior he compilado de nuevo (sin tocar nada del programa) y ya no ha salido ningun error, el programa funciona


Jajaja no te preocupes, te voy a explicar cual es el problema.


Código: C
  1. volatile int flag_timer1;
  2.  
  3. void main(void)
  4. {
  5.     IO_CONFIG();                        // Solo la primera vez
  6.     TMR1_Initialize();                  // Configura el timer1
  7.     TMR1_StartTimer();                  // Empieza a contar
  8.     while(1)    
  9.     {
  10.         flag_timer1 = 0;                              // Baja la bandera de interrupcion
  11.         while(!flag_timer1);                      // Espera sin hacer nada la interrupcion del timer1
  12.         LATCbits.LATC2=~LATCbits.LATC2;   // Cuando hay interrupcion cambia el led del PORTC2
  13.     }
  14. }

2 cosas ahi..

La primera es ponerle "volatile" a las variables que uses en interrupciones y en el main. Ya que sino el compilador las optimiza, y como no hay conexion  por software de la interrupcion y el main, elimina intrucciones, y luego ocurren los errores que vos tenes que dice que no corresponde a un espacio en memoria. Esta es la regla general, luego vas a entender que hace volatile.

La segunda que en el while, deberia negarse como puse. Las condiciones son true o false, es considera false unicamente el valor 0 o false. Todo lo demas es considerado true. Asi que si flag_timer vale 100 y pones while(!100), como el ! es un operador logico (true/false) primero se evalua el 100 si es true o false, quedando: while(!true), y luego while(false) pasando l negacion. En este caso, apenas entra es 0 por lo tanto false, y al negarlo queda true, asi que queda encerrado hasta que lo cambia la interrupcion.

Tu programa es "bloqueante" ya que se queda encerrado en un while para siempre, asi que prefiero algo asi:

Código: C
  1. volatile int flag_timer1;
  2.  
  3. void main(void)
  4. {
  5.     IO_CONFIG();                        // Solo la primera vez
  6.     TMR1_Initialize();                  // Configura el timer1
  7.     TMR1_StartTimer();                  // Empieza a contar
  8.     while(1)    
  9.     {
  10.         if(flag_timer1)
  11.         {
  12.            flag_timer1 = 0;                              // Baja la bandera de interrupcion
  13.            LATCbits.LATC2=~LATCbits.LATC2;   // Cuando hay interrupcion cambia el led del PORTC2
  14.         }
  15.    }
  16. }

De esta forma nuestro while principal continua con lo que puede seguir.

Desconectado Loudness

  • PIC16
  • ***
  • Mensajes: 147
Re:XC8, forma de hacer polling
« Respuesta #6 en: 06 de Septiembre de 2018, 10:02:30 »
Gracias KILLERJC ((:-))


Voy a estudiar electronica analogica.
Pienso hacerlo todo a base de integrados, nada de programacion.


... esperemos un poco, no he llegado hasta aqui desde la nada para rendirme ahora :D

Lo del volatile no lo sabia. De momento lo he puesto y parece que el programa funciona.

No se si esta relacionado (creo que no) pero para esta linea:

Código: [Seleccionar]

LATCbits.LATC2=~LATCbits.LATC2;


me sale el siguiente warning:

Citar

main.c:31: warning: (373) implicit signed to unsigned conversion


En otros programas al declarar variables a veces me sale el mismo warning y a veces consigo eliminarlo cambiando el tipo de variables (desde signed a unsigned o al reves,etc...) un poco "al tiento".
Pero LATC no es una variable que haya declarado yo asi que no se muy bien que hacer para quitar el warning :?.

Si, ya se que los warning dejan compilar y en muchos casos no suponen un gran problema para el programa, pero creo que tambien son fuente de problemas si se dejan sin hacer caso, asi que no puedo evitar pensar en ello...

Gracias por su paciencia





Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:XC8, forma de hacer polling
« Respuesta #7 en: 06 de Septiembre de 2018, 14:07:08 »
Podes probar:

Código: C
  1. LATCbits.LATC2= !LATCbits.LATC2;
  2.  
  3. LATCbits.LATC2 ^= 1;

El primero, transforma el LATCbits.LATC2 en un booleano ( false/true) y luego lo niega, asignandoselo a LATC2.
El segundo le hace una XOR al valor de LATC2, al hacer una XOR con 1, termina invirtiendo el valor.

Desconectado Loudness

  • PIC16
  • ***
  • Mensajes: 147
Re:XC8, forma de hacer polling
« Respuesta #8 en: 07 de Septiembre de 2018, 09:19:08 »
Gracias por la respuesta.

Al intentar esta forma

Código: [Seleccionar]

LATCbits.LATC2 ^= 1;


el warning ha desaparecido ((:-))

La semana que viene estoy ocupado asi, de momento, se acabo el c :cry: pero, dentro de poco, estare por aqui para molestarles de nuevo jejeje.


Saludos


 

anything