Go Down

Topic: Modbus Data Logger (Read 119 times) previous topic - next topic

TedStriker

May 20, 2019, 11:12 am Last Edit: May 20, 2019, 11:26 am by TedStriker
 Buongiorno,

tempo fa ero stato già stato aiutato da ORSO riguardo il modbus, che ringrazio ancora.

Ora vorrei saperne di più a riguardo e vorrei realizzare qualcosa di più "articolato". Grazie appunto all'aiuto di ORSO, sono riuscito a capire un po' di più riguardo il ModBus.

Quello che vorrei realizzare è un datalogger per circa 200 valori, leggerli e storicizzarli.
Premetto che ho già preso un Arduino Zero, in modo da avere più capacità.

Partendo dal codice seguente che ho già usato:

Code: [Select]


/*
*  Test program for Arduino RS422/RS485 Shield
*  Version 1.0
*  Copyright (C) 2018  Hartmut Wendt  www.zihatec.de
*  
*  (based on sources of https://github.com/angeloc/simplemodbusng)
*  
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/  

#include <SimpleModbusSlave.h>

#define  ledPin  12 // onboard led
#define  buttonPin  7 // push button



/* This example code has 9 holding registers. 6 analogue inputs, 1 button, 1 digital output
  and 1 register to indicate errors encountered since started.
  Function 5 (write single coil) is not implemented so I'm using a whole register
  and function 16 to set the onboard Led on the Atmega328P.
 
  The modbus_update() method updates the holdingRegs register array and checks communication.

  Note:  
  The Arduino serial ring buffer is 128 bytes or 64 registers.
  Most of the time you will connect the arduino to a master via serial
  using a MAX485 or similar.

  In a function 3 request the master will attempt to read from your
  slave and since 5 bytes is already used for ID, FUNCTION, NO OF BYTES
  and two BYTES CRC the master can only request 122 bytes or 61 registers.

  In a function 16 request the master will attempt to write to your
  slave and since a 9 bytes is already used for ID, FUNCTION, ADDRESS,
  NO OF REGISTERS, NO OF BYTES and two BYTES CRC the master can only write
  118 bytes or 59 registers.

  Using the FTDI USB to Serial converter the maximum bytes you can send is limited
  to its internal buffer which is 60 bytes or 30 unsigned int registers.

  Thus:

  In a function 3 request the master will attempt to read from your
  slave and since 5 bytes is already used for ID, FUNCTION, NO OF BYTES
  and two BYTES CRC the master can only request 54 bytes or 27 registers.

  In a function 16 request the master will attempt to write to your
  slave and since a 9 bytes is already used for ID, FUNCTION, ADDRESS,
  NO OF REGISTERS, NO OF BYTES and two BYTES CRC the master can only write
  50 bytes or 25 registers.

  Since it is assumed that you will mostly use the Arduino to connect to a
  master without using a USB to Serial converter the internal buffer is set
  the same as the Arduino Serial ring buffer which is 128 bytes.
*/


// Using the enum instruction allows for an easy method for adding and
// removing registers. Doing it this way saves you #defining the size
// of your slaves register array each time you want to add more registers
// and at a glimpse informs you of your slaves register layout.

//////////////// registers of your slave ///////////////////
enum
{    
 // just add or remove registers and your good to go...
 // The first register starts at address 0
 ADC0,    
 ADC1,        
 ADC2,
 ADC3,
 ADC4,
 ADC5,  
 LED_STATE,
 BUTTON_STATE,
 TOTAL_ERRORS,
 // leave this one
 TOTAL_REGS_SIZE
 // total number of registers for function 3 and 16 share the same register array
};

unsigned int holdingRegs[TOTAL_REGS_SIZE]; // function 3 and 16 register array
////////////////////////////////////////////////////////////

void setup()
{
 /* parameters(long baudrate,
               unsigned char ID,
               unsigned char transmit enable pin,
               unsigned int holding registers size,
               unsigned char low latency)
               
    The transmit enable pin is used in half duplex communication to activate a MAX485 or similar
    to deactivate this mode use any value < 2 because 0 & 1 is reserved for Rx & Tx.
    Low latency delays makes the implementation non-standard
    but practically it works with all major modbus master implementations.
 */
 
 modbus_configure(9600, 1, 6, TOTAL_REGS_SIZE, 0);
 pinMode(ledPin, OUTPUT);
 pinMode(buttonPin, INPUT);
 
}

void loop()
{
 // modbus_update() is the only method used in loop(). It returns the total error
 // count since the slave started. You don't have to use it but it's useful
 // for fault finding by the modbus master.
 holdingRegs[TOTAL_ERRORS] = modbus_update(holdingRegs);
 for (byte i = 0; i < 6; i++)
 {
   holdingRegs[i] = analogRead(i);
   delayMicroseconds(50);    
 }
 
 byte buttonState = digitalRead(buttonPin); // read button states
 
 // assign the buttonState value to the holding register
 holdingRegs[BUTTON_STATE] = buttonState;
 
 // read the LED_STATE register value and set the onboard LED high or low with function 16
 byte ledState = holdingRegs[LED_STATE];
 
 if (ledState) // set led
 {  
   digitalWrite(ledPin, HIGH);
 }  
 else if (ledState == 0) // reset led
 {
   //digitalWrite(ledPin, LOW);
   holdingRegs[LED_STATE] = 0;
 }
 
}



Come posso implementarlo per poter leggere i valori dell'Holding Registers dal 400000 al 400200?
Riesco a leggere correttamente i valori impostati su "LED_STATE" e "BUTTON_STATE".
E' sufficiente inserire altri valori dopo l'ultimo "BUTTON_STATE"?

Grazie in anticipo.

ORSO2001

ciao,

mi ricordo che ci siamo già confrontati...ma non ricordo di preciso cos'abbiamo fatto...nel senso...se leggi bene nell'esempio che hai postato c'è scritto:
Quote
In a function 3 request the master will attempt to read from your
  slave and since 5 bytes is already used for ID, FUNCTION, NO OF BYTES
  and two BYTES CRC the master can only request 122 bytes or 61 registers.
non ricordo se avevamo modificato il limite dell'array!? altrimenti devi fare 4 richieste di 50 registri ciascuna.

TedStriker

Ciao ORSO2001,
grazie ancora per la tua risposta.

Si, da quanto ho letto il buffer della seriale di arduino è di 128 byte, quindi non posso andare oltre una 50'ina di registri.

Come posso fare per fare le altre richieste?

ORSO2001

ok...e come vorresti "funzionasse" questo data logger? a tempo? su richiesta (evento)? in polling? e cosa dovrebbe farne dei dati raccolti? salvarli da qualche parte (SD od altro)? semplice analisi?

TedStriker

Ciao ORSO,

essendo solo per studio sul funzionamento, va bene in qualsiasi modalità, credo che il "polling" sia il più semplice.
Per adesso nessuna SD, mi basta vederli sul display.
L'interesse è nato anche perchè i TAG all'origine sono di tipo Float32.

ORSO2001

ciao

aspetta un attimo...forse mi sto confondendo...con questa libreria arduino è uno slave...e devi avere un master che invvi comandi e "valori"...è così o deve essere l'arduino master verso altro dispositivo?

Go Up