ModBus communication with Arduino

Hi Everyone,

I am trying to operate a variable frequency drive (Yaskawa V1000) with the arduino uno and modbus . What i am trying to do is to run a motor in different frequencies for a particular amount of time. For example . i want to start the motor up to 40 hz ( 2400rpm) hold it for 2 minutes and then stop it. I was wondering if somebody did something similar and had some code to share. Not so familiar with modbus but i am willing to figure out. I am waiting for the RS 485 for arduino and i have some code that i found on the internet and i am trying to put everything together. The part that i am a little confused is the CRC CALCULATIONS AND how i implement it in the code. I have attached the code and the manual of the vfd. Hopefully someone can help me.

Regards,
Thomas

Yaskawa-V1000-Manual-modbus.pdf (722 KB)

VFD.zip (1.04 KB)

I can't tell what function crc() is supposed to do. Is it some of the code that you downloaded from somewhere else?

If you're looking for code to calculate CRC, there are a lot of examples on the web. If you'd like to develop your own code, we can help with that. What'll it be?

I had to do some MODBUS recently. Searching for MODBUS CRC found some code in basically the first Google result. It was C code and needed to change something in the type names (like int16 has to be uint16_t on Arduino) but it worked first time.

Here’s a complete working example of how to use the MODBUS CRC:

/* CO2 Modbus
  
  Verify basic Serial communication with the K30 from co2meter.com
  
  Hardware: Arduino Due (K30 requires 3.3v communications)
            K30 powered from 5v, communicating on Tx0/Rx0
              

  
  Modification History:
  4/6/15 M Sandercock: Created
*/
#define SerialPort SerialUSB //for testing on Arduino DUE native port (SerialUSB) or programming port (Serial)
#define SerialSensor Serial  //

#define K30ADDRESS 0x68      //the I2C address of the sensor. This is programmable through I2C, but 0x68 is the factory default

// Compute the MODBUS RTU CRC
//from http://www.ccontrolsys.com/w/How_to_Compute_the_Modbus_RTU_Message_CRC
uint16_t ModRTU_CRC(byte buf[], int len)
{
  uint16_t crc = 0xFFFF;
 
  for (int pos = 0; pos < len; pos++) {
    crc ^= (uint16_t)buf[pos];        // XOR byte into least sig. byte of crc
 
    for (int i = 8; i != 0; i--) {    // Loop over each bit
      if ((crc & 0x0001) != 0) {      // If the LSB is set
        crc >>= 1;                    // Shift right and XOR 0xA001
        crc ^= 0xA001;
      }
      else                            // Else LSB is not set
        crc >>= 1;                    // Just shift right
    }
  }
  // Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes)
  return crc;  
}

void setup() {
  SerialPort.begin (115200);
  SerialSensor.begin(9600);  
  while(!SerialPort); //wait for serial monitor to connect
  SerialPort.println ("Starting ...");

}  // end of setup

void loop() {
  //send the MODBUS read command, asking for the number 4 register (address 3) which is the CO2 concentration in ppm/10
  //<FE> <04> <00> <03> <00> <01> <D5> <C5>
  //FE is the all-sensors broadcast address. It's not suposed to be used but 
  //nowhere in the MODBUS docs does it say how to set the address or even find out what it is.
  //Fortunately, it seems to use the same address as the I2C. (Just need to get the CRC correct.)
  byte msg[] = {K30ADDRESS, 4, 0, 3, 0, 1};
  uint16_t CRC = ModRTU_CRC(msg, 6);
  SerialPort.print("Sending:");
  for(int i=0; i<6; i++) {
    SerialSensor.write(msg[i]);
    
    SerialPort.print(" 0x");
    if(msg[i]<0x10) SerialPort.print("0");
    SerialPort.print(msg[i], HEX);
  }
  SerialSensor.write((byte) CRC);

  SerialPort.print(" 0x");
  if(((byte) CRC)<0x10) SerialPort.print("0");
  SerialPort.print((byte) CRC, HEX);

  SerialSensor.write((byte) (CRC>>8));

  SerialPort.print(" 0x");
  if(CRC>>8<0x10) SerialPort.print("0");
  SerialPort.print(CRC>>8, HEX);
  SerialPort.println();
  

  
  //wait up to 300ms for a response
  unsigned long start = millis();
  //wait until we have enough bytes in our input buffer
  while(SerialSensor.available() < 7) {
    if(millis() - start > 300) break; 
  }
  unsigned long finish = millis();
  
  SerialPort.print("Response: ");
  while(SerialSensor.available()) {
    SerialPort.print(" 0x");
    SerialPort.print(SerialSensor.read(), HEX);
  }
  SerialPort.println();
  SerialPort.print("Wait duration was: ");
  SerialPort.print(finish-start);
  SerialPort.println("ms");

 
 
  SerialPort.println("Press any key to re-scan");
  SerialPort.print(">");
  
  while(!SerialPort.available()) {
    delay(100); //wait, let some characters come into the serial buffer
  }
  while(SerialPort.available()) {
    SerialPort.read(); //clear the serial buffer
  }
}

Hi Everyone! Thank you for you replies. MorganS thank you for the example code. I am getting the RS485 tomorrow. I will try and come back to you for results or if i have any questions. Thank you again.

Regards,
Thomas

You can use this crc calculation on your project. İts product true hex code.

// Compute the MODBUS RTU CRC
String ModRTU_CRC(String raw_msg_data) {
//Calc raw_msg_data length
byte raw_msg_data_byte[raw_msg_data.length()/2];
//Convert the raw_msg_data to a byte array raw_msg_data
for (int i = 0; i < raw_msg_data.length() / 2; i++) {
raw_msg_data_byte = StrtoByte(raw_msg_data.substring(2 * i, 2 * i + 2));

  • }*

  • //Calc the raw_msg_data_byte CRC code*

  • uint16_t crc = 0xFFFF;*

  • String crc_string = “”;*

  • for (int pos = 0; pos < raw_msg_data.length()/2; pos++) {*

  • crc ^= (uint16_t)raw_msg_data_byte[pos]; // XOR byte into least sig. byte of crc*

  • for (int i = 8; i != 0; i–) { // Loop over each bit*

  • if ((crc & 0x0001) != 0) { // If the LSB is set*

  • crc >>= 1; // Shift right and XOR 0xA001*

  • crc ^= 0xA001;*

  • }*

  • else // Else LSB is not set*

  • crc >>= 1; // Just shift right*

  • }*

  • }*

  • // Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes)*

  • //Become crc byte to a capital letter String*

  • crc_string = String(crc, HEX);*

  • crc_string.toUpperCase();*

  • //The crc should be like XXYY. Add zeros if need it*

  • if(crc_string.length() == 1){*

  • crc_string = “000” + crc_string;*

  • }else if(crc_string.length() == 2){*

  • crc_string = “00” + crc_string;*

  • }else if(crc_string.length() == 3){*

  • crc_string = “0” + crc_string;*

  • }else{*

  • //OK*

  • }*

  • //Invert the byte positions*

  • crc_string = crc_string.substring(2, 4) + crc_string.substring(0, 2);*

  • return crc_string;*
    }