Pages: 1 [2]   Go Down
Author Topic: Programmazione orientata agli oggetti con Arduino  (Read 1927 times)
0 Members and 1 Guest are viewing this topic.
Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Volenti o nolenti, l'Arduino ci va giù di C++ e di conseguenza tutte le lib a seguire.
Si dovrebbe riscrivere il core in C puro ma questo non credo sia possibile  smiley-wink
Logged


0
Offline Offline
Faraday Member
**
Karma: 30
Posts: 2905
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Volenti o nolenti, l'Arduino ci va giù di C++ e di conseguenza tutte le lib a seguire.
Si dovrebbe riscrivere il core in C puro ma questo non credo sia possibile  smiley-wink

Per fare si può, non vedo perchè non si possa scrivere una libreria simil core, il problema non è tanto il linguaggio,
che può fare la differenza in modo marginale o influire marcatamente, tutto dipende da come si usano i linguaggi C/C++.

Anche il C permette la programmazione orientata agli ogetti e ti posso assicurare che se vuoi rispettare tutti comandamenti della OOP, il tutto finisce per
essere veloce quanto il C++. Il C++ non è lento per natura, ma è quello che gli facciamo fare che lo fa diventare lento.

Spesso tutto ciò che è buona tecnica di programmazione OOP peggiora le prestazioni. Se te ne freghi di OOP allora forse il C è la migliore soluzione.

Dai commenti sembra che il C++ sia il male assoluto, e quindi anche arduino visto che buona parte è composta da classi, invece ci sono cose interessanti al fine di riusare il codice, quindi minore spazio del compilato e minore impronta in RAM. C'è anche da considerare che scrivere programmi decenti è più complesso se usi il C++, specie quando si hanno limitate risorse.

In ogni caso penso proprio che buona parte del core contiene ottimo codice finalizzato a favorire la semplicita di utilizzo più che l'efficienza, nota che sono parti della stessa coperta, se tiri verso la semplicità perdi in efficienza e in flessibilità.

Tra le altre cose digitalWrite() è lenta non perchè è scritta in C++, anzi è proprio una comune funzione  C. Dall'altro lato usando il C ti puoi scordare la print che stampa più di un tipo, in C dovresti usare una funzione per tipo oppure la printf e le format string che come sapete non sono proprio amichevoli.

Se volete provare il lavoro non è molto, ma ci si deve dividere il compito e sopratutto avere tutti lo stesso orientamento, e per questo la vedo molto dura, ma forse perchè sono influenzato negativamente dagli accadimenti degli ultimi 30 anni. smiley-mr-green

Ciao.
Logged

AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home

Rome (Italy)
Offline Offline
Tesla Member
***
Karma: 120
Posts: 9178
"Il Vero Programmatore ha imparato il C sul K&R, qualunque altro testo è inutile e deviante."
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Dai commenti sembra che il C++ sia il male assoluto,

Sulle piccole mcu lo è, ti faccio un banale esempio che dovrebbe chiarire il concetto, se realizzo un programma in ANSI C quando lo compilo so sempre esattamente quanta memoria  ram utilizza, se lo fai in C++ non puoi mai saperlo con precisione, sai solo l'impegno "statico", quello dinamico potrebbe facilmente andare oltre la ram disponibile con tutte le conseguenze del caso.
E' vero che la digitalwrite() è una funzione e non una classe, però è scritta male ed è per questo che è molto lenta, invece di un singolo ciclo macchina richiede come minimo oltre 50 cicli macchina.

Logged

0
Offline Offline
Faraday Member
**
Karma: 30
Posts: 2905
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Il computo della quantità di memoria occupata dal programma in corsa, può essere una incognita difficile da determinare anche in C, tutto dipende dal tipo di programmazione che stai mettendo in essere. Su dispositivi dalle risorse limitate il miglior risultato lo ottieni scrivendo codice specializzato, e quindi non generico, e il riuso del codice tramite funzioni o OOP cessa di esistere.

La digitalWrite() fa delle cose che se vuoi fargliele fare per forza ciò che puoi guadagnare riscrivendola lo perdi ad esempio in semplicità, e comunque sarà sempre un compromesso che se accettato viene considerato il prezzo da pagare. Se la digitalWrite() fosse una macro o funzione inline e se operasse con gli indirizzi delle porte sarebbe molto più veloce e questa avrebbe un valore statico conosciuto, diversamente se devi cercare nella flash una corrispondenza tra il digital 3 e il reale registro si finisce per forza per avere una velocità di esecuzione che dipende da quanto tempo impiega la ricerca.

Segue del codice per discuterci sopra:

Code:
inline void gpio_on(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in,
                    uint8_t bit, int8_t pcInt)
{
    *out |= _BV(bit);       // imposta il bit on
}

Ogni volta devo passare 5 argomenti alla funzione, e ne sarei obbligato se volessi anche attivare la direzione. Il costo in tempo per passare 3 variabili puntatore e 2 per valore è conosciuto, ma il calcolo ora io non lo so fare, ma ammettiamo fosse un tempo accettabile, non è accettabile il tempo che impiego a scrivere la chiamata alla funzione. Per ridurre il tempo che impiego a scrivere la chiamata a funzione si possono accorpare gli argomenti in una define così:

Code:
//      Name               DDRx,       PORTx,         PINx,   Bit,   PCINT
#define GPIO_B0     &DDRB,      &PORTB,     &PINB, 0, 0
#define GPIO_B1     &DDRB,      &PORTB,     &PINB, 1, 1

quindi posso chiamare la funzione così:

Code:
gpio_on(GPIO_B0);

Oppure potremmo pensare che passare un solo puntatore a struttura costi meno di quanto costa la attuale chiamata a gpio_on(), si in effetti
un solo puntatore costerebbe meno, ma mi comporta un costo di RAM, allora posso pensare di salvare la struttura in FLASH ed avere in ram il solo
puntatore, ma perderei in velocità.

Dal momento che gpio_on() non usa gli argomenti 'dir, in, pcint' potrei eliminarli ma perdo in omogeneità. Il programmatore si aspetta di poter usare
ovunque le macro GPIO_xx es:
Code:
inline void gpio_mode(volatile uint8_t *dir, volatile uint8_t *out, volatile uint8_t *in,
                      uint8_t bit, int8_t pcInt, enum pin_mode mode)
{
    // se mode==mode_output imposta il pin come output
    // altrimenti se mode==inp_mode imposta il pin come input
    // altrimenti se mode==inp_pullup_mode imposta il pin come input con pullup

    (mode==out_mode) ? *dir |= _BV(bit)
        : (mode==inp_mode) ? *dir &= ~_BV(bit), *out &= ~_BV(bit)
        : (mode==inp_pullup_mode) ? *dir &= ~_BV(bit), *out |= _BV(bit) : 1;
}

Qui si vede come soltanto 'in, pcint' sono superflui, ma se devo leggere da un pin attraverso una funzione inline mi serve 'in".
Allora con le macro GPIO_xx si guadagna in chiarezza e omogeneità, ma alle volte a seconda delle funzioni chiamate si passano degli argomenti
superflui.

Quindi l'efficienza maggiore la otteniamo scrivendo codice specializzato, evitanto le indirezioni e le facility, ma se nel computo della efficienza ci mettiamo anche il tempo per scrivere il codice e il tempo per mantenerlo la valutazione si complica e in questo contesto sarebbe un errore di valutazione, noi vogliamo ottenere la velocità massima o una molto vicina al massimo.

Quindi, si passano solo puntatori a funzioni, anche per un intero, e se possibile usiamo le variabili globali con tutti i rischi che ne conseguono, si perchè le variabili globali sono considerate il male, causa di bug difficili da scovare, se non impossibili. Ma quando vogliamo la velocità le variabili globali sono l'unica soluzione per manipolare i dati da dentro ambiti con scope interno a quello globale, cioè nel caso di funzioni o in genere in blocchi {} interni.

Tutte queste precauzioni ha senso usarle sempre e comunque, a prescindere dalla necessità di ottimizzare?

Ciao.


Logged

AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home

Rome (Italy)
Offline Offline
Tesla Member
***
Karma: 120
Posts: 9178
"Il Vero Programmatore ha imparato il C sul K&R, qualunque altro testo è inutile e deviante."
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Il computo della quantità di memoria occupata dal programma in corsa, può essere una incognita difficile da determinare anche in C

Assolutamente no, in C ANSI sai esattamente quanta ram serve, o viene impegnata, al termine della compilazione, unica eccezione è se viene usata la malloc() con valori determinati da eventi run time, però è sempre possibile prevedere, e limitare, il range per non sforare la ram disponibile.
Logged

0
Offline Offline
Faraday Member
**
Karma: 30
Posts: 2905
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Certo è infatti ho specificato :
Quote
tutto dipende dal tipo di programmazione che stai mettendo in essere

Se usi il C++ e le classi, ma non usi l'ereditarietà e non usi allocazione dinamica e i template, il calcolo della dimensione è fattibile.
Una classe C++ e una struttura C++ ed entrambe sono quasi intercambiabili.

Se invece fai uso della allocazione dinamica e usi il C forzandolo verso il C++ ti perdi di casa nel computo della memoria occupata, come accade con il C++.

Cioè quindi non è il C++ che è negato o è il male assoluto e quello ci fai fare e che il linguaggio ti permette di fare in modo semplice che porta a conseguenze
disastrose.

Nel core di Arduino c'è la libreria ic2 che è realizzata come si realizzano le librerie sul pc, cioè il codice funzionale è scritto in C e compilato dal compilatore gcc C, mentre la classe che usiamo "wrappa", cioè avvolge il codice funzionale C, ed è compilata con g++, ma il linker è sempre quello del C++, perchè quello del C non è in grado di operare con gli oggetti.

Sul pc questo è un buon metodo di programmazione perchè realizzi la funzionalità che magari e legata al sistema dove tutto è scritto in C, ma permetti a programmatori C++ di usare la funzionalità attraverso la programmazione OOP. Se è un buon metodo lavorare così anche in ambito embedded dove le risorse sono limitate come per il 328 è tutto da discutere. Sicuramente usare l'implementazione C++ introduce una indirezione in più che è lo scotto da pagare per usare gli oggetti, o meglio l'oggetto perchè di i2c c'è ne una sola.

Ciao.
Logged

AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home

Global Moderator
Italy
Offline Offline
Brattain Member
*****
Karma: 325
Posts: 22498
Logic is my way
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

legata al sistema dove tutto è scritto in C
Uhm... Forse questo può valere per Linux ma non so ad esempio se Windows è ancora scritto in C.
Logged


0
Offline Offline
Faraday Member
**
Karma: 30
Posts: 2905
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quanto di windows sia scritto in C non so dirlo, ma posso sicuramente dirti che il layer di basso livello è scritto in C, o almeno c'è una libreria C che fornisce servizi. Lo posso dire perchè ho visto codice specifico per fare girare applicazioni scritte in C++/Qt che come sai è multipiattaforma, ma i servizi di sitema te li devi gestire scrivendo codice diependente dalla piattaforma.

Comunque penso che anche windows è scritto totalmente in C, poi salendo di livello useranno C# o altro di casa loro, ma non penso proprio che siano così idioti da pensare di scrivere un kernel in C#, anche perchè per forza di cose una porzione deve essere scritta un un linguaggio che non richiede intermediari.

Comunque ritornando in tema, si può scrivere una libreria C, se si trovano altri interessati si può iniziare a proprorre qualcosa su cui discutere, diversamente tutto rimane com'è.

Ciao.

Logged

AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home

0
Offline Offline
Faraday Member
**
Karma: 45
Posts: 5790
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

A volte è divertente leggere anche cose di cui non si capisce niente  smiley
Logged

- [Guida] IDE - http://goo.gl/ln6glr
- [Lib] ST7032i LCD I2C - http://goo.gl/GNojT6
- [Lib] PCF8574+HD44780 LCD I2C - http://goo.gl/r7CstH

0
Offline Offline
Faraday Member
**
Karma: 30
Posts: 2905
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Sono cosciente di aver usato termini specifici poco comprensibili, ma tu e gli che avete interesse siete liberi di porre domande e sta sicuro che almeno da parte mia tenterò di dare una risposta la più comprensibile possibile.

Indirezzione http://www.google.it/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&ved=0CDUQFjAA&url=http%3A%2F%2Fit.wikipedia.org%2Fwiki%2FIndirezione&ei=zgqQUZb6K4rE4gSNuYHQAw&usg=AFQjCNEPuXSwX4bqZ7DcKzAyy0DS4RAgtA&bvm=bv.46340616,d.bGE

Anziche agire direttamente su un registro interno crei una struttura nella quale ci metti dei puntatori ai registri e poi usi delle funzioni che manipolano i puntatori presenti nella struttura i quali puntano ad altri indirizzi. Mi pare ovvio che più numerose sono le indirezzioni più lentamente viene eseguito il lavoro finale che è quello di agire sul registro.

Ciao.









Logged

AvrDudeQui front end per avrdude https://gitorious.org/avrdudequi/pages/Home

0
Offline Offline
Faraday Member
**
Karma: 45
Posts: 5790
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Non voleva essere una critica, sia chiaro, ma solo una sottolineatura della mia ignoranza  smiley
Logged

- [Guida] IDE - http://goo.gl/ln6glr
- [Lib] ST7032i LCD I2C - http://goo.gl/GNojT6
- [Lib] PCF8574+HD44780 LCD I2C - http://goo.gl/r7CstH

Pages: 1 [2]   Go Up
Jump to: