Hello Guest it is March 29, 2024, 08:49:00 AM

Author Topic: Arduino Mega, Modbus, How to display g xyz coordinates on lcd  (Read 3809 times)

0 Members and 1 Guest are viewing this topic.

Arduino Mega, Modbus, How to display g xyz coordinates on lcd
« on: August 12, 2019, 05:22:36 PM »

Hello all.
I am trying to display the current xyz coordinates on arduino. For now, I can only light the led on arduino. Could someone more knowledgeable in the subject support me with the arduino code and information on how and what to do? I don't expect anyone to do it for me but any help will be helpful.


I use arduino code from this forum and it works very well. But I have no idea how to display xyz coordinates.
Code: [Select]
Below is the code I have on arduino:

[code]
/*
     Modbus Slave designed for Mach 3 CNC Software
 Written by: Tim W. Shilling, March 4, 2012.
 Released into the Public Domain
 */
//############################################
//  Supportted Functions
//  1:  Read Coil
//  2:  Read Descrete Input   
//  3:  Read Holding Reg
//  4:  Read Input Reg
//  5:  Write Single Coil
//  6:  Write Single Reg
//  7   Read Exception
//  15: Write Multiple Coils
//  16: Write Multiple Holding Reg

// Notes on Timing:
// Original Design implemented Timer 1 and 0, but these conflict with the PWM generators
// Timers dropped for millis and micros functions.  Not as accurate but fine for this purpose






// WH4004A Test Program: WinStar 40x4 LCD
// using Enhanced LiquidCrystal440.h
// Since the pinouts are different from Forum sample 40x4 LCDs
// Available nkcelectronics.com. Data sheet WH4004A-YYH-JT.pdf
// To adjust contrast, 10K pot between GND and +5V, wiper W to lcd 12
// LCD Func Arduino Desc pins               Dan Magorian 10/19/2010
// 1    DB7  12    Data bus line
// 2    DB6  11    Data bus line
// 3    DB5  10    Data bus line
// 4    DB4   9    Data bus line
// 5    DB3        Data bus line
// 6    DB2        Data bus line
// 7    DB1        Data bus line
// 8    DB0        Data bus line
// 9    E1   4     Chip enable signal, lcd lines 1 & 2
// 10   RW   3     H: Read L: Write
// 11   RS   2     H: DATA, L: Instruction code
// 12   V0   W     Contrast, gnd = full, too dark
// 13   VSS GND    Ground for logic
// 14   VDD +5V    Supply Voltage for logic
// 15   E2   5     Chip enable signal, lcd lines 3 & 4
// 16    NC
// 17    LED+      Ext +5V Supply for fluor LED+ optional turn fluor on
// 18    LED-      Ext GND Supply for fluor LED- optional turn fluor on
//
// If char blocks show black but nothing prints, adjust contrast pot,
// and check lcd pins 13 and 14: display may not be initialized.
// If alternate blocks and blank lines show, then neither of the controllers
// is properly initialized, check RW, E1, E2, or any of the connections




//################# INCLUDES #################
#include <Modbus_Slave.h>    // Ensure you have included the libraries in the Arduino Libraries folder
#include <ArduinoModbus.h>
#include <LiquidCrystal440.h>



const int ledPin = LED_BUILTIN;


// LiquidCrystal lcd(rs,rw,enable1,enable2,d4,d5,d6,d7);
// Note: some Forum examples using LiquidCrystal440.h have wrong DB pins,
// eg DB0-DB3, or in wrong order.  The top 4 work, in this order.

LiquidCrystal lcd(2, 3, 4, 5, 9, 10, 11, 12);



//################# DEFINES ##################
#define Baudrate 9600       //Desired Baud Rate, Recommend, 9600, 19200, 56800, 115200
#define Freq 16000000        //Don't Touch unless using a differnt board, Freq of Processor
#define Slave_Address 0x01   //Address of MODBus Slave
#define Kill_Time 2000       //2 Sec (2000msec) keep alive, 0 => OFF

//############  REGISTER DEFINES ############# // Each Register is 16bit
#define Digital_IO_Register 0
#define PWM_Register        10
#define AN_Register         30
#define Timer_Register      50
#define IO_Config_Register  60
#define Kill_IO_Register    70
#define PWMIOMap_Register   80
#define ANIOMap_Register    81
#define General_Config      90
#define Error_Register      91
#define Digital_IO_Pins     14   //Total number of Digital IO pins, Limits update scanner pin count
#define Number_Of_Registers 100

//############ GLOBAL VARIABLES ##############
unsigned char Data[256];                                         // All received data ends up in here, also used as output buffer
unsigned short Index = 0;                                        // Current Location in Data
unsigned short Register[Number_Of_Registers];                    // Where all user data, Coils/Registers are kept
ModBusSlave ModBus(Slave_Address,Register,Number_Of_Registers);  // Initialize a new ModBus Slave, Again, you must have my Arduino ModBusSlave Library
unsigned long Last_Time=0;
unsigned long Time = 0;
unsigned long LongBreakTime;                                            //Time for 3.5 characters to be RX




//################## Setup ###################
// Takes:   Nothing
// Returns: Nothing
// Effect:  Opens Serial port 1 at defined Baudrate
//          Configures all Pins
//          Initiallized Timer 1






void setup()
{

  lcd.begin (40, 4);
  lcd.clear();

  lcd.setCursor(0, 0);
  lcd.print("MODBUS TEST:");

    // configure the LED
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
 

 
  //################ Initialize IO #################     // 0 => Output, 1 => Input, opposite of normal Arduino, but my habit from other platforms, 0 looks like an O and 1 looks like an I
  Register[IO_Config_Register]    = 0b0000000000000000;  // UNO and MEGA  PIN 00-15
  Register[IO_Config_Register+1]  = 0b0000000000000000;  // MEGA          PIN 16-31
  Register[IO_Config_Register+2]  = 0b0000000000000000;  // MEGA          PIN 32-47
  Register[IO_Config_Register+3]  = 0b0000000000000000;  // MEGA          PIN 48-64
  Register[IO_Config_Register+4]  = 0b1111111111111111;  // AN Digital    PIN A0-A16

  //################ Kill IO Register #################  // 0 => Leave, 1 => Kill
  Register[Kill_IO_Register]    = 0b1111111111111111;    // UNO and MEGA  PIN 00-15
  Register[Kill_IO_Register+1]  = 0b1111111111111111;    // MEGA          PIN 16-31
  Register[Kill_IO_Register+2]  = 0b1111111111111111;    // MEGA          PIN 32-47
  Register[Kill_IO_Register+3]  = 0b1111111111111111;    // MEGA          PIN 48-64
  Register[Kill_IO_Register+3]  = 0b1111111111111111;    // AN Digital    PIN A0-A16

  //################ PWM IO Register #################   // 0 => Normal I/O, 1 => PWM I/O
  Register[PWMIOMap_Register]   = 0b0000111001101000;    // UNO and MEGA  PWM 01-16

  //################ AN IO Register #################    // 0 => Digital, 1=> Analog
  Register[ANIOMap_Register]    = 0b1111111111111111;    // UNO and MEGA

  Config_IO();

  LongBreakTime = (long)((long)28000000.0/(long)Baudrate);
  if(Baudrate > 19200)
    LongBreakTime = 1750;                                // 1.75 msec
  Serial.begin(Baudrate);                                // Open Serial port at Defined Baudrate
  Time = micros();                                       // Preload Time variable with current System microsec
}

//################ Main Loop #################
// Takes:   Nothing
// Returns: Nothing
// Effect:  Main Program Loop

unsigned long LongKillTime = (long)((long)Kill_Time * (long)1000);      //Time ellapsed between RX that causes system Kill

unsigned long Keep_Alive = 0;                                           // Keep Alive Counter Variable

