A Forum run by Enthusiasts of MidNite Solar

The Open Source software/hardware corner => Arduino => Topic started by: dgd on February 05, 2015, 03:48:23 AM

Title: rs232 modbus to Classic
Post by: dgd on February 05, 2015, 03:48:23 AM
Some info on connecting an UNO to a Classic via rs232 modbus
Using a low cost UNO, rs232 shield and LCD 16by2 disply shield (with small keyboard) all up cost under $25, the only part that had to be made was a cable rj11 to DB9 plug. Connected to Classic middle rj11 socket MNGP/SLAVE.
The software library Simplemodbusmaster was used. The example program (sketch) provided with the lib is well detailed and and excellent explantionof how it all works. It supports the most common Modbus commands
Only a few software changes were made to get it working with a Classic.
I initially only wanted to read the four registers 4114, battery voltage, to 4117 (see Midnite Modbus register list)
So the only changes made were:

#define baud 19200
#define timeout 1000
#define polling 200 // the scan rate

// array for register values read from Classic
unsigned int readRegs[5];

..in the setup()
  modbus_construct(packet1, 10, READ_HOLDING_REGISTERS, 4114, 4, readRegs);
  modbus_configure(&Serial, baud, SERIAL_8N1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS);

and that was all  :)

..in loop()
the  modbus_update()
does the communications in the background.
This command is repeated in loop(), I inserted a delay(200) to let the LCD update at a readable rate

I can provide the full sketch with LCD  displaying of the modbus values if anyone wants it.

dgd



Title: Re: rs232 modbus to Classic
Post by: cabinrob on February 05, 2015, 04:57:36 PM
This sounds almost exactly like the project I was going to start planning!
I would love to get a copy of your sketch!
Have you considered an Ethernet shield to enable web access?
rob
Title: Re: rs232 modbus to Classic
Post by: mtdoc on February 05, 2015, 06:08:10 PM
Quote from: dgd on February 05, 2015, 03:48:23 AM

I can provide the full sketch with LCD  displaying of the modbus values if anyone wants it.


Yes, please!
Title: Re: rs232 modbus to Classics
Post by: dgd on February 06, 2015, 08:06:30 AM
Ok, a couple of days playing with this and it's getting nicely complicated and more useful  8)
Reading via rs232 modbus 20 registers from 4114 battery voltage up to the one that has FET temp
The 2 line by 16 char blue lcd now has four 2-line pages scrollable up and down using the up and down keypad buttons.
Showing charging state, battery volts and amps, watts and Kwhrs, PV volts and PV max volts, pcb and FET temps.

This is using the normal size UNO, rs232 shield and 1602 blue lcd with 5 key keypad shield.
I have a few Lites out at different sites so I'm intending to nicely box up these parts with a dc to dc converter to power it although it seems the 9volts available on the Middle serial rj12 in the Classic could power it. Then get one on each lite.
I had considered upgrading the Lites with MNGPs but the sites with classics have more support problems because locals want to fiddle with buttons and mngp display.
There is nothing worse than a 6 hour round trip to find some idiot has unintentionally turned off the charging mode.
At least with this UNO display there is no fatal keystrokes, even pressing the rest button only resets the UNO  :)
Dgd
Title: Re: rs232 modbus to Classic
Post by: dgd on February 06, 2015, 04:36:34 PM
Sketch below, sorry I could not get a server without paying $ or giving away all my personal details, to upload this too.
It seems to fit in one posting.
Its more documentation than code but is a work in progress.
Anyhow it works for me, despite lack of printf (formatted print) and all those tiresome print instructions
Remember you will need to google SimpleModbusMaster and load the library to your PC that you do Arduino development on.

dgd


#include <LiquidCrystal.h>

#include <SimpleModbusMaster.h>

// Connect Uno  via rs232 shield to Midnite Classic's rj11 MNGP/Slave rs232 port.
// uses Modbus RTU to retrieve modbus registers. UNO is master, Classic is slave.
// David Dix Jan 2015, dgd@kc.net.nz

/*
   SimpleModbusMaster allows you to communicate
   to any slave using the Modbus RTU protocol.
 
   To communicate with a slave you need to create a packet that will contain
   all the information required to communicate to the slave.
   Information counters are implemented for further diagnostic.
   These are variables already implemented in a packet.
   You can set and clear these variables as needed.
   
   The following modbus information counters are implemented:   
   
   requests - contains the total requests to a slave
   successful_requests - contains the total successful requests
   failed_requests - general frame errors, checksum failures and buffer failures
   retries - contains the number of retries
   exception_errors - contains the specific modbus exception response count
   These are normally illegal function, illegal address, illegal data value
   or a miscellaneous error response.
 
   And finally there is a variable called "connection" that
   at any given moment contains the current connection
   status of the packet. If true then the connection is
   active. If false then communication will be stopped
   on this packet until the programmer sets the connection
   variable to true explicitly. The reason for this is
   because of the time out involved in modbus communication.
   Each faulty slave that's not communicating will slow down
   communication on the line with the time out value. E.g.
   Using a time out of 1500ms, if you have 10 slaves and 9 of them
   stops communicating the latency burden placed on communication
   will be 1500ms * 9 = 13,5 seconds! 
   Communication will automatically be stopped after the retry count expires
   on each specific packet.
 
   All the error checking, updating and communication multitasking
   takes place in the background.
 
   In general to communicate with to a slave using modbus
   RTU you will request information using the specific
   slave id, the function request, the starting address
   and lastly the data to request.
   Function 1, 2, 3, 4, 15 & 16 are supported. In addition to
   this broadcasting (id = 0) is supported for function 15 & 16.

   Constants are provided for:
   Function 1  - READ_COIL_STATUS
   Function 2  - READ_INPUT_STATUS
   Function 3  - READ_HOLDING_REGISTERS
   Function 4  - READ_INPUT_REGISTERS
   Function 15 - FORCE_MULTIPLE_COILS
   Function 16 - PRESET_MULTIPLE_REGISTERS
   
   Note: 
   The Arduino serial ring buffer is 128 bytes or 64 registers.
   Most of the time you will connect the Arduino using a MAX485 or similar.

   In a function 3 or 4 request the master will attempt to read from a
   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 a
   slave and since 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.
   
   Note:
   Using a USB to Serial converter the maximum bytes you can send is
   limited to its internal buffer which differs between manufactures.

   Since it is assumed that you will mostly use the Arduino to connect without
   using a USB to Serial converter the internal buffer is set the same as the
   Arduino Serial ring buffer which is 128 bytes.
   
   The example will use packet1 to read a register from address 0 (the adc ch0 value)
   from the arduino slave. It will then use this value to adjust the brightness
   of an led on pin 9 using PWM.
   It will then use packet2 to write a register (its own adc ch0 value) to address 1
   on the arduino slave adjusting the brightness of an led on pin 9 using PWM.
*/

// number of two line LCD display pages
#define HIGH_PAGE 3

//////////////////// Port information ///////////////////
#define baud 19200
#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

#define LED 9

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

// Create an array of Packets to be configured
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];
// packetPointer packet2 = &packets[PACKET2];

// Data read from the arduino slave will be stored in this array
// if the array is initialized to the packet.
unsigned int readRegs[21];

// Data to be written to the arduino slave
// unsigned int writeRegs[1];

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

int page=0;  // display page on LCD
// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

void setup()
{
  lcd.begin (16,2);
 
  // setup LCD display
 
  // The modbus packet constructor function will initialize
  // the individual packet with the assigned parameters. You can always do this
  // explicitly by using struct pointers. The first parameter is the address of the
  // packet in question. It is effectively the "this" parameter in Java that points to
  // the address of the passed object. It has the following form:
  // modbus_construct(packet, id, function, address, data, register array)
 
  // For functions 1 & 2 data is the number of points
  // For functions 3, 4 & 16 data is the number of registers
  // For function 15 data is the number of coils
 
  // read 20 register starting at address 4114 
  modbus_construct(packet1, 10, READ_HOLDING_REGISTERS, 4114, 20, readRegs);
 
  // write 1 register starting at address 1 
//  modbus_construct(packet2, 2, PRESET_MULTIPLE_REGISTERS, 1, 1, writeRegs);
 
  // P.S. the register array entries above can be different arrays
 
  /* Initialize communication settings:
     parameters(HardwareSerial* SerialPort,
long baud,
unsigned char byteFormat,
unsigned int timeout,
unsigned int polling,
unsigned char retry_count,
unsigned char TxEnablePin,
Packet* packets,
unsigned int total_no_of_packets);

     Valid modbus byte formats are:
     SERIAL_8N2: 1 start bit, 8 data bits, 2 stop bits
     SERIAL_8E1: 1 start bit, 8 data bits, 1 Even parity bit, 1 stop bit
     SERIAL_8O1: 1 start bit, 8 data bits, 1 Odd parity bit, 1 stop bit
     
     You can obviously use SERIAL_8N1 but this does not adhere to the
     Modbus specifications. That said, I have tested the SERIAL_8N1 option
     on various commercial masters and slaves that were suppose to adhere
     to this specification and was always able to communicate... Go figure.
     
     These are already defined in the Arduino global name space.
  */
  modbus_configure(&Serial, baud, SERIAL_8N1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS);
 
// pinMode(LED, OUTPUT);
}

void loop()
{
 
  float batt_volts, in_volts, batt_amps, kwh, high_in_volts;
  int state, watts;
  float fet_temp, pcb_temp;

  // read the Classic's modbus registers
  modbus_update();
 
// writeRegs[0] = analogRead(A0); // update data to be written to arduino slave
 
// analogWrite(LED, readRegs[0]>>2); // constrain adc value from the arduino slave to 255
 
  /* You can check or alter the internal counters of a specific packet like this:
     packet1->requests;
     packet1->successful_requests;
     packet1->failed_requests;
     packet1->exception_errors;
     packet2->requests;
     packet2->successful_requests;
     packet2->failed_requests;
     packet2->exception_errors;
  */
 
  // make Classic register values ready for LCD
     batt_volts = readRegs[0];
     batt_volts /=10;
     in_volts = readRegs[1];
     in_volts /=10;
     batt_amps = readRegs[2];
     batt_amps /=10;
     kwh= readRegs[3];
     kwh /=10;
     watts = readRegs[4];
     state = (unsigned int)readRegs[5] >> 8;  // high byte contains charge state code
     high_in_volts = readRegs[8];
     high_in_volts /=10;
     pcb_temp = readRegs[18];
     pcb_temp /=10;
     fet_temp = readRegs[19];
     fet_temp /=10;

     // top line of lcd
     lcd.setCursor(0,0);
     if (page==0)         // first page of 2 lines on LCD displays Clssic state on top
     {                    // line and battery voltage and current on second line
      switch (state) {
       case 0:
          lcd.print ("Resting  ");
          break;
       case 3:
          lcd.print ("Absorb   ");
          break;
       case 4:
          lcd.print ("BulkMppt ");
         break;
       case 5:
          lcd.print ("Float    ");
          break;
       case 6:
          lcd.print ("FloatMppt");
          break;
       case 7:
          lcd.print ("Equalize ");
          break;
       case 10:
          lcd.print ("HyperVoc ");
          break;
       case 18:
          lcd.print ("EqMppt   ");
          break;
      }
     

     // second line of page 0
     
     lcd.setCursor(0,1);
     lcd.print("Batt ");
     lcd.print(batt_volts);
     lcd.setCursor(9,1);
     lcd.print("v ");
     lcd.print(batt_amps);
     if (batt_amps < 10)  // dont want that extra zero
     {
       lcd.setCursor(14,1);
       lcd.print ("a ");
     }
     else
     {
        lcd.setCursor(15,1);
        lcd.print ("a");
     }
   } // end of page 0
   
   if (page==1)           // second page of two LCD lines shows Watts on first line and
   {                      // Energy Kw/hrs on second line
     lcd.setCursor(0,0);
     lcd.print ("Watts ");
     lcd.print(watts);

     lcd.setCursor(0,1);
     lcd.print("KwHrs ");
     lcd.print(kwh);
   } // end of page 1
   
   if (page == 2)         // third page of two LCD lines shows PV input voltage on first line
   {                      // and PV in max voltage on second lione   
     lcd.setCursor(0,0);
     lcd.print("PV input ");
     lcd.print(in_volts);
     if (in_volts > 99.9)
     lcd.setCursor(14,0);
     else
     lcd.setCursor(13,0);
     lcd.print("v ");
     
     lcd.setCursor(0,1);
     lcd.print("PV max   ");
     lcd.print(high_in_volts);
     if (high_in_volts > 99.9)
     {
       lcd.setCursor(14,1);
       lcd.print ("v ");
     }
     else
     {
       lcd.setCursor(13,1);
       lcd.print("v  ");
     }
   }  // end page 2
   
   if (page == 3)         // fourth page of two LCD lines has PCB temp on top line and FET
   {                      // temp on second line
     lcd.setCursor(0,0);
     lcd.print("Temps  PCB ");
     lcd.print (pcb_temp);   
     lcd.setCursor(0,1);
     lcd.print("       FET ");
     lcd.print (fet_temp);

   }   // end page 3
   
// check if keypad button pressed - presently only looking for UP and DOWN keys to scroll
// up/down beween disply pages, further pages on way...

lcd_key = read_LCD_buttons();  // read the buttons

switch (lcd_key)               // depending on which button was pushed, we perform an action
{
   case btnRIGHT:
     {
     break;
     }
   case btnLEFT:
     {
     break;
     }
   case btnUP:
     {
     if (page == 0) page = HIGH_PAGE;
     else page -= 1;
     lcd.clear();
     break;
     }
   case btnDOWN:
     {
     if (page >= HIGH_PAGE) page=0;
     else page += 1;
     lcd.clear();
     break;
     }
   case btnSELECT:
     {
     break;
     }
     case btnNONE:
     {
     break;
     }
}


// delay to stop LCD flickering, refreshes display 300ms
  delay(300);
 
}

// read the buttons
int read_LCD_buttons()
{
adc_key_in = analogRead(0);      // read the value from the sensor
// my buttons when read are centered at these valies: 0, 144, 329, 504, 741
// we add approx 50 to those values and check to see if we are close
if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
// For V1.1 us this threshold
if (adc_key_in < 50)   return btnRIGHT; 
if (adc_key_in < 250)  return btnUP;
if (adc_key_in < 450)  return btnDOWN;
if (adc_key_in < 650)  return btnLEFT;
if (adc_key_in < 850)  return btnSELECT; 

// For V1.0 comment the other threshold and use the one below:
/*
if (adc_key_in < 50)   return btnRIGHT; 
if (adc_key_in < 195)  return btnUP;
if (adc_key_in < 380)  return btnDOWN;
if (adc_key_in < 555)  return btnLEFT;
if (adc_key_in < 790)  return btnSELECT;   
*/
return btnNONE;  // when all others fail, return this...
}

Title: Re: rs232 modbus to Classic
Post by: dgd on February 06, 2015, 05:23:19 PM
At one of my Classic Lite locations I need to control a vent fan, a night light and I would like to have an additional small cooling fan that directs airflow around the back of aluminum plate that has the Classic and another item surface mounted on it. The plate is on 1 inch standoffs attached to a cement block wall.
The Lite has a WbJr so only AUX1 is left

Now with the UNO attached there are many available digital and analogue control outputs. So one update I plan to make is connect some of the UNO digital outputs to this 8 port relay control board.
It uses Omron 240v 50/60Hz 2amp relays as I want to use two CFL night lights, AC vent fan and AC boxer cooling fan.

dgd
Title: Re: rs232 modbus to Classic
Post by: mtdoc on February 06, 2015, 06:19:02 PM
Most excellent dgd. Thank you!

I happen to have a few 'duinos sitting around and also the same LCD and RS232 shields you used.

I've been working on other non PV system related electronics projects but  have been meaning to get back to some things useful to my PV system.  This is just the ticket to get me back to it. 
Title: Re: rs232 modbus to Classic
Post by: dgd on February 06, 2015, 07:01:57 PM
Quote from: cabinrob on February 05, 2015, 04:57:36 PM
This sounds almost exactly like the project I was going to start planning!
I would love to get a copy of your sketch!
Have you considered an Ethernet shield to enable web access?
rob

I'm working on this now using a W5100 based ethernet shield with micro SD card storage.  I can get the web server working and taking data via rs232 modbus from Classic.
Or more exactly, I'm storing a log of data from the Classic on an SD card. The only web page I'm playing with now is a text type lookalike of an early MN designed page that showed a page of about 20 entries in a table of voltages, amps,kwhr, flags etc (node 10 page I think it was called).  Each line of data was on a 10 minute interval.
MN did not use this text table display page when MyMidnite was released.

It does not appear to be that difficult to store a graphical web page frame on SD then dynamically serve a page with Classic running values in it. I'm thinking of a 'skin' type design that refreshed often enough to be useful.

dgd
Title: Re: rs232 modbus to Classic
Post by: dgd on February 06, 2015, 07:07:31 PM
Mtdoc,
I hope you can copy and paste the sketch.
Let me know if you get it going and of course any code improvement changes/additions would be very welcome  :)
dgd
Title: Re: rs232 modbus to Classic
Post by: mtdoc on February 06, 2015, 08:22:11 PM
Yes, I'll let you know. It will be a few weeks before I can really dig in to this. I'll need to make the cable. If I get it working well, I plan to interface it with LabView using the LabView Interface For Arduino toolkit and get a GUI going on my system monitoring computer.  I've wanted to do this for a while but hadn't had the time to learn Modbus so that I could brew my own solution. It looks like this will let me bypass that step and get my lazy butt going on it!

Thanks again dgd!
Title: Re: rs232 modbus to Classic
Post by: cabinrob on February 06, 2015, 08:30:38 PM
dgd,

Thanks for posting the sketch.
Let us know how the Ethernet connection turns out.
You're many steps ahead of me - given that I haven't even taken delivery of my Classic yet - but hopefully I'll be able to contribute once I've got some hardware on my bench.
What I don't get, is why Midnite Solar isn't doing something similar?  They could even sell an Arduino based system in a nice box + some software and we would be all good to go.
Title: Re: rs232 modbus to Classic
Post by: xsnrg on February 06, 2015, 08:34:17 PM
dgd, nice work!  It is a lot of fun seeing what people can think to do with all the "little boards that can" that are floating around now.
Title: Re: rs232 modbus to Classic
Post by: dgd on February 06, 2015, 10:12:44 PM
Quote from: xsnrg on February 06, 2015, 08:34:17 PM
dgd, nice work!  It is a lot of fun seeing what people can think to do with all the "little boards that can" that are floating around now.

Yes it is, I must admit I'm still surprised by how versatile and capable the arduino stuff is.
This little project is so dead easy that anyone could do it (and should!), the only issue is making or have made a suitable cable.
The three cards are cheap on EBay and simply plug together.
ALthough I intended it for a Classic Lite it will also be useful with a normal Classic to at least provide many more AUX outputs.
The Arduino UNO even has several PWM outputs so will be capable of PWM controlling an SSR for water heating (or similar)

I can think of many more uses for this with the Classic.
The grail will definitely be a proper web server for the Classic, that should not be too far away.

dgd
Title: Re: rs232 modbus to Classic
Post by: dgd on February 07, 2015, 01:13:21 AM
a sketch update
to power off the LCD backlight after no keypad activity for about 1 minute. Make LCDOFF_TIME larger for a longer delay
Any key pressed activates backlight
dgd

---
a new define
#define LCDOFF_TIME 200
and two new global variables
int lcdoff_counter = 0;
int lcdoff = 0;

code to insert after the line with
lcd_key = read_LCD_buttons();  // read the buttons
in the loop() routine

// lcd backlight on/off control timeout

if (lcd_key == btnNONE)
{
   if (lcdoff_counter++ >= LCDOFF_TIME)
   {
     pinMode(10, OUTPUT);
     digitalWrite(10,LOW);   // pin 10 in output low turns off lcd backlight
     lcdoff=1;
     lcdoff_counter--;
   }
}
else
{
   lcdoff_counter = 0;
   if (lcdoff)
   {
      pinMode(10, INPUT_PULLUP);  // pin 10 input pulled high turns on backlight
      lcd_key = btnNONE;               // so keypress only activates backlight
    }
   lcdoff = 0;
}

Title: Re: rs232 modbus to Classic
Post by: mtdoc on February 09, 2015, 05:12:33 PM
Hi dgd,

I had a few free moments last night so I  plugged your code into the Arduino IDE last night - but it wouldn't compile. It looks like there's an issue with your  packet array and pointer type definitions. I'm a C newbie so it would take me some time to figure out how to best to fix it - but since it's your code, I thought I'd throw it your way first.  Or maybe I goofed  with my cut and paste?  Have you tried to compile the code exactly as you posted it here?

Thanks for your work on this!
Title: Re: rs232 modbus to Classic
Post by: dgd on February 09, 2015, 06:12:25 PM
Yes it compiles clean. You have installed the SimpleModbusMaster library? And you are using ide 1.5.8
When I upload executable to the uno I seperate it from other shields as it gets the not synced error because the USB port get confused with the rs232 port.

Dgd
Title: Re: rs232 modbus to Classic
Post by: mtdoc on February 09, 2015, 11:37:44 PM
Well I did have a old version of the Arduino IDE so I upgraded to the newest version 1.6 but still no go.

Here is the error message:
Quote
Arduino: 1.6.0 (Windows 7), Board: "Arduino Uno"

Build options changed, rebuilding all

Using library LiquidCrystal in folder: C:\Program Files (x86)\Arduino\libraries\LiquidCrystal

Using library Simplemodbusmaster in folder: C:\Users\jmp\Documents\Arduino\libraries\Simplemodbusmaster (legacy)



C:\Program Files (x86)\Arduino/hardware/tools/avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10600 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\standard -IC:\Program Files (x86)\Arduino\libraries\LiquidCrystal\src -IC:\Users\jmp\Documents\Arduino\libraries\Simplemodbusmaster C:\Users\jmp\AppData\Local\Temp\build8728361313426657017.tmp\sketch_feb09a.cpp -o C:\Users\jmp\AppData\Local\Temp\build8728361313426657017.tmp\sketch_feb09a.cpp.o

sketch_feb09a.ino:126:1: error: 'packetPointer' does not name a type
sketch_feb09a.ino: In function 'void setup()':
sketch_feb09a.ino:173:20: error: 'packet1' was not declared in this scope
sketch_feb09a.ino:203:119: error: too few arguments to function 'void modbus_configure(HardwareSerial*, long int, unsigned char, long int, long int, unsigned char, unsigned char, Packet*, unsigned int, unsigned int*)'
In file included from sketch_feb09a.ino:4:0:
C:\Users\jmp\Documents\Arduino\libraries\Simplemodbusmaster/SimpleModbusMaster.h:134:6: note: declared here
void modbus_configure(HardwareSerial* SerialPort,

      ^
sketch_feb09a.ino: In function 'void loop()':
sketch_feb09a.ino:332:6: error: expected '}' before 'else'
Error compiling.

Thanks again for the help.
Title: Re: rs232 modbus to Classic
Post by: dgd on February 10, 2015, 01:47:01 AM
Mtdoc,

I don't understand how you are compiling the sketch.
On my Win8 laptop I have installed the Arduino ide window system (or whatever it is called) and I never see any c:\ prompt for compiling.
The packet and packetpointer data types are defined in SimpleModbusMaster.h
See the screenshot below.
I just pressed the verify key which compiles the sketch and the results are at bottom of the window

dgd
Title: Re: rs232 modbus to Classic
Post by: mtdoc on February 10, 2015, 01:59:42 AM
I'm doing the same as you. The error text i posted is what shows up in the Arduino IDE lower message box after i push the verify button and it fails to compile. Perhaps it's an issue with the simplemodbuslibrary I'm using?  I'll look into it more tomorrow.
Title: Re: rs232 modbus to Classic
Post by: dgd on February 10, 2015, 02:03:55 AM
Ok, When you look at the examples directory do you see the simplemodbusmaster example?
I simply copied and modifies that example as a start to my sketch and that is where the packetpointer variables were created and defined

dgd
Title: Re: rs232 modbus to Classic
Post by: mtdoc on February 10, 2015, 02:28:30 AM
Thanks for the quick reply! I'm not at my computer now (ipad). It's late here (yawn..) so i'll get back to you tomorrow once i have a chance to check some things.
Title: Re: rs232 modbus to Classic
Post by: mtdoc on February 10, 2015, 02:42:42 PM
dgd,

I've looked in both the SimpleModbusMaster.h library file and also in the SimpleModbusMasterArduino example (which compiles fine).

I see some packet definitions but no packetpointer.

I'm using V2r2 of SimpleModbusMaster.h   Is that the same version you are using?
Title: Re: rs232 modbus to Classic
Post by: dgd on February 10, 2015, 06:20:49 PM
My example sketch has packet pointer in it.
I'm not home right now so can't look at version, have a look for a later version

Dgd
Title: Re: rs232 modbus to Classic
Post by: mtdoc on February 13, 2015, 09:17:49 PM
dgd - have you had a chance to look at the version of SimpleModbusmaster library you're running?

Below is the code from the SimpleModbusMaster example which compiles fine for me. I don't see the "packetPointer" from line 126 of your code defined there or in the library. That is were the compiler seems to be first hanging up.

#include <SimpleModbusMaster.h>

/*
   The example will use packet1 to read a register from address 0 (the adc ch0 value)
   from the arduino slave (id=1). It will then use this value to adjust the brightness
   of an led on pin 9 using PWM.
   It will then use packet2 to write a register (its own adc ch0 value) to address 1
   on the arduino slave (id=1) adjusting the brightness of an led on pin 9 using PWM.
*/

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

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

#define LED 9

// The total amount of available memory on the master to store data
#define TOTAL_NO_OF_REGISTERS 1

// 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,
  TOTAL_NO_OF_PACKETS // leave this last entry
};

// Create an array of Packets to be configured
Packet packets[TOTAL_NO_OF_PACKETS];

// Masters register array
unsigned int regs[TOTAL_NO_OF_REGISTERS];

void setup()
{
  // Initialize each packet
  modbus_construct(&packets[PACKET1], 1, READ_HOLDING_REGISTERS, 0, 1, 0);
  modbus_construct(&packets[PACKET2], 1, PRESET_MULTIPLE_REGISTERS, 1, 1, 0);
 
  // Initialize the Modbus Finite State Machine
  modbus_configure(&Serial, baud, SERIAL_8N2, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs);
 
  pinMode(LED, OUTPUT);
}

void loop()
{
  modbus_update();
 
  regs[0] = analogRead(0); // update data to be written to arduino slave
 
  analogWrite(LED, regs[0]>>2); // constrain adc value from the arduino slave to 255
}
Title: Re: rs232 modbus to Classic
Post by: dgd on February 13, 2015, 10:38:01 PM
The simple modbus master zip file I downloaded is called

SimpleModbusMasterV2rev2_DUE.zip

and is 20.4k in size

dgd
Title: Re: rs232 modbus to Classic
Post by: mtdoc on February 14, 2015, 01:03:44 AM
Quote from: dgd on February 13, 2015, 10:38:01 PM
The simple modbus master zip file I downloaded is called

SimpleModbusMasterV2rev2_DUE.zip

and is 20.4k in size

dgd

Well, still not working.

I was using the non DUE version so I downloaded and tried the DUE version.

I downloaded both from the google drive files referenced from THIS (https://code.google.com/p/simple-modbus/) google code site which is what comes up in a google search.

To use the DUE version I had to change the first line in your code from  #include <SimpleModbusMaster.h>  to # include SimpleModbusMaster_DUE.h  (for obvious reasons) - but still the same failure to compile with the same errors as I listed in my previous post.

I'm not sure what the issue is - there must be a difference between the code you have running and what I copied and pasted from your earlier posts here (which I've done over a few times just to be sure).

Is there any chance you can open your running Arduino sketch and copy and paste the code directly to a post here again?  Maybe the SimpleModbusMaster.h file as well?  There must be a difference in there someplace.

Had anyone else been able to get this to compile?

Thanks again dgd. It's awesone that you're working on and sharing this stuff.

BTW you can use the inert code function ( the button with the # sign on it brings it up) to put the code in a scrollable box like this
Title: Re: rs232 modbus to Classic
Post by: dgd on February 14, 2015, 01:16:43 AM
I am at a complete loss to understand what is happening with your attemps to compile this.
Forget my code and just load the example program supplied with the SimpleModbusMaster library
Does it compile cleanly?
Look in the example code and you should see a line that is

packetPointer  packet1 = &packets[PACKET1]

This means that a pointer called packet1 is pointing to the address of the PACKET1 element of the packets array and the pointer packet1 is of the type packetPointer.
packetPointer is a datatype that is part of the library file SimpleModbusMaster.h
if you do not have the above line in your example program then probably try v10 library.

If you cannot compile the example program they supply then there is a problem with your library (or environment or something else)

Also I did download v10 of the library but I downloaded the v22 shortly after. Maybe I actually have v10 so maybe you could try downloading that version too, if you cannot find the packetPointer data type defined in you .h file

Last, if you look in the arduino forum you will find lots of stuff about SimpleModbusMaster and Slave and I see the packetpointer line in all the examples they quote.

Do you get the same error when trying to compile my SImple webserver code?

dgd
Title: Re: rs232 modbus to Classic
Post by: mtdoc on February 14, 2015, 01:29:32 AM
Quote from: dgd on February 14, 2015, 01:16:43 AM
I am at a complete loss to understand what is happening with your attemps to compile this.

Me too! :(

Quote
Forget my code and just load the example program supplied with the SimpleModbusMaster library
Does it compile cleanly?

Yes, it does

QuoteLook in the example code and you should see a line that is

packetPointer  packet1 = &packets[PACKET1]

No that line is not in the example code. What line are you seeing it?

Quote
This means that a pointer called packet1 is pointing to the address of the PACKET1 element of the packets array and the pointer packet1 is of the type packetPointer.
packetPointer is a datatype that is part of the library file SimpleModbusMaster.h
if you do not have the above line in your example program then probably try v10 library.

I just replied to your other thread about the same issue. The v22 SimpleModbusMaster.h library I have does not have a packetPointer definition in it.

I'll look at the  v10 library.

Title: Re: rs232 modbus to Classic
Post by: mtdoc on February 14, 2015, 01:51:17 AM
Success!

That was the issue. The V22 library does not have that packetPointer definition but the V12 library does! (there was no V10 library that I could find on that google drive site).

I did have to add one } before else on line 326 of your original posted code - otherwise it compiled cleanly.

OK - now that it compiles I just need to make a cable and hook up some hardware!

Thanks again.
Title: Re: rs232 modbus to Classic
Post by: dgd on February 14, 2015, 01:56:48 AM
thats good, look forward to seeing a pic of your lcd display  :)

dgd
Title: Re: rs232 modbus to Classic
Post by: WillEert on July 21, 2015, 01:38:54 PM
       Well I have built this system and tried to run it using the lower Classic RJ11 port. The code worked great in that the lcd display worked well however I did not get a connection to the Classic and see Classic data. I suspected my pinout on the cable or a bad connection and spent some time looking at that however the cable did not seem to be the problem. I changed the pinout to allow use of the middle port and everything worked very well. The code worked great and the LCD display was very nice. I saw the Classic data and it updated nicely. I changed the pinout back to the lower port and once again I did not see the Classic. Does anyone know what might be different about the lower RJ11 port? Might it not access the registers that the upper 2 ports do? Possibly a different address or something? Possibly one of the different wires that I use due to the different pinout is damaged. I would like to use the lower port my diversion control as I am using the middle port for my MNGP remote which I enjoy looking at wile I am in my kitchen. I guess that I could have the arduino display as a remote and do the diversion control however I would prefer not to have to take that route.

Thanks

Will
Title: Re: rs232 modbus to Classic
Post by: dgd on July 21, 2015, 09:25:52 PM
Hi Will,
I never tried the third (lower) rj11 port but I did note the only difference is the RX and TX are reversed.
Does the remote MNGP work when plugged into the third  rj11?
I seem to remember reading somewhere  it would work in either port so maybe it auto detects which is TX and RX.
dgd
Title: Re: rs232 modbus to Classic
Post by: WillEert on July 22, 2015, 08:39:57 AM
HI djd,

I tried the remote in the lower port. It did not work. I could not figure out how it would work because as you say the TX and RX wires are reversed. I do not know about auto detection but it would need to have something like that. Also it has no +9v power which I would guess the MNGP needs to work. Since this port is the second half of the follow me system the pinout of the lower port makes sense in that it is the reverse of the middle port. I know my pin 3 and 4 wires are good because they worked when I used the middle port. Maybe my pin 2 wire a has a problem preventing a ground connection which would stop the RS232 system from working.

Will
Title: Re: rs232 modbus to Classic
Post by: WillEert on July 22, 2015, 10:30:41 AM
Continuing the thought of the lower port being primarily a follow me port maybe it will not work unless follow me is enabled?

Will
Title: Re: rs232 modbus to Classic
Post by: WillEert on July 22, 2015, 09:32:48 PM
Managed to get the Uno via rs232 to Classic system to work on the lower RJ11 port. Yay! I had to reverse the RX and TX pins from what the drawing in the Modbus Network Spec suggested it should be. So for me GND is pin 2, RX is pin 3 and TX is pin 4 on the lower RJ11 port.

Will
Title: Re: rs232 modbus to Classic
Post by: dgd on July 22, 2015, 09:55:02 PM
Excellent. Just another of those little documentation errors placed there to test your resolve. Its surprising nobody found this before  :o

dgd
Title: Re: rs232 modbus to Classic
Post by: dgd on July 23, 2015, 07:53:47 PM
Will,
The use of the lower rj11 serial port has me thinking now that a second Arduino could be connected to a Classic.
So rather than have the one Mega or DUE being a web server AND controlling other devices it may a better design to keep the web server just web serving and therefore fast on 1 second modbus reads - then use an UNO on the lower port to manage water heating - PWMing relays etc. It could probably also talk to the web server to provide info on how the water heating is progressing
LCD display on UNO optional   :)

dgd
Title: Re: rs232 modbus to Classic
Post by: WillEert on August 04, 2015, 04:01:04 PM
Hi dgd

I like the idea of using both of the available RJ11 ports on the Classic. Since the arduino does not really do two things at once very well your idea  really makes sense.

Will 
Title: Re: rs232 modbus to Classic
Post by: WillEert on August 04, 2015, 04:24:49 PM
A tale of woe about a nubies attempts to learn about RS232 communication with the Classic.

        I want to write to the Classics 4148 register Battery output Current Limit so I configured, using the SimpleModbusMaster library example as a template, what I thought should work. I was in doubt about the meaning of the last line of code which actually writes to the register however I put the value that I wanted the register to take in the () replacing the AO in the example. The first time I tried the Classic was not happy. It went to mode off and offered the error - battery overvoltage. I reset it after some head scratching and got it going again. One thing I had done was I did not multiply the PV *10 so although I put in 65 in the packet the Classic of course saw 6.5. It took this value but s/d. I had to reload most of its parameters to get it to go again. I do not have an unlimited supply of Classics to destroy so I was not happy with my performance in this instance. I tried again using 650 as a value. It took this value but once again went to off mode- this time without an error message. I retreated in disarray after resetting my Classic......

        I went over cpfl's code as he is writing to the Classic successfully with his nice diversion system however not knowing Python? and having only a basic understanding of C it did not help me much. I poked around the arduino site and the web but did not get an understanding of where I am going wrong. I am posting the code I used with the rs232 writing code commented out . I am making an error in the code somewhere but so far have not been able to find what it is.

Will

Title: Re: rs232 modbus to Classic
Post by: WillEert on August 05, 2015, 02:05:52 PM
I think I am starting to determine what I did incorrectly. I found the SimpleModbusManual which is helping me out. Looks like I may have written the same value to three registers. Also the manual states that the FSM does not like delays in excess of 100 msec and this sketch has one of 300 msec. So I have changed the function code to write to 1 register only and taken the delay out - we shall see how the Classic likes it now.....

Will
Title: Re: rs232 modbus to Classic
Post by: WillEert on August 05, 2015, 03:35:19 PM
A form of success. I am writing to the Classic Battery Output Current Limit register and the Classic is not shutting down or rebelling in any way I can tell however -- The numbers the limit changes to do not make sense to me. I would have thought if I sent it 650 I would see     650 /10 = 65 however what I get is 88, which looks like the amp high limit. If I send it 65 I get 5 which looks like the battery low limit. So when I send it 300 I get.........5 ?????. Possibly this is a bit shifting thing although the register list does not show that this is type of byte.

More work needed.  I am baffled at this point I think.

At least my Classic has survived so far.

Latest sketch attached.

Will
Title: Re: rs232 modbus to Classic
Post by: WillEert on August 05, 2015, 10:01:04 PM
Got it working - Yay. I know more about data arrays today than I did yesterday.

Will
Title: Re: rs232 modbus to Classic
Post by: dgd on September 01, 2015, 07:09:56 AM
Will,
How have you progressed with this?
All working now?
dgd
Title: Re: rs232 modbus to Classic
Post by: WillEert on September 08, 2015, 10:46:25 PM
Hi David,

   I am working towards a combination voltage control / amps control diversion controller. This control will let me overarray my batteries while preventing them from getting too much current. The concept is to have a control that will monitor both current flow to the batteries and battery voltage. If the current flow to the batteries exceeds a setpoint then the controller will divert based on amps to the batteries. As the batteries charge and the current they take reduces then the controller automatically will change to do voltage control diversion.  Paul sent me all of his work with a diversion controller that has a gui but I have not had time to get it up and running as the amps /voltage controller has been consuming me.
   I coded up a method of changing the amps setpoint limit based on wbjr amps flowing to the battery. This lets me set the amp limit high (near comfortable Classic max) to bring as much power in as possible from the array. If the diversion load should not be available  (thermostats open) then the amps will rise above the amps diversion setpoint. When this happens the code reduces the amp setpoint limit to protect the batteries and vice versa. This is working very well.
   Next I got amp diversion control working. The amps to the battery really move around so I had to put in a smoothing system and control from that. Control is not that great due to smoothing time delay but  the concept works and will work better with some more tuning. The PID tuning is very different to the voltage tuning so I put in another PID controller for amp control with different tuning parameters - much slower.
   Next I started working on changing the state of the controller from amp control to voltage control based on input variables to the PID and amps in relation to the amp- setpoint. I had to put in a timer to prevent cycling between amp / voltage modes - this due to the slowness of amp control. Somewhere along the way I learned about pointers and am using them during the changeover process. I  have logic problems with the changeover and am working to resolve this. My most recent book is helping me with this. I realize that my logic was giving an if function a value of one when I am trying to compare values so it is making the statement true when it should not be. More thought required.
    While all this was going on I got into unreliability issues with the diversion controller. On 4 occasions the battery voltage variable locked up at one voltage. This caused the diversion controller to either go wide open or shut down - Yeek!!! What to do? I suspected possibly the uno had run out of memory as it was showing 64% when compiled so I started using a Mega. This was not the solution as it locked up with the Mega also. I started thinking it was the rs232 so read and learned more about how it worked. I increased the time out count ,polling time and number of retrys. I coded up a method of seeing the retry count and watched it. The sketch still locked up even though the rs232 was OK. Hmmmm.....
      I went back to a very simple voltage control diversion sketch. This worked very well and did not lock up. I started adding refinements a couple of days apart. When I added the "button'" I had coded up to turn off the lcds with a time delay the controller locked up. I took the button out and have not locked up since. The button turns the lcds on when pushed and then after a millis count turns them back off again - similar to the Classic controller which we like so well. I am going to run with no changes for another 2 weeks before I go at the amp control again just to be sure that it was the button that was giving the controller the reliability issues.
      So that where I am. We are building a house and we are pushing to get in before Christmas. I have not figured out why my button locks up the voltage variable - an overflow or something perhaps. Luckily I do not need it to run the control. I coded up a simple system that turns the lcds off when the Classic is resting which is better than having them on all the time but it is not really how I want the controller to work. So I am thinking now  a state machine will work well to change modes. I think with my new understanding that any number greater than one is seen as true in an if statement will let me get the changeover logic working as I would like. I am still poking about with different button logic as I would like the off delay timer to work. The pid voltage diversion controller is working great. I have tuned it up a bit more and now the response time to recover from a cloud and get back to full diversion is getting quite fast. Paul's idea of lead/lag elements is working well. I rewired my hot water tank and put new thermostats on it and my system now will capture just about every watt available so long as I do not run out of diversion load room. When I put the house heating system in service (which removes heat from the HWT via an hx) then the thermostats never open and my off grid system makes almost as much power as a grid tie system would.
      I am thinking it would be very easy to make a standalone amps diversion controller. I am considering doing this and running it for a while just to see how it works and to gain experience with it. It could then be added to the voltage diversion control and the state change logic figured out without the variable of trying to get the amp control working at the same time as trying to get the state changeover working. Also I am thinking of a amp limiting control to answer to need of some people on the wbjr thread. This would just raise and lower the amp limit within upper and lower parameters in response to amp flow to the batteries. It would not do diversion but would permit over arraying of a battery bank while protecting them from the risk of overcurrent - I think this should be quite easy.  I just need to get this house finished...

  Just for fun I have attached a sketch that is about as far as I have got when I had to back up and find out why the voltage was locking up. Caution - This is not a finished piece of code and will "lock up" periodically doing various horrible things to your system. Also the changeover logic is not working - I think due to the 1s problem. Maybe you can tell why the button timer gives the sketch problems - I have not been able to yet in the time I have had available to think about it.

Will
Title: Re: rs232 modbus to Classic
Post by: Manjunath on October 12, 2015, 08:26:19 AM
I am also trying to read one of the Energy meter's modbus data through rs485 and show in hercules(Terminal).
for this case I used arduino as master to read Energy meter as slave to read modbus data. I am failed to use this library
Any body please help me
Title: Re: rs232 modbus to Classic
Post by: kibi on December 11, 2016, 07:02:44 AM
Just one small observation that I have made.
According to your code, PCB temp is being read at register(18) and FET temp is being read at register(19).


     pcb_temp = readRegs[18];
     pcb_temp /=10;
     fet_temp = readRegs[19];
     fet_temp /=10;


These are the wrong way around according to the Classic register map. FETtemp is at 4133 and PCBtemp is at 4134

I have amended my sketch to look like this:


     fet_temp = readRegs[18];
     fet_temp /=10;
     pcb_temp = readRegs[19];
     pcb_temp /=10;


Like I said, it's a minor detail, but it's nice to have things as perfect as possible :)

Thank you very much for your efforts.
I am working towards adapting your project to use the data gathered from the Classic to construct a Victron VE.Direct data frame and have the Classic pose as one of Victron's charge controllers to my BBB which running Venus. The BBB is then posting data to Victron's VRM site.