Come allestire un framework per consentire l’esecuzione di più task in parallelo su un PIC16F877

Come allestire un framework per consentire l’esecuzione di più task in parallelo su un PIC16F877

Disporre di uno scheduler per un PIC16F877 è sicuramente utile in quanto rende possibile l’esecuzione di più tasks in parallelo ottimizzando così le performance del micro. L’approccio, implementato nel listato 1, è il seguente:

  • Inizializzazione di  TIMER1  per generare un interrupt ogni milli-secondo; ad ogni interrupt vengono aggiornate alcune variabili gestibili anche dal programma principale per determinare gli intervalli di esecuzione delle applicazioni. Il listato 1 consente di eseguire task ad intervalli multipli di 1ms, 10ms, 100ms o 1 secondo.
  • Nel programma  principale  vengono conteggiati i vari intervalli ed eseguite le relative applicazioni.

Le istruzioni nella routine di servizio dell’interrupt sono ridotte al minimo onde evitare di compromettere la temporizzazione.  Il codice del listato 1 è scritto per i compilatori C di CCS. L’esempio  mostra  il  cambio  di stato  di  alcuni LED ogni 250ms, 500ms, 1 secondo e 2 secondi, oltre ad azzerare il watchdog timer ogni 10ms.

#include <16f877.h>
#fuses HS,NOPROTECT,NOWDT,BROWNOUT,PUT,NOLVP
/*eventuale spazio per bootloader*/
#ORG 0x1F00,0x1FFF {}
#device *=16
/* clock a 20 MHz. */
#use delay(clock=20000000)
/* Direttiva per l’interfaccia RS-232*/
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
/* definizioni I/0 */
#define LED0 PIN_B4
#define LED1 PIN_B5
#define LED2 PIN_B6
#define LED3 PIN_B7
// Variabili di schedulazione
   unsigned char t1mS = 0,
   t10mS = 0,
   t100mS = 0;
   unsigned char t1mS0 = 0,
   t10mS0 = 0,     // Temporizz. Per Watchdog timer
   t10mS1 = 0,     // LED blinking (ogni 0.25sec)
   t100mS0 = 0,    // LED blinking (ogni 0.5sec)
   tS0 = 0,        // LED blinking (ogni secondo)
   tS1 = 0;        // LED blinking (ogni 2 secondi)
void main(void);
void init_pins(void);
void init_timers(void);
void init(void);
void timer1_isr(void);
void
init_pins(void) {
  set_tris_b(0b00000000);
/* B4 to B7 are outputs.
   Rest are not used. */
  output_low(LED0);
  output_low(LED1);
  output_low(LED2);
  output_low(LED3);
} /* init_pins */

void
init(void) {
  init_pins();
  init_timers();
  // Enable Timer1 interrupts
     enable_interrupts(INT_TIMER1);
     enable_interrupts(GLOBAL);
     printf(“Scheduler demo\r\n”);
} /* init */
/* inizializzazione del Timer1 */
void
init_timers(void) {
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
} /* init_timers */

void
main(void) {
  init();
 for ( ; ; ) {
   if (t1mS0) { /* trascorso 1ms */
     t1mS0 = 0;
  }
  if (t10mS0) { /* trascorsi 10ms */
/* azzeramento del watchdog timer. */
   RESTART_WDT();
 }
 if (t10mS1 == 25) {
    /* trascorsi 250ms. */
    t10mS1 = 0;
   /* Toggle LED */
   output_bit(LED0, !input(LED0));
   }
  if (t100mS0 == 5) {
    /* trascorsi 500ms. */
    t100mS0 = 0;
   /* Toggle LED */
   output_bit(LED1, !input(LED1));
  }
  if (tS0) {
    /* trascorso 1 secondo */
    tS0 = 0;
   /* Toggle LED */
   output_bit(LED2, !input(LED2));
  }
  if (tS1 == 2) {
    /* trascorsi 2secondi */
    tS1 = 0;
   /* Toggle LED */
   output_bit(LED3, !input(LED3));
  }
 }
} /* main */

#int_timer1
void timer1_isr(void) {
   // Routine di servizio dell’interrupt
   set_timer1(-625);
// For 20 MHz/625 => 1 ms - latency

  t1mS0++;
  if (t1mS++ == 9) { // 10 ms
    t1mS = 0;
    t10mS0++;
    t10mS1++;
    if (t10mS++ == 9) { // 100 ms
      t10mS = 0;
      t100mS0++;
      if (t100mS++ == 9) { // 1 s
        t100mS = 0;
        tS0++;
        tS1++;
      }
    }
  }
} /* timer1_isr */
Listato 1.

Una risposta

  1. Maurizio Di Paolo Emilio Maurizio 18 settembre 2016

Scrivi un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *