Creare Librerie

Se io ho bisogno di una funzione che mi ritorni 3 valori float come posso fare?

E' meglio dichiarare tre variabili pubbliche poi utilizzarle nello sketch?

Se hai necessità che restituisca tre diversi valori potresti passarli come puntatori ed elaborarli all'interno della funzione oppure li dichiari globali e li hai sempre a disposizione.

grazie!!!

Una delucidazione, spero sia l'ultima per vedere se ho capito bene:

Variabile public:
Le posso usare sia nelle funzioni della classe, sia al di fuori e rimangono definite per 'sempre'
Variale private:
Utilizzabili solo dentro alla classe, rimangono valide per 'sempre'
Variabile dichiarate dentro una funzione (di una classe o meno):
Valgono solo dentro quella funzione e vengono ridichiarate ad ogni ciclo

E' corretto?

Quindi se io ho bisogno di una variabile solo dentro una funzione di una classe, ma che rimanga anche alla chiamata successiva per una iterazione, la dovrei mettere private, se una mi serve averla sempre e accessibile 'dallo sketch' la devo mettere pubblica.
Se mi basta averla dentro a una funzione la dichiaro li dentro

prima di tutto c'è il tempo di vita delle variabili.
Una variabile che viene istanziata all'interno di un blocco,muore alla sua fine.
Un blocco è delimitatato da { }
quindi una bariabile dichiartata in un blocco if, morirà al termine dell'if.

Poi c'è la visibilità;
una variabile/funzione/classe public è richiamabile all'esterno della classe;
una variabile/funzione/classe protected è richiamabile dalle sotto classi;
una variabile/funzione/classe private è richiamabile dalla classe che la istanzia;

Riesumo nuovamente un topic sulle librerie per chiedere una spiegazione:

Innanzitutto ho trovato in giro delle librerie che non hanno bisogno di essere inizializzate dal costruttore, si tratta di librerie che non lavorano a classi?
(Ho letto che le librerie non per forza devono essere organizzate in classi, come si fanno queste ultime?)

Ad esempio prendiamo la libreria Wire.h... non ha il costruttore no? come faccio a creare una libreria simile?

Se poi io volessi usare una libreria dentro un'altra libreria, oppure una funzione di comodo dentro alla funzione che non uso all'esterno, ma che alcune funzioni della stessa libreria richiamano. Come devo dichiararla?

Faccio un esempio pratico: ho 2-3 funzioni che elaborano dei dati letti da un sensore I2C, per la lettura voglio fare una funzione a sé che richiamo senza scrivere ogni volta...la dichiaro sempre allo stesso modo type CLASS::function(){}? e quando la richiamo la chiamo senza il costruttore (che ovviamente dentro alla libreria non so visto che è a discrezione)?

Spero di essere stato chiaro, anche se mi rendo conto di essere stato un po' contorto in alcuni punti

Ho fatto delle prove quindi esplicito meglio le mie domande e i miei dubbi:

  • Come funzionano le librerie senza classi di cui ho letto in internet e/o su qualche guida?
  • Una di queste è tipo la Wire? cioè una libreria che non ha bisogno di costruttore quando la uso? (per costruttore intendo qualcosa del tipo ClassName pinco; e poi uso pinco.function()...

Ho poi provato a vedere come funziona richiamare una funzione in una seconda funzione della stessa classe, ho visto che non serve il costruttore, ma se io ho bisogno di usare la funzione di un'altra classe o di un'altra libreria?
Faccio un esempio: devo creare una libreria che mi serve a leggere due sensori I2C:

  • Voglio fare tutta una libreria in cui metto tre classi: Calcoli sensore 1, calcoli sensore 2, lettura sensori generica che mi servirà in entrambe le altre classi
  • Voglio includere una libreria dentro a questa (di fatto suddivido le tre classi sopra indicate in tre lib diverse), come faccio? Intendo dire tipo quello che si fa con Wire...la includo, uso il begin e posso usare le sue funzioni ovunque

Spero di essermi spiegato meglio :slight_smile:

Sicuramente hai dato il massimo per spiegarti, ma non sono riuscito a seguirti.

La Wire, come la Serial sono classi che hanno un costruttore (in C++ il costruttore c'è sempre) e vengono pre-istanziate nel codice di libreria. Se apri Wire.h e Wire.cpp ti accorgi che in all'ultima riga del .cpp, che la creazione di una istanza:

TwoWire Wire = TwoWire();

nel .h c'è la dichiarazione di Wire extern:

extern TwoWire Wire;

Quest'ultima rende visibile la variabile Wire a tutto il codice che include l'header file Wire.h.

Se tu vuoi fare la stessa cosa prendi esempio da Wire, se non è questo che ti serve, spiega cosa ti serve.
Forse sarebbe più semplice se spiegassi un solo punto per volta e così' ci si concentra su una sola cosa.

Ciao.

Beh si diciamo che hai dato soluzione a molti miei dubbi, ora vorrei capire bene cosa vuol dire quel codice, ma ho capito che di fatto fa l'istanza già dentro la libreria e l'Arduino ovviamente la vede come parte di codice integrando tutto assieme.

Solo che in genere l'istanza la si fa tipo

nomeClasse name;
oppure se necessita di parametri nomeClasse name(parametri);

quindi perché abbiamo TwoWire Wire=TwoWire(); cioè a cosa fanno riferimento? Wire sicuramente al 'name' indicato prima, il primo TwoWire sarà il 'nomeClasse', ma il secondo TwoWire?

Il resto me lo sono appena risolto da solo con l'aiuto della Cookbook

grazie mille:)

Il resto me lo sono appena risolto da solo con l'aiuto della Cookbook

Quale libro? link please (sempre se c'è link).

Argomentare sarebbe lungo e io non ho informazioni fresche su C++.
Non ho idea del perché abbia usato quella sintassi, per me sarebbe bastato TwoWire Wire;
In quel caso si è chiamato in causa il costruttore di copia e non ho indagato se nella classe ne è stato fornito uno
esplicito. Quando ho qualche dubbio, apro QtCreator creo un progetto C++ e sperimento sul PC.

Ciao.

Il link alla cookbook si trova in giro, io ce l'ho, ma non so se sia legale e quindi se si possa inserire qui nel forum/sito...ad ogni modo con una piccola ricerca su google lo trovi.
Si chiama Arduino Cookbook della O'reilly.

Grazie comunque!!!

Innanzitutto ho trovato in giro delle librerie che non hanno bisogno di essere inizializzate dal costruttore, si tratta di librerie che non lavorano a classi?

dipende. A colpo d'occhio puoi distuinguere una classe (quindi C++) da una libreria (quindi C) (quindi sì, chiamare "librerie" quelle di arduino è un errore, sono quasi tutte classi) dal fatto che di solito una classe ha un file .cpp che si chiama come il file .h e ne implementa i metodi. Poi se apri il .h e vedi "class" o "interface" da qualche parte, allora sai che hai a che fare con una classe :slight_smile: )

Dal punto di vista funzionale invece cambia tantissimo; avere un oggetto fa in modo tale che tu possa fare nomeOggetto.funzione(parametro); invece una vera libreria è una raccolta di funzioni che vengono appese (immagina un copia/incolla) al tuo codice, il che vuol dire che hai un sacco di problemi; niente funzioni con lo stesso nome, niente "memorizzazione di stato" per la amancanza di variabili etc..

Quindi una classe può contenere una o più altre classi, o perfino estenderle, mentre una libreria è una grezza raccolta di funzioni.

Di default tutte le classi hanno un costruttore "void", ovvero senza parametri e che non fa nulla. Se vuoi tu puoi sovrascrivere (override) questo costruttore, aggiungendo anche parametri (sovraccaricarlo).

quindi

TwoWire::TwoWire(){//override costruttore void
}

TwoWire::TwoWire(int parametro){//sovraccarico costruttore
}

In generale temo ti manchino le basi per riuscire a capire a fondo il tema. Parti dall'idea ad oggetti (C++) o lineare (C) perchè sono due cose fondamewntalmente differenti.

Consiglio di programmareil C puro su pc (copn arduino è pressochè impossibile) e vedrai che le differenze e tantecose le capirai

Grazie lesto,

quindi detta in parole spicce: si può fare una classe che ti permette di avere molte 'funzionalità' in più. Cioè di chiamare più funzioni con lo stesso nome perché poi sono richiamate dal costruttore di classe ecc. ecc.

Oppure fare un semplice elenco di funzioni (C non l'ho usato molto, però con PHP e Javascript è lo stesso) dove si mettono le funzioni e poi si caricano nello sketch e via. Questa seconda opzione con Arduino non è possibile giusto? Quello che io utilizzo senza istanza (Wire, Serial, SD) è solo perché è già istanziato nella libreria?

Poi andrò chiaramente a cercare qualche guida, ma cerco di fare le cose mirate, anche perché purtroppo il tempo che ho non è molto e in quella, poca, esperienza che ho, mi sono reso conto che apprendo molto di più a pormi i problemi facendo cose anche 'ambiziose' e rispondendomi (anche non partendo dalle basi basi) che prendere una guida, leggerla senza 'giocare' e finire per dover rileggere ogni volta che mi serve una cosa

(C non l'ho usato molto, però con PHP e Javascript è lo stesso)

attento che PHP e JS inseriscono qualche cosa di oggetti, per esempio puoi incapsulare variabilioltre che funzioni e giochetti simili..

non è possibile giusto

si che è possibile, basta aprire un secondo tab (o più) nell'edito ed inserire le propire funzioni. Non si fa così nel C vero, ma ci avvicianiamo abbastanza. ( l'ide arduino non gioca proprio pulito, per questo consigliavo di fare programmi lato pc)

Quello che io utilizzo senza istanza (Wire, Serial, SD) è solo perché è già istanziato nella libreria?

esatto, la classe crea un istanza (di solito statica) di se stessa, così tu non rischi di istanzairala due volte e creare casini. Invece la Servo, per esempio, non si auto istanzia, perchè ogni pin è comandabile a sè. Immagina di fare la stessa cosa con le funzioni e basta; non puoi,dovresti essere te a mantenere un array di strutture contenenti i dadi da passare alle funzioni in base a quale pin vuoi comandare.

Se vai nel reference, troverai come scrivere una "libreria" in aruino, che poi è una classe. Ti consiglio di seguirla,

Grazie mille, ti rompo ancora per una cosa:

quando scrivo una funzione in libreria e inserisco dei parametri anticipati da *nome o &nome che significa?

Credo di aver capito che si tratta di indicare tipo l'indirizzo della variabile da modificare o qualcosa del genere, nel senso che modificando, all'interno della funzione, la variabile 'nome' vado in realtà a fare la modifica alla variabile che ho passato durante lo sketch nella posizione di nome.

E' corretto? cosa cambia per le due sintassi?

cosa cambia? il mondo.
Non sto scherzando, la differenza è che stai usando i puntatori, concetto fondamentale non solo del C, ma di TUTTI i linguaggi di programmazione, anche se fanno di tutto per nasconderteli. Molto potenti, e per questo molto facile combinare casini :slight_smile:

Segui la guida che ho in firma, ti porta ad una guida su HTML.it sul C in italiano ottima per iniziare.

Il C++ ha introdotto il passaggio di parametri per rifermento o alias tramite l'operatore &.
La confusione deriva dal fatto che & ricava l'indirizzo di una variabile.
L'operatore & usato su un parametro significa passa il riferimento ed è come se passassi il puntatore, cioè non viene fatta una copia locale del parametro.

Passare un puntatore o un riferimento e più rapido, più efficiente. Alle volte non vogliamo modificare il valore, ci basta leggere il contenuto della variabile passata per riferimento o come puntatore, in tal caso si usa anteporre il qualificatore "const", es: (const type &nameVar) o (const type *nameVar).
Ci sono varianti che per essere comprese si devono sperimentare sul pc, es: (type * const nameVar) il puntatore è costante ma il contenuto di nameVar lo posso cambiare senza ricevere errore in fase di compilazione.

Con (const type *nameVar) se provi a cambiare il contenuto della variabile da dentro la funzione ricevi errore in fase di compilazione.

Sono convinto che la difficoltà di comprensione con i puntatore e gli alias deriva dal fatto che non si ha bene chiaro
come è organizzata la RAM, un buon libro C/C++ spiega i puntatori usando delle caselle numerate con indirizzi esadecimali e mostra cosa accade graficamente.

Ciao.

Il C++ ha introdotto

??? il passaggio di puntatori come parametri c'è anche in C

Solito link "legale per uso personale" da dove reperire un bel libro sull'argomento ... Understanding and Using C Pointers

@ mastraa : studiatelo bene ... :wink:

Guglielmo

lesto:
cosa cambia? il mondo.
Non sto scherzando, la differenza è che stai usando i puntatori, concetto fondamentale non solo del C, ma di TUTTI i linguaggi di programmazione, anche se fanno di tutto per nasconderteli. Molto potenti, e per questo molto facile combinare casini :slight_smile:

Segui la guida che ho in firma, ti porta ad una guida su HTML.it sul C in italiano ottima per iniziare.

Adesso la guardo, non mi veniva la parola così al posto di puntatori ho messo indirizzo credo ]:smiley: