Go Down

Topic: leOS - un semplice OS per schedulare piccoli task (Read 45499 times) previous topic - next topic

Testato


grazie dei consigli, però sia che aggiorni prima un buffer o che aggiorni direttamente il display leggendo i dati al momento, devo temporizzare comunque la print() sul display, quindi in pratica per la funzione per scrivere sul display devo per forza fare un controllo tipo il blinkwithoutdelay, o ho capito male?

Non confondiamogli le idee (si stanno mettendo in campo tante variabili, fino ad addirittura la gestione di un monitor pc)
Io ti do' la mia risposta secca, per il tuo lavoro va bene Looper
- [Guida] IDE - http://goo.gl/ln6glr
- [Lib] ST7032i LCD I2C - http://goo.gl/GNojT6
- [Lib] PCF8574+HD44780 LCD I2C - http://goo.gl/r7CstH

tuxduino



Quote
Come fa a te a funzionare?


E' quello che vorrei sapere anch'io  :smiley-sweat:

Può essere che c'entrino le chiamate all'lcd ? Non mi sembra un motivo plausibile a dire il vero, cmq stasera per scrupolo provo la tua versione con i led.

Se parliamo della LiquidCrystal allegata all'IDE 1.0.2, gli ho dato un'occhiata ma non ho trovato cose eclatanti tipo manipolazioni dei timer od uso degli interrupt.


Sì, sto usando la 1.0.2.

Comunque non vedi lampeggiare i led perché
Code: [Select]

' ' != 0


:P

Prova con questo:
Code: [Select]

#include <leOS.h>

leOS myOS;


//variables to control the LEDs
byte led1Status = 0;
byte led2Status = 0;
byte led3Status = 0;
const byte LED1 = 7;
const byte LED2 = 8;
const byte LED3 = 9;

void setup() {
    pinMode(LED1, OUTPUT);
    pinMode(LED2, OUTPUT);
    pinMode(LED3, OUTPUT);
   
    myOS.begin();
    myOS.addTask(flashLed1, 500);
    myOS.addTask(flashLed2, 500);
}


//main loop
void loop() {
    digitalWrite(LED3, led3Status ? HIGH : LOW);
    led3Status ^= 1;   
    delay(1000);
}


//first task
void flashLed1() {
    digitalWrite(LED1, led1Status ? HIGH : LOW);
    led1Status^=1;
    delay(800);                // <<<<<<<<<<<<<<<< (*)
    digitalWrite(LED2, led1Status ? HIGH : LOW);
}


//second task
void flashLed2() {
    digitalWrite(LED2, led2Status ? HIGH : LOW);
    led2Status^=1;
}

leo72


Comunque non vedi lampeggiare i led perché
Code: [Select]

' ' != 0

Ho convertito al volo, non ho controllato più di tanto.  :smiley-sweat:
Quote

Prova con questo:

Oggi lo farò.... ma tu: hai provato questo codice? :P

tuxduino

Usando come pin per i led 11, 12, 13 a rotazione il led sul 13 lampeggia sempre. Oggi sperabilmente dovrei riuscire a provare collegando contemporaneamente tre led  :smiley-sweat:

leo72

#349
Nov 27, 2012, 04:51 pm Last Edit: Nov 27, 2012, 04:53 pm by leo72 Reason: 1
@tuxduino
Allora.... ho fatto un po' di test.
Intanto le certezze: una ISR di default non è interrotta da un'altra ISR.
Ho provato il tuo sketch e vedevo anch'io lampeggiare i 3 led. Una cosa che ho notato, però, è stata che i led 7 e 8 lampeggiavano entrambi con una frequenza che era la metà di quella del led 9, quindi non solo il led 8 ma anche il led sul pin 7, quello pilotato da un task in cui c'era un delay(800). Un delay che avrebbe dovuto inserire una certa differenza e quindi togliere la sincronizzazione dei flash.

Ho perciò preso un semplice sketch:
Code: [Select]
#include <leOS.h>

leOS myOS;


//variables to control the LEDs
byte led1Status = 0;
const byte LED1 = 7;

void setup() {
   pinMode(LED1, OUTPUT);
   Serial.begin(19200);    
   myOS.begin();
   myOS.addTask(flashLed1, 500);
}


//main loop
void loop() {
   digitalWrite(LED1, led1Status ? HIGH : LOW);
   led1Status ^= 1;    
}


//first task
void flashLed1() {
   delay(10000);
}


Se il delay avesse funzionato nei task come tu affermavi accadeva, il led avrebbe lampeggiato regolarmente ogni secondo. Invece vedevo un velocissimo lampeggio.

Ho preso un altro sketch:
Code: [Select]
#include <leOS.h>

leOS myOS;


//variables to control the LEDs
byte led1Status = 0;
const byte LED1 = 7;

void setup() {
   pinMode(LED1, OUTPUT);
   Serial.begin(19200);    
   myOS.begin();
   myOS.addTask(flashLed1, 500);
}


//main loop
void loop() {
   digitalWrite(LED1, led1Status ? HIGH : LOW);
   led1Status ^= 1;    
}


//first task
void flashLed1() {
   Serial.println(micros(), DEC);
   delay(10000);
   Serial.println(micros(), DEC);
}


Sul monitor seriale ho ottenuto:
Code: [Select]
1000372
1000632
1500140
1500344
1999844
2000056
2499560
2499768
2999264
2999480
3498984
3499192
3998700
3998904
4498420
4498620
4998132
4998332
5497828
5498040

In teoria la cosa dovrebbe essere impossibile perché delay è una funzione che attende del tempo sfruttando un contatore interno:
Code: [Select]
void delay(unsigned long ms)
{
uint16_t start = (uint16_t)micros();

while (ms > 0) {
if (((uint16_t)micros() - start) >= 1000) {
ms--;
start += 1000;
}
}
}

Come vedi, ogni 1000 microsecondi, viene sottratto 1 ms al valore passato.
E micros() legge direttamente dal contatore agganciato al timer 0 (ed il timer continua a funzionare, solo che non viene più chiamato il relativo interrupt). Quindi non passa dalla ISR che aggiorna invece il valore di millis(). Però ovviamente, essendo gli interrupt fermi, il valore di timer0_overflow_count non viene incrementato per cui il ritardo non è esattamente calcolato.
Che tu metta un delay(1000) o un delay(10000) il risultato è di pochissimo differente.
Usando millis, invece, il tutto "muore". Ecco uno sketch di esempio:

Code: [Select]
#include <leOS.h>

leOS myOS;


//variables to control the LEDs
byte led1Status = 0;
const byte LED1 = 7;

void setup() {
   pinMode(LED1, OUTPUT);
   Serial.begin(19200);    
   myOS.begin();
   myOS.addTask(flashLed1, 500);
}


//main loop
void loop() {
   digitalWrite(LED1, led1Status ? HIGH : LOW);
   led1Status ^= 1;
}


//first task
void flashLed1() {
   unsigned long tempMillis = millis() + 10000;
   while (tempMillis > millis()); //morte cerebrale....
}

lesto

attenzione, non è che muore ma che millis() non cambia mai (loop infinito)
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

tuxduino

@leo, per la cronaca io affermavo proprio che la delay() sembrava non funzionare. Il tuo esempmio in cui l'unica funzione del task è chiamare una delay(1000) conferma quanto avevo osservato anch'io in precedenza.

Direi che hai spiegato perfettamente perché la delay() è "istantanea" (perdona la semplificazione... :) ) quando il task è chiamato dalla timer2 isr.

Grazie.

Per ora mi sembra di aver capito. Casomai rileggo la tua risposta un paio di volte... :)

leo72


attenzione, non è che muore ma che millis() non cambia mai (loop infinito)

Per "muore" intendo che si freeza lì perché appunto la millis, non vedendo più il valore che restituisce cambiato, genera un loop infinito.


@leo, per la cronaca io affermavo proprio che la delay() sembrava non funzionare.  Il tuo esempmio in cui l'unica funzione del task è chiamare una delay(1000) conferma quanto avevo osservato anch'io in precedenza.

Ah, ok. Non ricordavo più l'oggetto della discussione  :smiley-sweat:

Quote

Direi che hai spiegato perfettamente perché la delay() è "istantanea" (perdona la semplificazione... :) ) quando il task è chiamato dalla timer2 isr.

Grazie.

Per ora mi sembra di aver capito. Casomai rileggo la tua risposta un paio di volte... :)

A tua disposizione  ;)

d407336

sucsate un'ultima domanda sul display lcd e poi finisco l'off topic: quando ho il buffer pronto ed è il momento di inviarlo all'lcd, è meglio tenermi anche una copia del buffer precedente, confrontarlo con l'attuale e inviare al display solo le differenze, o va bene fare un clear() dell'lcd e inviare il buffer intero?
in pratica non dovrebbe cambiare niente, ma la soluzione migliore qual'è?
se facessi clear() prima sarebbe più semplice...

