2. Modbus Arduino Helper

Il software che presentiamo in questa sezione è parte dello Slave Modbus Arduino che stiamo costruendo.

Una rappresentazione a strati (layer) è visibile nella seguente figura:SWLayer

Sull’hardware Arduino abbiamo costruito una libreria per la sua gestione che specializza ogni PIN della scheda secondo le esigenze del progetto, offrendo dei metodi per la loro gestione che astraggono dall’hardware sottostante. In questa libreria vengono definite anche alcune funzioni di utilità per la gestione dello storage persistente (EEPROM) e alcune funzioni per la gestione dell’interfaccia seriale da affiancare a quelle standard di Arduino.
Sopra questo strato implementeremo una libreria che effettua il MAPPING MODBUS, definendo funzioni Modbus e indirizzi Modbus, degli oggetti presentati dall’helper.
Ancora sopra c’è lo strato di logica e di gestione dello SLAVE Modbus. Lo SLAVE Modbus è una classe astratta in C++ che quindi dovrà essere sempre utilizzata come classe padre della classe concreta che la implementa. Per questo ci penserà l’ultimo strato presentato in figura, ove la classe padre viede derivata dalle classi concrete che implementano il protocollo Modbus con trasporto RS485 o TcpIP.

L’architettura software in termini di moduli, file e funzionalità è illustrata nella seguente figura:

SWArch

La parte che analizziamo in questo primo articolo riguarda il modulo ArduHelper ed i suoi diretti correlati (Timer2 e MBUtils) che preparano la scheda Arduino ad essere utilizzata per il modulo Slave Modbus e aggiungono delle funzionalità di aiuto/utilità (helper) per leggere e scrivere i dati provenienti o destinati verso l’hardware della scheda.
I moduli software che analizziamo hanno i seguenti scopi:

  • MsTimer2: è composto da una libreria di terze parti illustrata sul sito Arduino.cc chiamata MSTimer2 (http://playground.arduino.cc/Main/MsTimer2) (a cui si rimanda per approfondimenti) ed è una piccola libreria che rende facilmente utilizzabile il Timer2 del chip (ATmega328) utilizzato da Arduino Uno esponendo un’interfaccia molto semplice da utilizzare. La sua risoluzione massima è di 1ms.
  • Utils: definisce, attraverso il suo file MBUtils.h, una serie di costanti e macro per lavorare con BYTE, WORD (16bit), DOUBLE-WORD (32bit).
  • ArduHelper: composto dai file MBArduHelper.h e ArduHelper.cpp definisce l’utilizzo dei PIN della scheda Arduino fornendo alcune funzioni di utilità per la gestione della scheda stessa. Vedremo per bene come è fatto questo modulo nelle righe seguenti.

All’interno del file header (MBArduHelper.h) troviamo la definizione di costanti per l’utilizzo dei PIN della scheda secondo il seguente schema:

// Mapping with Arduino UNO PINs
/* 
Pin Usage          Name 
---------------------------------- 
A0  Analog input   ARDU_ANALOG00 
A1  Analog input   ARDU_ANALOG01 
A2  Analog input   ARDU_ANALOG02 
A3  Analog input   ARDU_ANALOG03 
A4  Analog input   ARDU_ANALOG04 
A5  Analog input   ARDU_ANALOG05 
0   Serial RX      ARDU_RX 
1   Serial TX      ARDU_TX 
2   External IRQ   ARDU_COUNTER00 
3   External IRQ   ARDU_COUNTER01 
4   Digital I/O    ARDU_DIGITAL00 
5   Digital I/O    ARDU_DIGITAL01 
6   Digital I/O    ARDU_DIGITAL02 
7   Digital I/O    ARDU_DIGITAL03 
8   Digital I/O    ARDU_DIGITAL04 
9   Serial CTRL    ARDU_CTRL 
10  SS             ARDU_SS 
11  MOSI           ARDU_MOSI 
12  MISO           ARDU_MISO 
13  SCK            ARDU_SCK
 ---------------------------------- 
*/

Quindi della scheda utilizzeremo i sei PIN Analogici (che leggono la tensione da 0V a 5V) che verranno indicati con le costanti ARDU_ANALOG0X (con X da 0 a 5). Degli altri PIN verranno utilizzati i PIN 0 e 1 come canali di trasmissione seriale (ARDU_RX e ARDU_TX) per la RS485 insieme al PIN 9 per commutare il canale RS485 in lettura o scrittura (ARDU_CTRL). I PIN 2 e 3 verranno utilizzati come IRQ per poter gestire due contatori da 32 bit (ARDU_COUNTER00 e ARDU_COUNTER01). I PIN da 4 a 8 verranno utilizzati come PIN digitali di ingresso o uscita e verranno indicati con la costante ARDU_DIGITAL0X (con X da 0 a 4). Gli altri PIN, da 10 a 13, verranno utilizzati dallo shield Ethernet nella configurazione TCP.
Insieme a questa mappatura dei PIN della scheda esistono delle altri costanti di configurazione:

  • ARDU_IRQ_COUNTER00 e ARDU_IRQ_COUNTER01 che definiscono gli IRQ da utilizzare per i due counter.
  • ARDU_READ_ANALOG_MS che definisce l’intervallo di lettura (in ms) degli ingressi analogici.

Tutte queste costanti sono interne al modulo ArduHelper. Il software che utilizza questo modulo deve invece far riferimento alla definizione delle costanti e dei metodi all’interno del namespace MBArduHelper.
Per referenziare gli ingressi analogici, i counter e gli I/O digitali abbiamo definito le seguenti costanti:

enum ANALOGS { ANALOG00=0, ANALOG01=1, ANALOG02=2, ANALOG03=3, ANALOG04=4, ANALOG05=5, ANALOGS_COUNT=6 };
enum COUNTERS { COUNTER00=0, COUNTER01=1, COUNTERS_COUNT=2 };
enum DIGITALS { DIGITAL00=0, DIGITAL01=1, DIGITAL02=2, DIGITAL03=3, DIGITAL04=4, DIGITALS_COUNT=5 };

E per la configurazione dell’interfaccia seriale:

// Serial Parameter - RS485
enum { 
    SERIAL_PARITY_NONE = 0x00, // default 
    SERIAL_PARITY_EVEN = 0x40, 
    SERIAL_PARITY_ODD = 0x80, 
    SERIAL_BIT_STOP1 = 0x10, // always 
    SERIAL_BIT_STOP2 = 0x20, // not implemented 
    SERIAL_BIT_DATA5 = 0x05, // not implemented 
    SERIAL_BIT_DATA6 = 0x06, // not implemented 
    SERIAL_BIT_DATA7 = 0x07, // not implemented 
    SERIAL_BIT_DATA8 = 0x08 // always 
};

I metodi definiti all’interno del namespace servono per gestire Arduino. Elenchiamo di seguito questi metodi con le relative spiegazioni di utilizzo.

void ardu_init();

Inizializza la scheda Arduino e va richiamato prima di utilizzare la scheda stessa. Tale metodo inizializza tutti i PIN con settaggi e valori di default (disattiva tutti i contatori portandone il valore a 0, setta tutti gli I/O digitali in modalità INPUT, setta la trasmissione RS485 come TX) e inizializza il Timer2 della scheda (utilizzando la libreria MsTimer2) per la lettura periodica degli ingressi analogici. Questa inizializzazione viene realizzata richiamando la funzione interna _activateAnalogIRQ() che configura il Timer2 in modo che ogni ARDU_READ_ANALOG_MS venga richiamato l’IRQ handler __irqReadAnalogValue:

void _activateAnalogIRQ() {
    // Set interrupt timer and function for analog input 
    MsTimer2::set(ARDU_READ_ANALOG_MS, __irqReadAnalogValue); 
    MsTimer2::start(); 
}
unsigned getAnalogValue(ANALOGS analog);

Permette di leggere il valore dell’ingresso analogico (valore da 0 a 1023).

unsigned long getCounterValue(COUNTERS counter); 
void setCounterValue(COUNTERS counter, unsigned long value);

Queste funzioni permettono di leggere il valore di un counter oppure di settarne il valore iniziale prima di attivarlo.

unsigned getCountersConf(); 
void setCountersConf(unsigned value);

Le funzioni permettono di leggere la configurazione dei counter oppure di settarla. Al momento del setting di uno o di entrambi i counter essi vengono attivati o disattivati, a seconda del valore dei settaggi. La mappatura dei valori è descritta di seguito:

// Counter Configuration bit mapping 
/* 
  Possible IRQ trigger: 
  - LOW to trigger the interrupt whenever the pin is low
  - CHANGE to trigger the interrupt whenever the pin changes value
  - RISING to trigger when the pin goes from low to high
  - FALLING for when the pin goes from high to low. 
  4 bit mapping: 
  XY00: LOW 
  XY01: CHANGE 
  XY10: RISING 
  XY11: FALLING 
  X=0 counter is disabled, X=1 counter is enabled
  Y=0 increase counter, Y=1 decrease counter 
*/ 
// bit 15-8: always 0 
// bit 7,6,5.4: COUNTER01 
// bit 3,2,1,0: COUNTER00
int getDigitalValue(DIGITALS digit); 
void setDigitalValue(DIGITALS digit, int value);

Queste funzioni permettono di leggere o settare il valore di un PIN digitale, secondo la configurazione.

unsigned getDigitalsConf(); 
void setDigitalsConf(unsigned value);

Le funzioni permettono di leggere la configurazione dei PIN digitali oppure di settarla. Al momento del setting di uno o più PIN essi vengono configurati, a seconda del valore dei settaggi. La mappatura dei valori è descritta di seguito:

// Digital Configuration bit mapping 
/* 
  Possible Value: 
  - INPUT (default): Pins configured this way are said to be in a high-impedance state
  - OUTPUT: Pins configured as OUTPUT are said to be in a low-impedance state
  - INPUT_PULLUP: There are 20K pullup resistors built into the Atmega chip that can be accessed from software. The value of this pullup depends on the microcontroller used. On most AVR-based boards, the value is guaranteed to be between 20k and 50k. On the Arduino Due, it is between 50k and 150k. 
  2 bit mapping: 
  00: INPUT 
  01: OUTPUT 
  10: INPUT_PULLUP
*/ 
// bit 8, 9: DIGITAL4 
// bit 6, 7: DIGITAL3 
// bit 4, 5: DIGITAL2 
// bit 2, 3: DIGITAL1 
// bit 0, 1: DIGITAL0
void activateSerial(unsigned int baud = 9600L, byte ppssdddd = 0x18); 
void writeEnableSerial(); // writing enabled 
void readEnableSerial(); // reading enabled

Sono le funzioni per settare l’interfaccia Seriale e per comandare la RS485 in trasmissione o ricezione.
La configurazione della seriale (il byte ppssdddd) è descritto di seguito:

// PPSSDDDD Parity, Stop bits, Data bits 
// Parity: 00 No - 01 Even - 10 Odd 
// Stop bits: 01 1bit - 10 2bits --- always 01 
// Data bits: 0101 5bits - 0110 6bits - 0111 7bits - 1000 8bits --- always 1000 
// In this library version the byte must be --- PP011000, only parity can be change.

Inoltre abbiamo definito alcune funzioni di utilità per la gestione dello storage persistente (EEPROM) di Arduino:

// EEPROM function
byte eepromGetByte(int addr);
void eepromPutByte(int addr, byte val);
word eepromGetWord(int addr);
void eepromPutWord(int addr, word val);
dword eepromGetDWord(int addr);
void eepromPutDWord(int addr, dword val);

Nel seguente articolo parleremo del modulo di mapping dei PIN di Arduino con l’indirizzamento Modbus.

Download section

Libreria MBArduino contenente i file descritti nell’articolo. La libreria va inserita all’interno del folder libraries all’interno della directory di lavoro Arduino.
"Download (9,6 kB)"

Per testare la libreria abbiamo inserito due sketch Arduino, uno che utilizza la libreria (test_arduhelper) per leggere i valori iniettati da un altro sketch (tester_arduhelper) che genera delle onde quadre secondo le seguenti frequenze/tempi e PIN:

#define PIN_50Hz  2
#define PIN_25Hz  3
#define PIN_T1    4
#define PIN_T2    5
#define PIN_T3    6
#define PIN_T4    7
#define PIN_T5    8

Bisogna poi unire il tester con la scheda di test come in figura.

tester

Sketch per il test della libreria.
"Download (1,4 kB)"

Sketch tester per lo sketch di test.
"Download (820,0 B)"

 

Print Friendly

Lascia una risposta

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati *

È possibile utilizzare questi tag ed attributi XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Elettronica, programmazione embedded (Arduino, Raspberry PI) ed altro