void loop()
{
  Update_Time();
  if(Keep_Alive >= LongKillTime){               // Communications not Received in Kill_Time, Execute Lost Comm Emerency Procedure
    if(Kill_Time != 0){                         // If Kill_Time is 0, then disable Lost Comm Check
      Keep_Alive = LongKillTime;                // Avoid Keep_Alive rollover
      ModBus.Error = 0xff;                      // Set error code to Lost Comm
      Register[Error_Register] = ModBus.Error;  // Set Error Register
      Kill_IO();                                // Kill what should be killed
      digitalWrite(13,1);                       // Indicate Error with Solid LED
    }
  }
  else
  {
    Update_Pin_States();                        // Update Digital Pins
    Update_AN_States();                         // Update Analog Pins
    if(ModBus.Error != 0){                      // Flash Error LED is ModBus Error != 0
      digitalWrite(13,bitRead(Time,11));        // Toggle LED
    }
    else                                        // If no Error
    {
      digitalWrite(13,0);                       // Turn off LED
    }
  }
  //######################## RX Data ###############################
  if (Serial.available() > 0)                   // If Data Avilable
  {
    Data[Index] = (unsigned char)Serial.read(); // Read Next Char
    Keep_Alive = 0;                             // Reset Keep Alive counter     
    Last_Time = micros();                       // Update Last_Time to current Time
    Index++;                                    // Move Index Counter Forward
  }
  //##################### Process Data #############################
  if(Index > 0)                                 // If there are bytes to be read
  {
    if(Keep_Alive >= LongBreakTime)             // Transmission Complete, 3.5 char spacing observered
    {
      Register[Timer_Register] = (unsigned int)(millis() / 125.0);  // Converts to 1/8sec and load into Register
      ModBus.Process_Data(Data,Index);          // Process Data
      if(ModBus.Error == 0)                     // If no Errors, then...
      {
        Keep_Alive = 0;                         // Reset Keep Alive
        Last_Time = micros();                   // Set Last_Time to current time
      }
      else                                      // If there was an error
      {
        Register[Error_Register] = ModBus.Error;// Set Error Code
      }
      Index = 0;                                // Reset Index to 0, no bytes to read
    }
  }
}












//################ Update Time #################
// Takes:   Nothing
// Returns: Nothing
// Effect:  Updates Timer Register
//          Updates KeepAlive Count

void Update_Time()
{
  Last_Time = Time;                             // Set Last_Time to Current Time
  Time = micros();
  if(Time < Last_Time)                          // Counter has rolled over, should take 70 Min
  {
    Last_Time = 0;                              // Introduces a small clitch in timing by not accounting for how bad the roll over was.  Happens every 70 Min
                                                // Result is Delta will be smaller than it should be, Kill and Character Spacing will be usec longer than they should 
  }
  Keep_Alive += Time - Last_Time;               // Increment Keep Alive counter
  Register[Timer_Register] = (unsigned int)(millis() / 125.0);  // Converts to 1/8sec and load into Register
}
//EOF






Re: Arduino Mega, Modbus, How to display g xyz coordinates on lcd
« Reply #1 on: September 30, 2020, 02:15:21 PM »
Hello Adam_Weles, If your modbus map is okay i think it will working,  You said that you can only succeed make led ON arduino board. I thought that your communication setting software with arduino have not problem.  I suggest you check again modbus map for current xyz value.
Would you let us know your topology connection of your project?
Re: Arduino Mega, Modbus, How to display g xyz coordinates on lcd
« Reply #2 on: February 20, 2021, 06:27:41 AM »
haha bumping this old post.

here is a demo you can use. no arduino libraries currently exist to take advantage of floating point numbers being sent over modbus. so you have to convert the 16 bit integer value of the decimal and integer value of the DRO on both ends. I am using an ESP32 microcontroller with a ILI9341 display in this example (microcontroller has a 32 bit processor). An arduino due is just as fast. I am working on editing an arduino library to allow floating point numbers over modbus tcp.

this is the screen load script:
Code: [Select]
local axis1DROPrefixReg = mc.mcRegGetHandle(inst, 'ModbusMPG/axisDRO0')
local axis1DRODecimalReg = mc.mcRegGetHandle(inst, 'ModbusMPG/axisDRO1')

and the plc script:
Code: [Select]
local axisPos = mc.mcAxisGetPos(inst, 0)
axisPos = tonumber(string.format('%0.4f', tostring(axisPos)))

local axisPosPrefix = 0
if axisPos < 0 then
axisPosPrefix = math.ceil(axisPos)
else
axisPosPrefix = math.floor(axisPos)
end

local axisPosDecimal = (axisPos - axisPosPrefix) * 10000

mc.mcRegSetValueLong(axis1DROPrefixReg, axisPosPrefix)
mc.mcRegSetValueLong(axis1DRODecimalReg, axisPosDecimal)

here is a video demo of reading just the x-axis DRO onto the screen (slow refresh, but can make it faster by changing the LOOP_PERIOD #define in the firmware:

Code: [Select]
https://www.youtube.com/watch?v=jDV3ixK61aA
The firmware for the ESP32 is attached.

The instructions to get it up and running are here but you will need to add the 2 hregs for the xaxis dro manually. I can put them into the .exe soon but i'll probably do that after i update the modbus to transfer floating point numbers once i figure out the Mach4 protocol for sending.

Code: [Select]
https://github.com/kethort/esp32-cnc-mpg-handwheel-conversion-mach4
to add the 2 hregs in mach4 for testing follow the settings in the pictures below.

Offline Azalin

*
  •  181 181
    • View Profile
Re: Arduino Mega, Modbus, How to display g xyz coordinates on lcd
« Reply #3 on: August 24, 2021, 03:56:23 PM »
Hello @compewter_numerical,

I replicated this pendant. Works over USB but works well. One way of course.
https://www.instructables.com/Mach4-Pendant/

How can I listen axis coordinates from Mach4 in Arduino Due?

I do coding but Arduino and Modbus is still very new to me.

Thanks.
Re: Arduino Mega, Modbus, How to display g xyz coordinates on lcd
« Reply #4 on: September 09, 2021, 09:37:57 PM »
Hello @compewter_numerical,

I replicated this pendant. Works over USB but works well. One way of course.
https://www.instructables.com/Mach4-Pendant/

How can I listen axis coordinates from Mach4 in Arduino Due?

I do coding but Arduino and Modbus is still very new to me.

Thanks.

The modbus arduino library is really simple to setup.

The tricky part is floating point conversion of the modbus regs. you'll need to convert on both ends, mach4 and arduino.

I did this by creating two modbus regs for each axis DRO. where the first register represents the number without decimal and the second number is 4 digit decimal converted to int.

Here is an example of the conversion:

LUA in Mach4 PLC (droRegsPos and axisPos are globals defined in the screen load function):
Code: [Select]
-- script converts each axis DRO floating point numbers into two 16bit integers
-- which can be sent over modbus


-- gets the position of the given axisID from Mach core
local axisPos = mc.mcAxisGetPos(inst, axisID)
axisPos = tonumber(string.format('%0.4f', tostring(axisPos)))

-- gets the whole number (preceding the decimal) of the axis position
-- if the number is negative use math.floor otherwise math.ceil
local axisPosPrefix = 0
if axisPos < 0 then
axisPosPrefix = math.ceil(axisPos)
else
axisPosPrefix = math.floor(axisPos)
end

-- gets the decimal part of the axis position DRO (to 4 decimal places)
-- and stores it in an integer variable
local axisPosDecimal = (axisPos - axisPosPrefix) * 10000

-- set the modbus DRO regs with the values converted above
mc.mcRegSetValueLong(axisDRORegs[droRegsPos], axisPosPrefix)
droRegsPos = droRegsPos + 1
mc.mcRegSetValueLong(axisDRORegs[droRegsPos], axisPosDecimal)

-- increment our register and axis positions
-- the register positions are incremented once above and again below because
-- there are two registers for each DRO
droRegsPos = droRegsPos + 1
axisID = axisID + 1

if droRegsPos > #axisDRORegs then
droRegsPos = 1
axisID = 0
end

Arduino code:
Code: [Select]
  // converts two 16bit integers into floating point (DRO value)
  int16_t droPrefix = mb.Hreg(hreg1);
  int16_t droPostfix = mb.Hreg(hreg2);
  float droDecimal = droPrefix + (droPostfix / 10000.0);

I included a tutorial of this in the document I posted on a repo on github. I used TCP modbus in the examples but, it should be similar to use serial modbus connection in mach4 except you define a comm port and baud rate on both ends instead of an ip address:
Code: [Select]
https://github.com/kethort/io-over-tcp-modbus-arduino-mach4/blob/master/Mach4%20Arduino%20Modbus%20TCP.docx

You can find all of the code I described above in this repo:
Code: [Select]
https://github.com/kethort/esp32-cnc-mpg-handwheel-conversion-mach4

The best solution would be to convert the float to 32 bit int and update the arduino modbus lib to use uint32_t instead of uint16_t vars in it's payload. Here is a link on a calculator that explains how a floating point number can be stored in a 32bit type.

Code: [Select]
https://www.h-schmidt.net/FloatConverter/IEEE754.html


 
« Last Edit: September 09, 2021, 09:48:24 PM by compewter_numerical »