Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

Schedulatore

Raccolta di codici sorgenti

Moderatore: Foto UtentePaolino

0
voti

[11] Re: Schedulatore

Messaggioda Foto Utenteluxinterior » 18 giu 2019, 10:15

più o meno è come hai descritto tu.
Visti i tempi biblici per un micro io farei così
interrupt che incrementa variabile fino a 50.
micro che normalmente "gira in tondo" senza fare nulla esegue solo due if
if variabile%10 == 0 (fa il modulo)
if variabile == 0 (ha raggiunto 50 e nell'interrupt è stata azzerata per ripartire con il conteggio)
all'interno del primo if leggi il sensore
all'interno del secondo gestisci il led.
Siccome hai interrupt ogni 10ms tutto funziona se la lettura del sensore richiede un tempo molto inferiore ai 10ms in modo che il micro abbia il tempo di eseguire entrambi gli if tra due interrupt successivi.

C'è una potenziale disgrazia se usi micro 8bit definisci la variabile char per schivarla
Avatar utente
Foto Utenteluxinterior
2.497 2 4 8
Expert EY
Expert EY
 
Messaggi: 1470
Iscritto il: 6 gen 2016, 17:48

0
voti

[12] Re: Schedulatore

Messaggioda Foto UtenteTheMask » 18 giu 2019, 13:01

Però se ho una funzione che deve essere eseguita ogni 100ms perché devo stare sotto i 10ms?
Func1
{
leggi sensore 1
leggi sensore 2
---
---
}

la lettura di x sensori deve essere inferiore a 100ms non 10ms o sbaglio?

Forse devo fare un interrupt direttamente ogni 100ms al posto di 10ms per eseguire la lettura dei sensori?
Avatar utente
Foto UtenteTheMask
35 3
New entry
New entry
 
Messaggi: 72
Iscritto il: 14 gen 2015, 16:05

0
voti

[13] Re: Schedulatore

Messaggioda Foto Utenteluxinterior » 18 giu 2019, 13:45

Sì va bene come dici tu 100ms
Pensandoci la cosa pultia sarebbe fare così
Codice: Seleziona tutto
while (1)
{
   while (isr_flag == 0) ;
   isr_flag = 0  ;

   if (variabile%10 == 0)

   if (variabile == 0)
}


isr_flag lo metti a 1 ogni 100ms dentro l'interrupt.
In questo modo il micro esce dal loop while (isr_flag) ogni 100m sper faare quello che deve
Avatar utente
Foto Utenteluxinterior
2.497 2 4 8
Expert EY
Expert EY
 
Messaggi: 1470
Iscritto il: 6 gen 2016, 17:48

1
voti

[14] Re: Schedulatore

Messaggioda Foto Utentexyz » 18 giu 2019, 16:23

Quella variabile "isr_flag" deve essere globale e deve essere dichiarata "volatile" o in un altro modo, dipende dalle linee guide di programmazione del micro-controllare in uso, altrimenti il compilatore può decidere di ottimizzarla in un registro con esiti disastrosi.

L'uso dell'operatore "%" con 10 implica una divisione, molti micro controllori non hanno in hardware la divisione. Consiglio di incrementare e poi azzerare o sfruttare le potenze di 2, ad esempio per ogni otto basta un AND con 0x07 o ogni 16 un AND con 0x0F.

Comunque se le operazione sono molto semplici per me il micro nel loop principale deve stare in stato di sleep con risveglio solo in caso di interrupt e nel codice degli interrupt gestire più velocemente possibile i compiti assegnati.
Avatar utente
Foto Utentexyz
5.930 2 4 5
G.Master EY
G.Master EY
 
Messaggi: 1572
Iscritto il: 5 dic 2009, 18:37
Località: Italy Turin

0
voti

[15] Re: Schedulatore

Messaggioda Foto UtenteTheMask » 19 giu 2019, 20:06

Vi aggiorno sul firmware. Allora il timer 4 fa scattare un interrupt ogni 2ms
Nel main ho messo questa funzione:
Codice: Seleziona tutto
bool flag_10ms;
bool flag_100ms;
bool flag_1000ms;

void main(void)
{   
   while (1)
   {
      if (flag_10ms == 1) //Task da 10ms
      {
         GPIO_WriteReverse(LED1);
         flag_10ms = 0;
      }
      if (flag_100ms == 1) //Task da 100ms
      {
         GPIO_WriteReverse(LED2);
         flag_100ms = 0;
      }
      if (flag_1000ms == 1) //Task da 1000ms
      {
         GPIO_WriteReverse(LED3);
         flag_1000ms = 0;
      }
   }
}


Mentre nel file di interrupt:
Codice: Seleziona tutto
int tmr_10ms;
int tmr_100ms;
int tmr_1000ms;
extern bool flag_10ms;
extern bool flag_100ms;
extern bool flag_1000ms;

void TIM4_UPD_IRQHandler(void)
{
   tmr_10ms++;
   tmr_100ms++;
   tmr_1000ms++;
   
   if(tmr_10ms == 5)
   {
      flag_10ms = 1;
   }
   if(tmr_10ms > 5)
   {
      flag_10ms = tmr_10ms = 0;
   }
   
   if(tmr_100ms == 50)
   {
      flag_100ms = 1;
   }
   if(tmr_100ms > 50)
   {
      flag_100ms = tmr_100ms = 0;
   }
   
   if(tmr_1000ms == 500)
   {
      flag_1000ms = 1;
   }
   if(tmr_1000ms > 500)
   {
      flag_1000ms = tmr_1000ms = 0;
   }
   
   TIM4_ClearFlag(TIM4_FLAG_UPDATE);
}


Mentre il segnale all'oscilloscopio dei primi due task da 10ms e 100ms:
Task 10ms
Traccia_10ms.png

Task 100ms
Traccia_100ms.png


A me sembra tutto corretto. Esiste un modo migliore per scrivere questo codice?
Avatar utente
Foto UtenteTheMask
35 3
New entry
New entry
 
Messaggi: 72
Iscritto il: 14 gen 2015, 16:05

0
voti

[16] Re: Schedulatore

Messaggioda Foto Utentexyz » 19 giu 2019, 22:13

Le variabili booleane utilizzate devono essere dichiarate almeno "volatile", sono condivise.

Fai un test e poi un assegnamento, di solito questa operazione deve essere atomica, vedi se hai una libreria o delle macro per operazioni atomiche.

Fai 2 test sui timer, uno per scatenare e uno per azzerarlo, prova a vedere se riesci a farne uno solo.
Avatar utente
Foto Utentexyz
5.930 2 4 5
G.Master EY
G.Master EY
 
Messaggi: 1572
Iscritto il: 5 dic 2009, 18:37
Località: Italy Turin

0
voti

[17] Re: Schedulatore

Messaggioda Foto UtenteTheMask » 20 giu 2019, 15:40

Ciao, per operazioni atomiche non basta ad esempio mettere all'interno di tutti i task la funzione per disabilitare tutti gli interrupt e poi riabilitarli quando ha finito tutte le operazioni?
Codice: Seleziona tutto
if (flag_10ms == 1) //Task da 10ms
      {
--> DISSATTIVO TUTTI GLI INTERRUPT
         GPIO_WriteReverse(LED1);
         flag_10ms = 0;
--> RIATTIVO TUTTI GLI INTERRUPT
      }


Oppure intendi una cosa del genere:
Codice: Seleziona tutto
if (flag_10ms == 1 && flag_100ms == 0 && flag_1000ms == 0 )
{
...
}
if (flag_100ms == 1 && flag_10ms == 0 && flag_1000ms == 0 )
{
...
}
if (flag_1000ms == 1 && flag_10ms == 0 && flag_100ms == 0 )
{
...
}
Avatar utente
Foto UtenteTheMask
35 3
New entry
New entry
 
Messaggi: 72
Iscritto il: 14 gen 2015, 16:05

0
voti

[18] Re: Schedulatore

Messaggioda Foto Utentexyz » 20 giu 2019, 21:16

Dipende dal micro controllore. Con i micro-controllori a 8 bit si salva lo stato, si disattivano gli interrupt, si eseguono le operazioni critiche, si ripristina lo stato. Con i micro controllori a 32 bit le cose sono più complesse, ad esempio gli ARM Cortex hanno delle opportune librerie e macro per operazioni atomiche.

Per leggere un booleano se è true e subito dopo impostarlo a falso si usa un'altra tecnica. Si esegue una swap in assembler tra un registro col valore falso e la memoria che contiene il booleano, questa operazione è in generale atomica. Se il registro contiene falso il booleano non ha cambiato stato, se è true il booleano ha cambiato stato e contemporaneamente è stato impostato a false. Questa operazione è di solito presente in qualche libreria con una funzione inline o una macro.

Quei test con le AND non sono operazione atomiche.
Avatar utente
Foto Utentexyz
5.930 2 4 5
G.Master EY
G.Master EY
 
Messaggi: 1572
Iscritto il: 5 dic 2009, 18:37
Località: Italy Turin

0
voti

[19] Re: Schedulatore

Messaggioda Foto UtenteTheMask » 21 giu 2019, 9:34

Grazie delle risposte. Ma ho un'ultima domanda. Secondo te perché non ottengo
10ms ma 12.3ms
100ms ma 105ms
A cosa può essere dovuto? Utilizzo l'oscillatore interno e la frequenza è 2MHz
Facendo due conti e considerando la tolleranza dell'oscillatore dovrei ottenere

Tick TIM x5 (10ms) --> [ms] 10,343 10,240 10,139
Tick TIM x50 (100ms) --> [ms] 103,434 102,400 101,386
Avatar utente
Foto UtenteTheMask
35 3
New entry
New entry
 
Messaggi: 72
Iscritto il: 14 gen 2015, 16:05

0
voti

[20] Re: Schedulatore

Messaggioda Foto Utentexyz » 21 giu 2019, 16:09

Se i pin di I/O vengono cambiati all'interno del codice dell'interrupt con un conteggio esatto del contatore, senza nessuna biforcazione o ritardi variabili il tempo misurato è preciso con la stessa tolleranza del clock principale.

Se invece dal interrupt si cambia il valore di una variabile condivisa, letta dal ciclo principale per pilotare i pin di I/O allora qui si ha una tolleranza maggiore, dovuto a quando viene scatenato interrupt (tra due istruzioni) e dal tempo di esecuzioni dei vari compiti gestisti nel ciclo principale.
Avatar utente
Foto Utentexyz
5.930 2 4 5
G.Master EY
G.Master EY
 
Messaggi: 1572
Iscritto il: 5 dic 2009, 18:37
Località: Italy Turin

PrecedenteProssimo

Torna a Firmware e programmazione

Chi c’è in linea

Visitano il forum: Nessuno e 3 ospiti