Autor Tema: problemas con interrupcion y maquina de estados  (Leído 284 veces)

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

Desconectado rafagranada

  • PIC10
  • *
  • Mensajes: 7
problemas con interrupcion y maquina de estados
« en: 03 de Septiembre de 2024, 06:17:59 »
buenos dias a todos

estoy haciendo una maquina de estados para que cuando reciba una interrupcion por el int RB o por el RB0 externa( me da igual )y comience a contar 5 segundos, y si no recibo nada pase de nuevo a estado inicial,
si en esos 5 segundos llega otra interrupcion pase al estado dos, vuelva a contar 5 segundos y si no llega otra interrupcion, pase al estado inicial,
si en esos 5 segundos llega otra interrupcion me pase al estado 3 que seria activar una salida del puerto RA.

os dejo el codigo que tengo hasta ahora a ver que veis raro

tambien dejo en un zip, todos los archivos proteux y picc

muchas gracias!!!



#include "D:\Documentos\programaciones\control motor ACS\bomba2.h"

#byte pb=6
#byte pa=5

int state = 0; // IDLE
int count_down=1; // seconds
int ia = 0;
int ib = 0;
int states=0;
int contador=0;
void states();
void stateA();
void stateB();
void startBomba();



#int_RB
EXT_isr()
{
// 0 = IDLE
   // 1 = STATE_A
   // 2 = STATE_B
   // 3 = END / START_BOMBA
     disable_interrupts(INT_RB);
   disable_interrupts(GLOBAL);
   output_high(PIN_A0);// 3 = END
   state ++;
   states();
 
       enable_interrupts(INT_RB);
   enable_interrupts(GLOBAL);
 
}

void states()
{
 
 if (state == 1) {
      //state = 1;
      stateA();
   } else if (state ==2) {
      //state = 2;
      stateB();
   } else if (state == 3) {
      //state = 3;
      startBomba();
   } else {
      // imposible state => IDLE
      state = 0;
      output_low(PIN_A0);

}
}


void stateA()
{
   output_high(PIN_A1);
   for (ia=0; ia<count_down*100; ia++) { // wait for X sec
      contador++;
   }
   output_low(PIN_A1);
 
   if (state == 1) {
      state = 0; // IDLE
      //output_low(PIN_A0);
   }
}

void stateB()
{
   output_high(PIN_A2);
   for (ib=0; ib<count_down*300; ib++) { // wait for X sec
      contador++;
      }
   output_low(PIN_A2);
 
   if (state == 2) {
      state = 0; // IDLE
   }
}

void startBomba()
{
   output_high(PIN_A3);
   delay_ms(1000);
   output_low(PIN_A3);

   state = 0; // IDLE
}




void main()
{


// 0. idle
   // A. Boton arranque: count_down = 5sec
   // B. Boton arranque: count_down = 5sec
   // Finish. Boton arranque: start
pa=0;

   //setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   enable_interrupts(INT_RB);
   enable_interrupts(GLOBAL);
   

while(true);


}

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1937
    • Sicoy
Re:problemas con interrupcion y maquina de estados
« Respuesta #1 en: 03 de Septiembre de 2024, 13:17:59 »
La máquina de estado creo que debería ser así.

Código: C
  1. void main()
  2. {
  3.     while(true)
  4.     {
  5.         task();
  6.     }
  7. }
  8.  
  9. ....
  10.  
  11. void task ()
  12. {
  13.     switch (state)
  14.     {
  15.         case 0: break; //IDLE
  16.         case 1:
  17.         {
  18.             if (getTimer() - valorInst) > 5000)
  19.             {
  20.                 state = 0;
  21.             }
  22.             break;
  23.         }
  24.         case 2:
  25.         {
  26.             if (getTimer() - valorInst) > 5000)
  27.             {
  28.                 state = 0;
  29.             }
  30.             break;
  31.         }
  32.         default: //Case int32_t
  33.         {
  34.             //activo la salida RA3
  35.             //Luego de esto a dónde debe ir?
  36.         }
  37.     }
  38. }

La interrupción sería así:

Código: C
  1. EXT_isr()
  2. {
  3.     switch (case)
  4.     {
  5.         case 0: state = 1; break;
  6.         case 1: state = 2; break
  7.         default: state = 3; break;
  8.     }
  9.     valorInst = getTimer(); //capturo un valor del contador de milisegundos para un nuevo retardo asincrónico
  10. }

