Interrumpir dentro de una interrupción en un PIC18

1

Estoy trabajando en el código para una interrupción externa de RB0 en un PIC18F4550 . Cuando se detecta una interrupción en RB0, el temporizador 0 se activa.

Entonces necesito ver el desbordamiento del timer0. Si lo hace, entonces el código puede volver a main. Si no lo hace, esto significa que se ha detectado otro flanco ascendente en RB0. Una vez que tengo un cierto número de interrupciones RB0 concurrentes antes de que el temporizador se desborde, paso al siguiente procedimiento.

Soy nuevo en las interrupciones y no estoy seguro de que "lidiar con" la interrupción del timer0 en mi RB0 ISR esté bien.

¿Necesito un nuevo ISR para que se llame al timer0 desde el RB0 ISR?

¿O está bien hacer lo que estoy en mi código?

    
pregunta Leon Ellis

1 respuesta

3

En términos generales, realmente no desea perder el tiempo en un ISR esperando que algo suceda. Cada ISR debe hacer lo que tiene que hacer y salir rápidamente. Las variables compartidas se utilizan para realizar un seguimiento de la información de estado y para comunicarse entre los ISR.

En su caso, debe hacer un seguimiento de si se ha iniciado o no el temporizador y el número de eventos RB0. También debe saber cuándo enviar un mensaje y qué debe incluir en el mensaje. Estas se convierten en variables globales:

bool timer_started;
int rb0_events;
bool send_message;
int message_data;

Inicializa esa variable en el código de la línea principal, antes de que se hayan habilitado las interrupciones. Luego, habilita las interrupciones y entra en un bucle que simplemente controla si se debe enviar un mensaje:

timer_started = 0;
rb0_events = 0;
send_message = 0;
message_data = 0;
/* Any other initialization goes here */
enable_interrupts();
while (1) {
  if (send_message) {
    send_message = 0;
    /* create and send the SMS message, using the value in message_data as needed */
  }
  /* Do other stuff while waiting for interrupts. */
}

En el RB0 ISR, verifica el indicador de timer_started y realiza la acción deseada:

++rb0_events;
if (!timer_started) {
  timer_started = 1;
  start_timer();
}

Y en el temporizador ISR, realiza las acciones requeridas allí:

timer_started = 0;
stop_timer();
if (rb0_events >= THRESHOLD) {
  message_data = rb0_events;
  send_message = 1;
}
rb0_events = 0;

Según sus comentarios, parece que lo que está implementando es básicamente un contador de frecuencia. En ese caso, no es necesario iniciar y detener el temporizador; simplemente déjelo funcionar continuamente, generando interrupciones en un intervalo fijo. Use las interrupciones RB0 para incrementar un contador, y use la interrupción del temporizador para capturar el valor de ese contador. El valor capturado representa la frecuencia de los eventos en RB0.

int rb0_events;
int rb0_frequency;
bool updated;

main () {
  rb0_events = 0;
  rb0_frequency = 0;
  updated = 0;

  /* configure and start timer */
  enable_interrupts();

  while (1) {
    if (updated) {
      if (rb0_frequency > THRESHOLD) {
        /* send SMS message */
      }
      updated = 0;
    }
    /* do other stuff while waiting for interrupts */
  }
}

rb0_isr () {
  ++rb0_events;
}

timer_isr () {
  rb0_frequency = rb0_events;
  rb0_events = 0;
  updated = 1;
}

Tercer intento. Como lo entiendo, usted desea enviar un mensaje si ha recibido al menos 182 eventos RB0 seguidos que nunca tuvieron más de 25 ms entre ellos. Cualquier intervalo más largo que ese restablece el contador de eventos.

int rb0_events;
bool send_message;

main () {
  rb0_events = 0;
  send_message = 0;
  /* Configure the RB0 and Timer interrupts, but don't start the timer. */
  enable_interrupts();
  while (1) {
    if (send_message) {
      send_message = 0;
      /* Send the SMS message. */
    }
    /* Do other stuff while waiting for interrupts. */
  }
}

rb0_isr () {
  /* Count the events, but keep the counter from "wrapping around" and triggering
   * a second message.
   */
  if (rb0_events < THRESHOLD + 1) ++rb0_events;
  /* Send one message when the counter reaches the threshold value.
   * No other message will be sent until the timer expires and resets the counter.
   */
  if (rb0_events == THRESHOLD) send_message = 1;
  /* The following call starts the 25 ms timer, or restarts it if it is already running. */
  start_timer();
}

timer_isr () {
  rb0_events = 0;
}
    
respondido por el Dave Tweed

Lea otras preguntas en las etiquetas