Come realizzare uno scheduler multitask con microcontrollori PIC

Come realizzare uno scheduler (framework che consente al microcontrollore di eseguire più task contemporaneamente) con i PICMICRO.

Scheduler con PIC

Il firmware proposto nel listato 1, implementa un semplice scheduler ovvero un framework che consente al microcontrollore di lanciare più task in parallelo al fine di ottimizzare l’utilizzo del micro stesso. La tecnica usata è la seguente:

  • viene impostato il Timer1 per produrre una interruzione ogni millisecondo;
  • ad ogni interruzione di Timer1 vengono aggiornate alcune variabili che saranno usate nel programma  principale  per  determinare  gli  intervalli  di tempo associati ai vari task. Nell’esempio le variabili sono gestite in modo da avviare i task ad intervalli multipli di 1ms, 10ms, 100ms o 1s.
  • Il programma principale controlla gli intervalli di tempo. Nell’esempio viene fatto  lampeggiare un LED ogni 250ms, 500ms, 1s e 2s e viene resettato il watchdog timer ogni 10ms.

Le variabili t1mS, t10mS, t100mS e t1S vengono usate per capire se è trascorso rispettivamente 1ms, 10ms, 100ms o 1s, mentre le variabili t1mS0, t10mS0, t10mS1, t100mS0, tS0 e tS1 sono utilizzate per determinare gli intervalli di tempo con cui inne- scare i task. Ad esempio per far lampeggiare il LED ogni 250ms viene controllato se la variabile t10mS1 contiene 25 (poiché 25x10ms=250ms).

Il programma  è scritto  in  C per un  PIC16F877 a 20MHz utilizzando PICC di CCS.

 #include <16f877.h>

 /* Configurazione del micro */
 #fuses HS,NOPROTECT,NOWDT,BROWNOUT,PUT,NOLVP
 
#device *=16 /* RAM 256 bytes */

/* Impostazione clock a 20 MHz. */
 #use delay(clock=20000000)

/* Definizioni per gli I/O */
#define LED0 PIN_B4
#define LED1 PIN_B5
#define LED2 PIN_B6
#define LED3 PIN_B7

// Variabili per la schedulazione
unsigned char t1mS = 0,
t10mS = 0,
t100mS = 0;

unsigned char t1mS0 = 0,
t10mS0 = 0, // Conteggio per Watchdog timer
t10mS1 = 0, // Lampeggio LED (250ms on/off)
t100mS0 = 0, // Lampeggio LED (500ms on/off)
tS0 = 0, // Lampeggio LED (1 secondo on/off)
tS1 = 0; // Lampeggio LED (2 secondi on/off)

void main(void);
void init_pins(void);
void init_timers(void);
void init(void);
void timer1_isr(void);

/* Impostazioni dei pin di I/O */
void
init_pins(void) {
set_tris_b(0b00000000); /* B4..B7 uscite */

/* Impostazioni iniziali per le uscite */
output_low(LED0);
output_low(LED1);
output_low(LED2);
output_low(LED3);
}

/* Inizializzazione */
void
init(void) {
init_pins();
init_timers();
// Abilitazione interruzione per Timer1
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
}

/* Inizializzazione Timer1 */
void
init_timers(void) {
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
}

/* Inizio programma principale*/
void
main(void) {
init();
for ( ; ; ) {
if (t1mS0) { /* Trascorso 1ms */
t1mS0 = 0;
}

if (t10mS0) { /* Trascorsi 10ms */
/* azzeramento watchdog timer */
RESTART_WDT();
}

if (t10mS1 == 25) { /* Trascorsi 250ms */
t10mS1 = 0;
/* Commutazione LED0 */

output_bit(LED0, !input(LED0));
}
if (t100mS0 == 5) { /* Trascorsi 500ms */
t100mS0 = 0;
/* Commutazione LED1 */
output_bit(LED1, !input(LED1));
}
if (tS0) { /* Trascorso 1s */
tS0 = 0;
/* Commutazione LED2 */
output_bit(LED2, !input(LED2));
}
if (tS1 == 2) { /* Trascorsi 2s */
tS1 = 0;
/* Commutazione LED3 */
output_bit(LED3, !input(LED3));
}
}
} /* Fine programma principale */

#int_timer1
void timer1_isr(void) {
// ISR per Timer1
set_timer1(-625); // 20 MHz/625 => 1 ms - latenza
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++;
}
}
}
}
Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend