How To: Crea la tua prima libreria per Arduino!

 

Svolgendo diversi progetti può succedere che alcune funzionalità debbano essere riutilizzate o passate ad altre persone. Il modo più veloce per farlo è creare una libreria.Per Arduino una libreria è essenzialmente una classe cioè un’entità con determinate funzionalità(metodi).

In questa guida verrà presentato come fare una libreria che utilizzi un pin per trasmettere informazioni con il codice morse con un LED. Armiamoci di un text editor( Notepad++ va più che bene) e iniziamo!

Organizzare il progetto

Il primo passo sta nell’organizzare le funzionalità della nostra libreria, cioè cosa deve essere in grado di fare.

Il nostro esempio è molto semplice ed ha solo tre metodi(funzionalità):

  1. Inizializzazione: nella quale associamo un pin alla nostra libreria, che verrà utilizzato come output per il LED. Questa è una funzionalità speciale, che deve essere chiamata alla creazione della nostra libreria(costruttore)
  2. Segnale punto: cioè accendere e spegnere il LED in un’intervallo che rappresenta un punto
  3. Segnale linea: cioè accendere e spegnere il LED in un’intervallo che rappresenta una linea

Iniziare a scrivere la libreria

Creiamo due file : uno chiamato “Morse.h” e l’altro “Morse.cpp”.

Nel primo file(header) scriveremo lo scheletro della nostra libreria, nel file .cpp l’implementazione vera e propria.

Questo è il contenuto del file Morse.h:

 C |  copy code |? 
01
#ifndef Morse_h
02
#define Morse_h
03
#include <WProgram.h>
04
 
05
class Morse
06
{
07
 public:
08
     Morse(int pin);
09
     void punto();
10
     void linea();
11
 private:
12
     int _pin;
13
};
14
#endif
15

Questo è lo scheletro della nostra classe. Come si può vedere il codice che definisce la classe è racchiuso da:

 C |  copy code |? 
1
#ifndef Morse_h
2
#define Morse_h
3
//il nostro codice
4
#endif

Che serve per assicurarci che non tentiamo due volte di includere la libreria Morse. Successivamente viene incluso il file WProgram.h che ci consente di utilizzare le funzionalità base dell’Arduino.

All’interno di questa classe ci sono due tipi di metodi o variabili: private o public. Un elemento public può essere richiamato dal nostro sketch, un metodo o variabile definito come private può essere utilizzato solo all’interno della classe stessa.

Il primo dei tre metodi è il costruttore, questo metodo ha il nome della classe e non ha alcun tipo di ritorno( neppure void). Gli altri due metodi implementano le nostre due funzionalità. Questi tre metodi sono pubblici.

L’unica variabile privata è il valore _pin, perchè dall’esterno non dobbiamo poterla modificare

Passiamo adesso il file Morse.cpp che come abbiamo detto dovrà implementare il costruttore e i due metodi punto() e linea().

Questo sarà il nostro Morse.cpp:

 C |  copy code |? 
01
#include <wprogram.h>
02
#include "Morse.h"
03
 
04
Morse::Morse(int&nbsp;pin)
05
{
06
pinMode(pin,OUTPUT);
07
_pin&nbsp;&nbsp;pin;
08
}
09
 
10
void&nbsp;Morse::punto()
11
{
12
digitalWrite(_pin,HIGH);
13
delay(250);
14
digitalWrite(_pin,LOW);
15
delay(250);
16
}
17
 
18
void Morse::linea()
19
{
20
digitalWrite(_pin,HIGH);
21
delay(1000);
22
digitalWrite(_pin,LOW);
23
delay(250);
24
}

All’inizio viene incluso sia il file Morse.h che abbiamo creato prima sia WProgram.h.

 C |  copy code |? 
1
2
Morse::Morse(int pin)
3
{
4
pinMode(pin, OUTPUT);
5
_pin=&pin;
6
}

Qui viene implementato il costruttore. Viene richiamato il metodo pinMode per impostare il valore del pin passato come parametro al metodo e viene assegnato un valore alla variabile _pin in modo tale di avere questo dato comune a tutta la classe quando verranno utilizzato gli altri metodi.

 C |  copy code |? 
