Problemi comunicazione MODBUS [RISOLTO]

Ciao a tutti
sono un neofita di Arduino con un pò di esperienza informatica/elettronica e dopo vari sketch ben riusciti mi sto cimentando nella supervisione di un dispositivo via MODBUS e dopo un paio di settimane di test (quasi vani) sono qui a chiedere aiuto!

Ho utilizzato la libreria SimpleModbusMaster per leggere da un dispositivo (id 2) ed ho collegato l'integrato MAX485 come da schema.

http://simple-modbus.googlecode.com/files/SimpleModbusV4.1.zip

Utilizzando l'esempio SimpleModbusMaster ho testato il collegamento e funziona, perchè monitorando la variabile regs[4] (richieste con successo) continua ad incrementare, inoltre il led collegato sull'uscita allarme non si accende (cosa che avviene non appena scollego un filo bus o cambio l'indirizzo del dispositivo slave 485).

La cosa che non riesco a capire è come leggere i valori che lo slave mi dovrebbe mandare indietro! è perchè non è implementata nella libreria o non sono riuscito a capire io cosa fare? Purtroppo le mie nozioni informatiche sono molto arrugginite dopo un decennio di inutilizzo...

Grazie già da ora a tutti!!!

Dentro la libreria trovi le varie funzioni che si occupano della trasmissione ad esempio getData(); e sendPacket(unsigned char bufferSize);

Scusa il ritardo, ero via per alcuni giorni...

Grazie per l'aiuto, solo che non ho ben compreso come utilizzare getData()... essendo una funzione dovrebbe restituirmi un unsigned char, giusto?
Per leggere i pacchetti trasmessi, la devo utilizzare nel loop giusto? perchè se provo ad fare un semplice variabile=getData() mi dice:
"error: 'getData' was not declared in this scope"
Immagino debba tornare a studiare ancora un bel pò, dopo 10 anni i miei ricordi sono scarsi :blush:

Da link da te indicato ho trovato un esempio

#include <SimpleModbusSlave.h>
#define  CE_Pin   8          // Chip Enable 
#define  baudrate 57600
byte ID = 1;

//////////////// registers of your slave ///////////////////
enum 
{     
  // ---- Addres Reg. 0 Lecturas de Valores  
  I,     
  V,        
  E,
  RAD,
  TEMP,
  PvGiro,
  PvEleva,
  VelGiro,
  VelEleva,
  AL1,
  AL2,
  
  // ---- Addres Reg. 11 Escrituras. Parametrso 
  MaxGiroPot,
  LGi,
  LGiC,
  CalibraGiEl,
  LElMaMe,
  LElCMaMe,
  VelGiElminAl,
  ZmGiEl,
  T1,
  T2,
  TEWeb_AngPosSeg,
  
  // ---- Addres Reg. 22 Escrituras. Posicion y Ordenes 
  SV_Giro,
  SV_Eleva,
  FLOrdenes,
  
  // ---- Addres Reg. 25 Escrituras. Fecha y Hora 
  Ano,
  MesDia,
  HoraMin,
  
  TOTAL_ERRORS,
  
  // leave this one
  TOTAL_REGS_SIZE 
  
};

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)
  modbus_configure(115200, ID, CE_Pin, TOTAL_REGS_SIZE);  //No es necesario definir CE_Pin como OutPut, lo hace la libreria    
}


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[I] = millis() / 1000;     
  holdingRegs[V] = 2;        
  holdingRegs[E] = 3;
  holdingRegs[RAD] = 4;
  holdingRegs[TEMP] = 5;
  holdingRegs[PvGiro] = 6;
  holdingRegs[PvEleva] = 7;
  holdingRegs[VelGiro] = 8;
  holdingRegs[VelEleva] = 9;
  holdingRegs[AL1] = 10;
  holdingRegs[AL2] = 11;
  
  //------------//
  holdingRegs[MaxGiroPot] = 12;
  holdingRegs[LGi] = 13;
  holdingRegs[LGiC] = 14;
  holdingRegs[CalibraGiEl] = 15;
  holdingRegs[LElMaMe] = 16;
  holdingRegs[LElCMaMe] = 17;
  holdingRegs[VelGiElminAl] = 18;
  holdingRegs[ZmGiEl] = 19;
  holdingRegs[T1] = 20;
  holdingRegs[T2] = 21;
  holdingRegs[TEWeb_AngPosSeg] = 22;
  
  //------------//
  holdingRegs[SV_Giro] = 23;
  holdingRegs[SV_Eleva] = 24;
  holdingRegs[FLOrdenes] = 25;
  
  //------------//
  holdingRegs[Ano] = 26;
  holdingRegs[MesDia] = 27;
  holdingRegs[HoraMin] = 28;
  
  holdingRegs[TOTAL_ERRORS] = modbus_update(holdingRegs); 
  
  for (byte i = 0; i < 29; i++)
   {
      Serial.print (holdingRegs[i]);
      Serial.print ("/");
    }
  Serial.println (TOTAL_REGS_SIZE);
  delay(1000);
}

forse ti potrebbe chiarire meglio come funziona la libreria.

tapirinho:
.. di un dispositivo via MODBUS e dopo un paio di settimane di test (quasi vani) sono qui a chiedere aiuto!

Mi fa piacere leggere che non sono l'unico..
Anche io sto facendo a pugni con il modbus e per ora vince Lui XD e non ai punti...

perchè hai scelto SimpleModbus e non il ModbusMaster?
Io ho tovato che per compilare ModbusMaster bisogna usare la versione :arduino-1.0 il perchè lo ignoro....

:~ mal comune mezzo Sketch

Luca

