Spesso voglio che la scheda Arduino controlli diverse periferiche. Scrivere un programma per tutti in un documento usando #define SOME_PIN 4
costruzioni mi sembra abbastanza sconveniente. Soprattutto in questo caso quando devi modificare il vecchio codice che è stato scritto molto tempo fa.
Ho scelto di utilizzare il seguente approccio per organizzare la parte di programmazione di un progetto. Quindi scrivere un codice potrebbe essere diviso in tre parti.
1. Struttura interfaccia
In questa fase il programmatore dovrebbe descrivere tutti i dispositivi usati nel suo progetto. Naturalmente, solo quelli di loro che Arduino programmaticamente interagisce con (sensori, chip e non resistori intermedi, per esempio). Ogni dispositivo in questa fase è rappresentato da una classe - description-class . La classe descrittiva ha funzioni membro speciali - funzioni-pin . Quelle funzioni sono pure virtuali e ognuna di esse è destinata a restituire un valore intero senza segno a 8 bit dal set di numeri di pin Arduino. Le funzioni pin svolgono un ruolo di fili tra Arduino e le periferiche. La classe descrittiva dovrebbe contenere anche funzioni che sono istruzioni Arduino e destinate a questo dispositivo concreto.
Arduino ha anche una classe descrittiva, ma ora è usata come spazio dei nomi con costanti. Nessun oggetto di questa classe è necessario finora.
Di seguito è riportato un esempio di utilizzo dell'interfaccia.
- Controller: Arduino Uno R3
- Periferiche: sensore ultrasonico HC-SR04
1.1 Descrizione della classe Arduino Uno R3
La classe descrizione di Arduino Uno R3 consiste solo di costanti statiche che sono numeri pin.
1.1.1 Uno.h
#ifndef UNO_H
#define UNO_H
#include <inttypes.h>
class Uno
{
public :
//Digital pins
static const uint8_t D0 = 0;
static const uint8_t D1 = 1;
static const uint8_t D2 = 2;
static const uint8_t D3 = 3;
static const uint8_t D4 = 4;
static const uint8_t D5 = 5;
static const uint8_t D6 = 6;
static const uint8_t D7 = 7;
static const uint8_t D8 = 8;
static const uint8_t D9 = 9;
static const uint8_t D10 = 10;
static const uint8_t D11 = 11;
static const uint8_t D12 = 12;
static const uint8_t D13 = 13;
//Analog pins
static const uint8_t A0 = 0;
static const uint8_t A1 = 1;
static const uint8_t A2 = 2;
static const uint8_t A3 = 3;
static const uint8_t A4 = 4;
static const uint8_t A5 = 5;
//SPI
static const uint8_t SS = D10;
static const uint8_t MOSI = D11;
static const uint8_t MISO = D12;
static const uint8_t SCK = D13;
//I2C
static const uint8_t SDA = A4;
static const uint8_t SCL = A5;
//Serial
static const uint8_t TX = D0;
static const uint8_t RX = D1;
};
#endif
1.2. Descrizione della descrizione del sensore ultrasonico (dispositivo astratto)
Per questo esempio ho scelto di utilizzare il sensore ultrasonico HC-SR04. Ha quattro pin: VCC
, GND
, TRIG
e ECHO
. Anche se in realtà (qualunque cosa sia) tutti e quattro i pin sono collegati ad Arduino, solo TRIG
e ECHO
sono usati nel programma. Non so cosa fare con quegli spilli finora. Forse non dovrebbero mai apparire nel codice.
1.2.1 HC_SR04.h
#ifndef HC_SR04_H
#define HC_SR04_H
#include <inttypes.h>
#include <Arduino.h>
class HC_SR04
{
public :
//pin-functions
virtual uint8_t VCC() = 0;//???
virtual uint8_t TRIG() = 0;
virtual uint8_t ECHO() = 0;
virtual uint8_t GND() = 0;//???
//device specific functions
void setup();
long get_distance();
};
#endif
1.2.2 HC_SR04.cpp
#include "HC_SR04.h"
void HC_SR04::setup()
{
pinMode( TRIG(), OUTPUT );
pinMode( ECHO(), INPUT );
}
long HC_SR04::get_distance()
{
digitalWrite( TRIG(), LOW );
delayMicroseconds( 2 );
digitalWrite( TRIG(), HIGH );
delayMicroseconds( 10 );
digitalWrite( TRIG(), HIGH );
return 0.017 * pulseIn( ECHO(), HIGH );
}
2. Descrizione della CPU
In questa fase il programmatore dovrebbe "collegare" tutti i dispositivi reali sul tavolo sovraccaricando le funzioni pin in una sottoclasse derivata dalla corrispondente descrizione della classe.
2.1 Sensore a ultrasuoni (dispositivo reale)
2.1.1 US.cpp
#include "Uno.h"
#include "HC_SR04.h"
class US : public HC_SR04
{
public :
uint8_t VCC() { return 0; }//What to do with this pin
uint8_t GND() { return 0; }//What to do with this pin
uint8_t TRIG() { return Uno::D10; }//wire between TRIG-pin on US and 10th digital pin on Uno
uint8_t ECHO() { return Uno::D11; }//...
};
3. File principale (file .ino)
#include "US.cpp"//bad line?
US us;//Create ultrasonic device plugged in as descripted in US.cpp file
void setup()
{
Serial.begin( 9600 );
us.setup();
}
void loop()
{
Serial.println( us.get_distance() );
delay( 1000 );
}
4. Struttura della directory del progetto
5.Discussione
Eccolamiavistasull'approcciosopra.Certo,potrebbeesseresbagliato.
Svantaggi:
- Livelloaggiuntivodiastrazione=(forse)negativopericontrolleramemoriabassa
- L'interoprogrammaèdivisoinparti.Ogniparteèresponsabiledellacomunicazioneconildispositivoconcreto.(forse)Cattivoperunprogettocondispositividipendenti
Ivantaggi:
- L'interoprogrammaèdivisoinparti.Ogniparteèresponsabiledellacomunicazioneconildispositivoconcreto.Ottimoperunprogettoconmolteperifericheindipendenti
- Codiceauto-descrittivo
- Codiceriutilizzabileperdispositivisimilioaltriprogetticonglistessidispositivi
Perfavore,dimmicosanepensi.Comesempre,qualsiasiidea,correzione,critica,ecc.Sarebbeapprezzata.
P.S.PercaricareilprogrammasuArduino,utilizzo