Para el retardos asincrónico, deberías usar un temporizador que produzca una interrupción cada 1 ms, y incrementas en 1  a una variable, un pseudocoidgo sería:

Código: C
  1. InterrupcionTimerCada1ms()
  2. {
  3.     variable++;
  4. }
  5.  
  6. uint16_t getTimer()
  7. {
  8.     return variable;
  9. }

Lo que deberías considerar, es que a pesar que las variables usadas en (getTimer() - valorInst), deben ser enteras sin signo, es posible que esa diferencia te de un valor negativo (restar un número mayor de un menor), si es así, debes obtener el valor absoluto.
Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Desconectado rafagranada

  • PIC10
  • *
  • Mensajes: 7
Re:problemas con interrupcion y maquina de estados
« Respuesta #2 en: 04 de Septiembre de 2024, 08:50:53 »
Hola DominusDRR

muchas gracias por tu respuesta.

en el default, que me preguntas donde deberia de ir, se supone que al terminar de activar y desactivar la RA3, debe de quedarse a la espera de cuando se vuelve a realizar el ciclo de los dos cases.

lo que no entiendo es lo que me explicas del retardo asincrono para la interrupcion de 1ms. eso de donde lo saco?

muchas gracias de nuevo por tu ayuda.

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1937
    • Sicoy
Re:problemas con interrupcion y maquina de estados
« Respuesta #3 en: 04 de Septiembre de 2024, 14:12:34 »
Hola DominusDRR

muchas gracias por tu respuesta.

en el default, que me preguntas donde deberia de ir, se supone que al terminar de activar y desactivar la RA3, debe de quedarse a la espera de cuando se vuelve a realizar el ciclo de los dos cases.

lo que no entiendo es lo que me explicas del retardo asincrono para la interrupcion de 1ms. eso de donde lo saco?

muchas gracias de nuevo por tu ayuda.

El retardo asincrónico son los if que esperan a que se cuente 5000 para conseguir 5 segundos.

Me imagino que sabes configurar alguno de los temporizadores que posee el microcontrolador, para que siempre esté generando una interrupción cada 1 ms.
En esa interrupción, incrementas en 1 una variable (puede ser de 16 bits), nuevamente escribo el pseudocódigo de eso:

Código: C
  1. InterrupcionTimerCada1ms()
  2. {
  3.     variable++;
  4. }
  5.  
  6. uint16_t getTimer()
  7. {
  8.     return variable;
  9. }

Completando tu código creo que tu proyecto quedaría así

Código: C
  1. void task ()
  2. {
  3.     switch (state)
  4.     {
  5.         case 0: break; //IDLE
  6.         case 1:
  7.         {
  8.             if (getTimer() - valorInst) > 5000)
  9.             {
  10.                 state = 0;
  11.                 return; // para que no ejecute el código de abajo
  12.             }
  13.             /** equivale stateA()**/
  14.             if (getTimer() - valorInst) > X) //espero un tiempo X, obviamente menor a 5000ms
  15.             {
  16.                 output_low(PIN_A1);
  17.                 state = 0;
  18.             }
  19.             /****/
  20.             break;
  21.         }
  22.         case 2:
  23.         {
  24.             if (getTimer() - valorInst) > 5000)
  25.             {
  26.                 state = 0;
  27.             }
  28.              /** equivale stateB()**/
  29.             if (getTimer() - valorInst) > X) //espero un tiempo X, obviamente menor a 5000ms
  30.             {
  31.                 output_low(PIN_A2);
  32.                 state = 0;
  33.             }
  34.             /****/
  35.             break;
  36.         }
  37.         case 3://START_BOMBA
  38.         {
  39.             output_high(PIN_A3);
  40.             valorInst = getTimer();
  41.             state = 4;
  42.             break;
  43.         }
  44.         default:
  45.         {
  46.             if (getTimer() - valorInst) > 1000) //espero 1000 ms
  47.             {
  48.                 output_low(PIN_A3);
  49.                 state = 0;
  50.             }
  51.         }
  52.     }
  53. }

Lo primero que debes hacer, es configurar a un temporizador para generar una interrupción cada 1 ms, y en esa interrupción incrementar en 1, variable



Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Desconectado DominusDRR

  • PIC24H
  • ******
  • Mensajes: 1937
    • Sicoy