Invece dell'IDE 1.0 usate l'1.0.1 corregge alcuni bug presenti nella 1.0
E' probabile che serva la versione 1 invece delle precedenti perché include i file Arduino.h e non il Wprogram.h delle versioni precedenti.

Ma visto che io devo monitorare un dispositivo Modbus, non dovrei usare la libreria Master invece della Slave?

Leggendo più a fondo la libreria, ho visto che funziona così (se sbaglio correggetemi) :

nel loop viene lanciata la funzione modbus_update, la quale inizializza la comunicazione e controlla se va a buon fine
tramite la funzione construct_packet, in base alla funzione richiesta, crea il pacchetto contenente indirizzo, funzione, indirizzo di partenza ecc...
con check_response richiama la funzione check_F3_data (nel caso che mi interessa)
nella funzione check_response memorizza i dati ricevuti in "packet->register_array = (frame[index] << 8 ) | frame[index + 1]; "
quindi io nello sketch esempio dovrei trovare in packet1->register_array[ i ] i valori Holding Register dello Slave. Sempre che il mio ragionamento sia corretto...
Per Illuca: in realtà li ho provati entrambi, solo che con SimpleModbusMaster ho anche un feedback sul funzionamento della comunicazione, e come spiegavo all'inizio mi ha dato subito esito positivo, per cui ho deciso di partire da questa base... :*

ciao,
Nella mia ricerca per ora vana di capire questo protocollo mi sono inbattuto in:
http://www.modbus.pl/node/10
sinceramente :blush: per ora io non ho risultati ma forse può essere di aiuto...

Luca

Se proprio te lo vuoi studiare --> http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf

e questo --> http://www.modbus.org/docs/Modbus_over_serial_line_V1_02.pdf

Ciao Paolo,
grazie per le letture
modificando opportunamenteil codice Slave che hai suggerito con:

 modbus_configure(9500, 1, 2, TOTAL_REGS_SIZE);

per monitorare i dati ho pensato di usare un lcd in questo modo:

#include <SimpleModbusMaster.h>
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 8);
 

// led to indicate that a communication error is present
#define connection_error_led 13

//////////////////// Port information ///////////////////
#define baud 9600
#define timeout 1000
#define polling 200 // the scan rate

// If the packets internal retry register matches
// the set retry count then communication is stopped
// on that packet. To re-enable the packet you must
// set the "connection" variable to true.
#define retry_count 10 

// used to toggle the receive/transmit pin on the driver
#define TxEnablePin 2 

// This is the easiest way to create new packets
// Add as many as you want. TOTAL_NO_OF_PACKETS
// is automatically updated.
enum
{
  PACKET1,
  PACKET2,
  // leave this last entry
  TOTAL_NO_OF_PACKETS
};

// Create an array of Packets for modbus_update()
Packet packets[TOTAL_NO_OF_PACKETS];

// Create a packetPointer to access each packet
// individually. This is not required you can access
// the array explicitly. E.g. packets[PACKET1].id = 2;
// This does become tedious though...
packetPointer packet1 = &packets[PACKET1];


// The data from the PLC will be stored
// in the regs array
unsigned int regs[9];

void setup()
{
   
  lcd.begin(16, 2);
  
  
  
  
  // read 3 registers starting at address 1
  packet1->id = 2;
  packet1->function = READ_HOLDING_REGISTERS;
  packet1->address = 1;
  packet1->no_of_registers = 3;
  packet1->register_array = regs;
  
 
  
  // P.S. the register_array entries above can be different arrays
  
  // Initialize communication settings etc...
  modbus_configure(baud, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS);
  
  pinMode(connection_error_led, OUTPUT);
}

void loop()
{
  unsigned int connection_status = modbus_update(packets);
  
  if (connection_status != TOTAL_NO_OF_PACKETS)
  {
    digitalWrite(connection_error_led, HIGH);
    // You could re-enable the connection by:
    //packets[connection_status].connection = true;
    lcd.print("errore ricezione");
  }
  else
    digitalWrite(connection_error_led, LOW);
  lcd.print("Dati ricevuti");
  // update the array with the counter data
  regs[3] = packet1->requests;
  regs[4] = packet1->successful_requests;
  regs[5] = packet1->total_errors;
 // lcd.setCursor(0, 1);
  // vorrei vedere qualche dato:
 // lcd.print("qualche dato???");
}

indovina cosa mi apapre sull' lcd ???

errore ricezione

hai idea quale sia l' errore?

Luca

Hai messo 9500 al posto di 9600. :sweat_smile:

=( GRAZIE ! :blush:

Purtroppo era solo un errore nel postare il codice.

ma come faccio a vedere

packet1->function = READ_HOLDING_REGISTERS;

sul master per poi visualizzarlo
sulla seconda riga del lcd

lcd.setCursor(0, 1);
// vorrei vedere qualche dato:
lcd.print(??? );

Grazie

Luca

Finalmente ho avuto risultati!
In effetti utilizzando la libreria SimpleModbusMaster sono finalmente riuscito a leggere quelle 3 variabili che mi servono!

X Luca: i risultati li trovi già nell'array regs. Funzionava già da subito, solo che io andavo a leggere gli indirizzi sbagliati!!! :blush:

Buongiorno a tutti,

anch'io sto cercando di comunicare in Modbus con un PowerMeter ma non riesco a capire come funziona la classe messa a disposizione.
In pratica io dovrei mandare allo strumento :
Device Addr : 0x01
Function : 0x03
MSB 1 Word Addr : 0x03
LSB 1 Word Addr : 0x25
Words number MSB: 0x00
Words number LSB: 0x04
CRC 16 MSB: 0x55
CRC 16 LSB: 0x86

Grazie ragazzi.