PkLab.net
Meccatronica
Italy - Basilicata - Matera
 
Robotica&Image processing Sistemi di controllo Applicazioni speciali Networking Didattica
 
Home e contatti
MULTIPROGRAMMAZIONE

MULTIPROGRAMMAZIONE

Nota: questo materiale è di proprietà di Pk Lab ed è utilizzabile liberamente a condizione di citarne la fonte

IL PROCESSORE DIVIDE LA SUA ATTIVITA' TRA DIVERSI PROCESSI.

APPLICAZIONI:

- CENTRI DI CALCOLO i processi appartengono ad utenti diversi che sono indipendenti tra loro. Tutti però insistono sulla stessa macchina

-SISTEMI REAL TIME sono quei sistemi che lavorano in stretta relazione con l'ambiente fisico esterno con il quale scambiano dati e segnali. Normalmente un processo fisico è caratterizzato da più elementi, gestiti da diversi moduli ed eseguiti contemporaneamente (in parallelo).

In un sistema real time il tempo di risposta ai segnali esterni è una delle caratteristiche principali.

PROGRAMMAZIONE SEQUENZIALE E MULTIPROGRAMMAZIONE

NELLA PROGRAMMAZIONE SEQUENZIALE IL PROBLEMA E' QUELLO DI TROVARE UN ALGORITMO CHE OPERI UNA TRASFOMAZIONE DEI DATI IN INGRESSO

NELLA PROGRAMMAZIONE CONCORRENTE VI SONO PIU' MODULI DI PROGRAMMA (TASK) CHE VENGONO ESEGUITI IN PARALLELO, SPESSO COOPERANDO TRA LORO.

I SISTEMI REAL-TIME POSSONO ESSERE REALIZZATI CON METODI DI MULTITASKING. E' INFATTI INTUITIVO SCOMPORRE IL PROBLEMA IN SOTTOPROBLEMI ELEMENTARI ED ASSOCIARE AD OGNIUNO DI ESSI UN TASK PRONTO A RISPONDERE ALLA PRIMA ESIGENZA

IL CALCOLATORE E' PER SUA NATURA SEQUENZIALE

LA DISPOSIZIONE SEQUENZIALE DI TASK PARALLELI, INTRODUCE FORTI LEGAMI TRA FUNZIONI CHE DOVREBBERO RESTARE SEPARATE

MultiTASKing


MTASK E' UN SEMPLICISSIMO NUCLEO PER LA MULTIPROGRAMMAZIONE.

I PROBLEMI DI SINCRONISMO E PROTEZIONE DELLE RISORSE VENGONO RISOLTI CON LA NATURA STESSA DEL NUCLEO.

OGNI TASK VIENE ATTIVATO PERIODICAMENTE CON PERIODO PROGRAMMABILE.

I TASK SCADUTI VENGONO ATTIVATI IN SEQUENZA

LA PRIORITA' DEI TASK E' IMPLICITA NELL'ORDINE IN CUI I TASK VENGONO DICHIARATI

QUANDO UN TASK VIENE ATTIVATO NON VIENE MAI INTERROTTO

LA BASE DEI TEMPI VIENE FORNITA DAL RTC CON UNA RISOLUZIONE (TICK) DEL ms

IL TEMPO TOTALE DI ESECUZIONE DI TUTTI I TASK ATTIVI DEVE ESSERE INFERIORE AL TICK

UN TASK PUO' CAMBIARE LO STATO E IL PERIODO DI TUTTI I TASK DICHIARATI (COMPRESO SE STESSO)

Download mtask.zip

MTASK.C

/*====================== COSTANTI TIMER ===============================*/

#define FMIN 1193180 /* valore da dividere per la freq desiderata
*/

#define FBASE 1000 /* in Hz stabilisce il tick del sistema */
#define TICKms 1 /* tick del sistema in ms */
#define TICK55ms 55 /* numero di tick per la freq 18.2Hz */

char mask8253; /* byte di controllo per 8253 prima di InstallMask*/

/*================ VARIABILI INTERNE AL NUCLEO MTASK =================*/

unsigned long int Ntick = 0; /* contatore dei tick trascorsi */

struct /* lista degli eventi da eseguire */
{     int periodo; /* periodo di attivazione in ms */
    int cnt; /* ms dall'ultima attivazione */
    char stato; /* ON/OFF */
    void (*evento)(void); /* funzione da attivare */
} eventi[MAXEVENT];

int numEvent = 0; /* numero eventi programmati */

/*================ FUNZIONI INTERNE AL NUCLEO MTASK =================*/
void interrupt ( *OldInt08)(void);

/************************************************************************
| InstallMtask
-------------------------------------------------------------------------
La seguente funzione serve a variare la frequenza del timer di sistema
8253 sul canale 0 IRQ0. In questo modo cambia la frequenza con cui viene
chiamato INT 08H. La nuova frequenza si ottiene inviando al timer il
divisore che si ottiene dalla seguente formula:
                 1 193 180 ---->(FMIN)
nuovo divisore = -----------
                 freq. desid.

Il divisore di default è 65535 in modo che la frequenza sia 18.2 Hz cioè
ogni 55ms. Questa frequenza è da tenere da conto inquanto INT 08H riginale
serve a tenere aggiornato l'orologio del sistema e a controllare il motore
del HD quindi qualsiasi sia la frequanza programmata il nuovo interrupt
deve essere in grado di lasciare eseguire ogni 55 ms l'interrupt originale
Questa routine inoltre cambia anche INT08H in modo che alla frequenza
stabilita venga eseguita la funzione utente desiderata NewInt08 di seguito
programmata.
-----------------------------------------------------------------------*/
char InstallMtask(void){ ... }

char UnInstallMtask(void){... }
/***********************************************************************
| Aspetta
-------------------------------------------------------------------------
DESCRIZIONE: termina solo quando sono trascorsi il numero di millisecondi
passatti
-----------------------------------------------------------------------*/
void Aspetta(int ms)
{
  unsigned long int atTick = Ntick + ms;
  while(Ntick < atTick)
  {
    #ifdef DEBUG
    Kernel();
    #endif
  }
}

/***********************************************************************
| OnEvent
------------------------------------------------------------------------
DESCRIZIONE: attiva l'evento passato pone il contatore interno ad un valore
pari al periodo in modo che viene immediatamente generato. Il contatore
interno viene posto ad un valore pari al periodo in modo da fare
immediatamente la prima attivazione senza aspettare che il periodo
trascorra.
PARAMETRI: il numero dell'evento desiderato. Cioè il valore tonato da
AddEvent
RITORNA: il vecchio stato
-----------------------------------------------------------------------*/
char OnEvent(int quale)
{
  char oldstate = eventi[quale].stato;
  eventi[quale].stato = ON;
  eventi[quale].cnt = eventi[quale].periodo;
  return(oldstate);
}

/************************************************************************
| OffEvent
-------------------------------------------------------------------------
DESCRIZIONE: disattivaa l'evento passato pone il contatore interno a 0
PARAMETRI: il numero dell'evento desiderato. Cioè il valore tornato da
AddEvento
RITORNA: il vecchio stato
-----------------------------------------------------------------------*/
char OffEvent(int quale)
{
  char oldstate = eventi[quale].stato;
  eventi[quale].stato = OFF;
  eventi[quale].cnt = eventi[quale].periodo;
  return(oldstate);
}

/************************************************************************
| ChangeEventPeriod
------------------------------------------------------------------------
DESCRIZIONE: cambia il periodo di attivazione dell'evento.
pone l'evento a ON e se il contatore interno ha un valore superiore
al periodo impostato, viene posto pari a quest'ultimo in modo da
effettuare subito la prima commutazione
PARAMETRI: il numero dell'evento desiderato. Cioè il valore tornato da
AddEvento
RITORNA: il vecchio periodo
-----------------------------------------------------------------------*/
int ChangeEventPeriod(int quale,int periodo)
{
  int oldperiod = eventi[quale].periodo;
  eventi[quale].periodo = periodo;
  eventi[quale].stato = ON;
  if(eventi[quale].cnt > periodo)
    eventi[quale].cnt = periodo;
  return(oldperiod);
}

/***********************************************************************
| AddEvent
------------------------------------------------------------------------
DESCRIZIONE: imposta l'evento nella prima posizione disponibile. L'evento
ha una priorità inferiore a tutte i precedenti e superiore a tutti i
successivi. Il primo evento viene generato allo scadere del periodo,
quindi sul fronte di discesa.
PARAMETRI: il periodo di attivazione dell'evento,il suo stato e la funzione
da attivare;
RITORNA: il numero dell'evento
----------------------------------------------------------------------*/
int AddEvent(int periodo,char stato, void (*evento)(void))
{
  if(numEvent < MAXEVENT)
  {
    eventi[numEvent].periodo = periodo;
    eventi[numEvent].cnt = 0;
    eventi[numEvent].stato = stato;
    eventi[numEvent].evento = evento;
    return(numEvent++);
  }
return(FULL);
}

/***********************************************************************
| Kernel
------------------------------------------------------------------------
DESCRIZIONE: questa funzione viene chiamata ogni ms da clock del 8253.
cerca nell'elenco degli eventi quello il cui contatore interno e' pari
al periodo interno, e lo attiva. Dopo averlo attivato azzera il contatore
interno. successivamente, In gni caso incremento i contatori interni.
Verifico poi che non siano trascorsi 55ms ed eventualmente attivo il
vecchio int08h. Infine incremento la variabile Ntick che conta il numero
degli impulsi trascorsi dal momento dell'installazione di Mtask
L'attivazione degli eventi avviene sul fronte di salita del clock.
mentre l'incremento dei contatori sul fronte di discesa. Questo implica
che prima eseguo la verifica, eventualmente attivo ed azzero, poi incremento.
PARAMETRI:
RITORNA:
-----------------------------------------------------------------------*/
#ifdef DEBUG
void Kernel(void)
#else
void interrupt Kernel(void)
#endif
{
  char i;
  static int cont08h =55;
  for(i=0;i<eventi[i].periodo) /* e se è scaduto */
      {
        (eventi[i].evento)(); /* attivo l'evento */
        eventi[i].cnt = 0; /* azzero il contatore */
      }
      eventi[i].cnt++; /* incremento i cnt di TUTTI gli elementi ON */
    }
  }

/*se necessario chiamo il vecchio int08h per mantere il clock di sistema */
if(cont08h == TICK55ms) /* ogni 55 ms */
{
  cont08h = 0; /* se passati 55ms azzero il contatore */
  #ifndef DEBUG
    OldInt08(); /* chiamo il vecchio interrupt */
  #else
    sound(1000);
    nosound();
  #endif
} else
  #ifndef DEBUG
    outp(0x20,0x20); /* mando EOI al 8259 per riattivare IRQ0 */
  #endif

cont08h++; /* incremento il contatore per i 55m */
Ntick++; /* incremento il contatore generale */
}

unsigned long int GetNtick() {return Ntick;}
prova di MTASK

#ifdef PROVA_MTASK

int ok =0;
void Suona()
{
    sound(10000);
    OffEvent(0);
}

void Stop()

{
    nosound();
    ok = 1;
}

/*******************************************************************/
void main()
{
    int primo,secondo;
    primo = AddEvent(0,ON,Suona);
    secondo = AddEvent(3000,ON,Stop);
    InstallMtask();
    while(ok==0)
    {
      #ifdef DEBUG
        Kernel();
      #endif
    }
    UnInstallMtask();
}
#endif

Il PKLAB aderisce ai principi Open Access della Dichiarazione di Berlino (Sito italiano)
[Home Page]  [System Control]   [Robotic & Image processing]   [Applicazioni Speciali]  [Didattica]   [Networking]   [Search]

Contatto:
Valid CSS!