01
02
void Morse::punto()
03
{
04
digitalWrite(_pin, HIGH);
05
delay(250);
06
digitalWrite(_pin, LOW);
07
delay(250);
08
}
09
void Morse::linea()
10
{
11
digitalWrite(_pin, HIGH);
12
delay(1000);
13
digitalWrite(_pin, LOW);
14
delay(250);
15
}
16

Questi metodi sono simili tra loro e accendono per un tempo corto o lungo il pin definita dalla variabile _pin. Questi metodi non riportano nulla.

Ultimi ritocchi

Prima che possiamo usare bene la nostra libreria ci sono altri due accorgimenti: aggiungere la nostra libreria tra quelle disponibili all’interno della lista dell’IDE e fare in modo che il nome della classe e i suoi metodi all’interno dello sketch abbiano la giusta formattazione(poiché l’IDE non lo fa in atomatico).

Per il primo accorgimento inseriamo i due files Morse.h e Morse.cpp in una cartella chiamata Morse e copiamola all’interno della cartella “libraries” dell’IDE. Ora andando su “sketch->Import library” troveremo anche la nostra Morse.

Per il secondo miglioramento aggiungiamo un file chiamato keywords.txt all’interno della cartella Morse nel quale scriviamo:

 C |  copy code |? 
1
2
Morse  KEYWORD1
3
dash   KEYWORD2
4
dot    KEYWORD2
5

Che formatta il nome della classe in un modo specifico(quello definito da KEYWORD1) e i metodi in un altro(quello definito da KEYDORD2).

Utilizzare la nostra libreria

Ora creiamo un semplice sketch:

 C |  copy code |? 
01
02
#include <Morse.h>
03
Morse morse(13);
04
 
05
void setup()
06
{
07
}
08
 
09
void loop()
10
{
11
morse.punto();morse.punto();morse.punto();
12
morse.linea();morse.linea();morse.linea();
13
morse.punto();morse.punto();morse.punto();
14
delay(3000);
15
}
16

Si vede che viene richiamata la libreria con il comando #include, poi creata una sua istanza con Morse morse(13) nel quale passiamo il valore da passare al costruttore e poi vengono richiamati i metodi punto() e linea() nel loop per riprodurre il segnale di SOS.

Si può migliorare la nostra libreria aggiungendo altre funzionalità come, ad esempio:

  • Settare dei valori arbitrari per la lunghezza temporale del ‘punto’ e ‘linea’
  • Creare un metodo al quale puoi passare un carattere(o un’ intera stringa) che viene espressa con il linguaggio Morse

La fantasia(e i limiti di complessità che può sostenere l’Arduino) sono i nostri limiti!  

Alcune note utili

Qui raccolgo alcune cose che ho notato/affrontato creando alcune semplici librerie:

  • Utilizzo della classe Serial
Per utilizzare la classe Serial e le sue funzionalità nella nostra libreria conviene passarla al costruttore che, nella sua implementazione, deve ricevere come parametro corrispondente riferimento ad un’HardwareSerial
Ad esempio:
Nella nostra libreria abbiamo:
-Nel file miaLibreria.h il costruttore miaLibreria( HardwareSerial &serial)
-Nel nostro sketch bisognerà chiamare il costruttore così: miaLibreria miaLib(Serial)
  • Utilizzo delle stringhe

Non potendo implementare la classe di Arduino che gestisce le stringhe(che a volte può risultare troppo pesante) dobbiamo riferirci alle stringhe come array di char(quindi ad esempio char[] prova) che possiamo manipolare con i metodi usuali del C: strcpy e sprintfI( che non supporta i float come parametri).

  • Alcuni tipi di dati particolari

Oltre WProgram.h è fondamentale includere inttypes.h quando si utilizzano alcuni tipi di variabili all’interno della nostra libreria come ad esempio uint8_t identifica una variabile da 8 bit unsigned.

Luca Panebianco

Luca Panebianco

Ciao! Mi chiamo Luca e frequento la magistrale in Ingegneria Informatica e dell'Automazione all'Università Politecnica delle Marche. Qui ho apprezzato pian piano la programmazione su microcontrollori oltre che la canonica sul PC. Sono interessato ai vari campi della programmazione su diversi dispositivi.

More Posts

By Luca Panebianco | aprile 4th, 2012 | SHOW COMMENTS (6)
  • Cristian

    Il non-breaking space ( &.n.b.s.p; senza puntini) non fa parte del codice o sbaglio?

    • Luca Panebianco

      Grazie per la segnalazione!
      Nono…non sbagli…ho già corretto…..
      E’ colpa di WordPress che cerca di dare una formattazione HTML anche alla parte riguardante il codice(che è racchiuso in un suo tag). Quando creo l’articolo il codice HTML non si vede, ma si vede solo in fase finale(pubblicazione vera e propria) dove la parte di codice viene formattata a parte e i non-breaking-spaces non vengono formattati ma diventano puro testo…
      In tutti le altre porzioni di codice avevo risolto, quello mi è sfuggito…:)

  • Marco

    Caro Luca, seguendo le sue istruzioni ho provato a creare una libreria per gestire i vari input possibili, leggendo gli ingressi con funzioni contenute nella libreria, ma già ai primi passi ho incontrato delle difficoltà (sono un ingegnere meccanico, per cui di informatica non ho molte nozioni). L’ambiente di Arduino in fase di compilazione mi dice che le funzioni definite nella libreria non sono visibili. Le allego il file header e il cpp, le sarei grato se potesse indicarmi dove sbaglio:

    .cpp

    #include “INPUTLIB.h”  // dichiarazione della classe

    /* Encoder. Restituisce 0,-1 o +1 a seconda della rotazione e del senso di rotazione dell’encoder */

    int8_t INPUTLIB::encoder(uint8_t ENC_PORT)                                     
    {
      static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};  
      static uint8_t old_AB = 0;
     
      old_AB <<= 2;                  
      old_AB |= ( ENC_PORT & 0×03 );  
      return ( enc_states[( old_AB & 0x0f )]);
    }

    /* Button. Legge gli input di un bottone.  */

    bool INPUTLIB::button (uint8_t BUTTONPIN)

    {
    static bool puls;
    static bool oldpuls;
    static bool state = 0;

      puls = digitalRead  (BUTTONPIN);               //leggo il valore del pulsante
       if ((puls == HIGH)&&(oldpuls == LOW))                     
      {
        state = 1 – state;
        delay(10);
        }
       
       oldpuls = puls;
       
       return (state);

     
      } 

    .h

    #ifndef INPUTLIB_H#define INPUTLIB_H#include "Arduino.h"#include #include class INPUTLIB{   public:      int8_t encoder(uint8_t ENC_PORT);           bool button (uint8_t BUTTONPIN);         private:       bool puls;       bool oldpuls;       bool state;       int8_t enc_states[];         uint8_t old_AB;};#endif

  • Luca Panebianco

    Ciao Marco,
    mi scuso prima di tutto per il ritardo con il quale rispondo ma non mi ero accorto fino ad oggi del tuo commento.
    Innanzitutto per quello che riguarda i tuoi file .cpp e .h non ho notato anomalie, solo il fatto che non esiste il costruttore, ma non è un problema.
    Sono riuscito a creare la classe in un progetto e a compilare senza problemi
    Quello che può aver comportato il problema nell’ambiente Arduino è aver scritto per costruire la classe INPUTLIB nel momento di inizializzarla
    INPUTLIB prova();
    invece di 
    INPUTLIB prova;

    Nel primo caso il compilatore pensa che esista una funzione chiamata “prova” che ritorna un oggetto di tipo INPUTLIB.
    L’errore che l’IDE mi riporta in questo caso è:
     
    error: request for member ‘encoder’ in ‘prova’, which is of non-class type ‘INPUTLIB ()()’

    Nel caso l’errore non fosse questo mi servirebbe l’errore dell’IDE e lo sketch per l’Arduino.
    Scusami ancora per il ritardo.
    Luca

  • Andrea

    Volevo sapere se è possibile inserire più di un costruttore (con nome ovviamente differenti) su una libreria?

    • Luca Panebianco

      Ciao, il costruttore per definizione ha il nome della classe stessa, quindi può esistere solo un “nome” per il costruttore.
      L’alternativa migliore è sfruttare l’overload: praticamente utilizzare due costruttori con “firma” diversa, cioè un diverso numero e/o tipo di parametri da passare.
      Ad esempio si può implementare un costruttore che ha impostazioni considerate di default(per esempio un valore di delay) che quindi non avrà parametri e un’altro nel quale l’utente può selezionare il valore che vuole(quindi avrà come parametro un int o long).
      Spero di essere stato chiaro :)