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 combinazione di un for tipo while(1) e una serie di if, “semplice” ma efficace 🙂