tornando a leOS
a me serve che un task venga eseguito ogni 1000 millisecondi esatti, quindi uso leOS e non leOS2 perchè 1000 non è multiplo di 16.
se però volessi eseguire il task ogni 2000 millisecondi (multiplo di 16), il task verrebbe eseguito ogni 2 secondi esatti o ogni 2 secondi ± 16ms ?

lesto

meglio le differenze. Eviti sfarfallamenti
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

leo72


sucsate un'ultima domanda sul display lcd e poi finisco l'off topic: quando ho il buffer pronto ed è il momento di inviarlo all'lcd, è meglio tenermi anche una copia del buffer precedente, confrontarlo con l'attuale e inviare al display solo le differenze, o va bene fare un clear() dell'lcd e inviare il buffer intero?
in pratica non dovrebbe cambiare niente, ma la soluzione migliore qual'è?
se facessi clear() prima sarebbe più semplice...

Non voglio andare contro lesto ma, secondo la mia modesta opinione, tenere 2 buffer in memoria, fare un confronto fra i 2 e spedire solo le differenze è un'inutile spreco di memoria (2 matrici) e di tempo (devi comunque confrontare tutte le celle dei 2 buffer per trovare i cambiamenti).
Tieni 1 solo buffer per volta e riscrivilo ogni xxx ms senza fare un clear() primo, in modo da: occupare meno memoria possibile; impiegare il minor tempo possibile per gestirlo; evitare sfarfallii dell'immagine (sovrascrivere i dati non crea sfarfallamenti).

Quote

tornando a leOS
a me serve che un task venga eseguito ogni 1000 millisecondi esatti, quindi uso leOS e non leOS2 perchè 1000 non è multiplo di 16.
se però volessi eseguire il task ogni 2000 millisecondi (multiplo di 16), il task verrebbe eseguito ogni 2 secondi esatti o ogni 2 secondi ± 16ms ?

Il leOS è la prima versione ed è stato scritto basandolo sui timer per cui si ottiene una discreta precisione, ma non una precisione assoluta. Ricordati che stai facendo i conti con un risonatore ceramico (quello dell'Arduino) che è più impreciso di un quarzo per cui anche se setti 1000 ms non avrai un intervallo accurato al millisecondo.
Il leOS2 è meno preciso perché si basa sul watchdog però, a differenza del leOS, non usa timer. Quindi ne va prima di tutto fatta una scelta in base alle proprie necessità. Che si scelga il leOS o il leOS2, poi, l'intervallo scelto è quello poi che effettivamente si avrà: questo vale sia per il leOS, che misura gli intervalli in ms, sia per il leOS2, che li misura in tick.

lesto

Quote
Tieni 1 solo buffer per volta e riscrivilo ogni xxx ms senza fare un clear() primo, in modo da: occupare meno memoria possibile; impiegare il minor tempo possibile per gestirlo; evitare sfarfallii dell'immagine (sovrascrivere i dati non crea sfarfallamenti).

molto meglio così, non ho pensato alla riscrittura senza clear
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie


Testato

logicamente se non usi il clear devi sovrascrivere tutte le celle di memoria dell'LCD, se ad esempio hai scritto pippolino, e dopo devi scrivere solo pippo, devi aggiungere alla matrice spazi vuoti per cancellare "lino"
- [Guida] IDE - http://goo.gl/ln6glr
- [Lib] ST7032i LCD I2C - http://goo.gl/GNojT6
- [Lib] PCF8574+HD44780 LCD I2C - http://goo.gl/r7CstH

tuxduino

(slightly-OT) Mi viene in mente che usando un buffer più ampio rispetto alla dimensione del display (ad esempio 40 colonne x 2 righe) e parametrizzando la routine di refresh con la colonna di partenza, si possono generare facilmente delle animazioni. Ad esmpio testo scorrevole. Il codice "applicativo" si comporta come se il display avesse 40 colonne anziché 16. La routine di refresh del display parte dalla colonne impostata (chiamiamola currRefreshCol) per copiare i 16x2 caratteri sul display fisico. Variando currRefreshCol, ad esempio con un'azione temporizzata, si ha che il testo sembra scorrere sull'lcd.

Go Up