Re:problemas con interrupcion y maquina de estados
« Respuesta #4 en: 04 de Septiembre de 2024, 14:23:43 »
Me olvidaba, valorInst y variable, deben ser sin signo.

El algún momento, al realizar la resta en los if:

getTimer() - valorInst

Pueda que getTimer retorne un valor menor que valorInst, en algunos compiladores dará un resultado negativo a pesar que son variables sin signo, en otros no habrá problema.

Puedes hace una prueba restando dos variables del mismo tipo y sin signo para determinar si existe ese problema.

Si es así, necesitas obtener el valor absoluto de esa resta, puedes recurrir a una función propia de tu compilador, o crear la tuta, algo así puede ser:

Código: C
  1. uint16_t abs_diff(uint16_t a, uint16_t b)
  2. {
  3.     return (a > b) ? (a - b) : (b - a);
  4. }

Entonces tu retardo asincrónico quedará así:

Código: C
  1. if (abs_diff(getTimer(),valorInst) > 5000)
  2. {
  3.     state = 0;
  4.     return; // para que no ejecute el código de abajo
  5. }



Tengo una idea algo difusa sobre MPLAB Harmony, XC32 con PIC32

Conectado Eduardo2

  • PIC24F
  • *****
  • Mensajes: 965
Re:problemas con interrupcion y maquina de estados
« Respuesta #5 en: 04 de Septiembre de 2024, 15:36:14 »
Además de lo ya dicho:

- El retardo también se puede llevar disparando una cuenta descendente con Timer0.

- La interrupción para detectar el pulsador no la veo necesaria.


Ejemplo:

Código: [Seleccionar]
#include <16F84A.h>
#use delay (clock=4MHz)
#use fast_io(all)

#byte pb=6
#byte pa=5     

int8 state=0;   

#define TIMERs(x) TimeOut=(.5+x/.065536)

int8 TimeOut=0 ;    // int8  para un maximo de 16.7"
                    // int16 para un maximo de 1h 11' 
                   
#INT_RTCC
void  RTCC_isr(void)
{   
    if(TimeOut) TimeOut-- ;
}                           
                                         
void state0()  // IDLE , state=0
{
    output_high(PIN_A0); 
//---------------------------------------------------
//  Bucle ppal del estado
//  En este caso es solo la condición de salida         
    while(!input(PIN_B0)) ;       
//---------------------------------------------------       
    state=1 ;
    output_low(PIN_A0);       
}

void stateA()    // state=1
{
    output_high(PIN_A1);
    delay_ms(400) ;   // si no, saldría inmediatamente por seguir
                      // activo el PIN_B0
    TIMERs(5) ;       // Dispara la cuenta descendente                   
//---------------------------------------------------
//  Bucle ppal del estado
//  En este caso son solo las condiciones de salida             
    while(TimeOut!=0 && !input(PIN_B0)) ;
//---------------------------------------------------   
    state = Timeout ? 2 : 0 ;   
    output_low(PIN_A1);
}

void stateB()     // state=2
{
    output_high(PIN_A2);
    delay_ms(400) ;   // si no, saldría inmediatamente por seguir
                      // activo el PIN_B0

    TIMERs(5) ;       // Dispara la cuenta descendente                   
//---------------------------------------------------
//  Bucle ppal del estado
//  En este caso son solo las condiciones de salida             
    while(TimeOut!=0 && !input(PIN_B0)) ;
//---------------------------------------------------
    state = Timeout ? 3 : 0 ;
    output_low(PIN_A2);
}

void startBomba()   // state=3
{
    output_high(PIN_A3);
    delay_ms(1000);

    state = 0;   // IDLE
    output_low(PIN_A3);
}

void main()
{
    set_tris_a(0x00) ;
    set_tris_b(0x01) ;
   
    // 0. idle
    // A. Boton arranque: count_down = 5sec
    // B. Boton arranque: count_down = 5sec
    // Finish. Boton arranque: start
    pa=0;

    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256|RTCC_8_BIT); //65.5 ms overflow
    enable_interrupts(INT_RTCC);
    enable_interrupts(GLOBAL);
                   
    while(true){
        switch(state){
            case 1:  stateA()    ; break ;
            case 2:  stateB()    ; break ;
            case 3:  startBomba(); break ;
            default: state0() ;
        }
    }
}


 

anything