Thursday 14 May 2015

controlling VFD with arduino...

i made a simple code to control VFD (change the speed and direction of ac drive) with arduino.

/*
Author : Kunchala Anil [anilkunchalaece@gmail.com]

Interfacing VFD with Arduino Via RS485 using MODBUS Protocol
MODBUS protocol
-------------------------------------------------------------------------
| Start Bit | Address | Function_Command | DATA | LRC or CRC | Stop bit |
| : | 2bytes | 2 bytes | | 2 bytes | \r\n |
-------------------------------------------------------------------------

Function Code : The format of data characters depend on function codes
The available function codes are described as follows:
0x03 : Read data from register
0x06 : Write single data to register
0x10 : Write multiple data to registers

MODBUS Protocol can be implemented in two ways ASCII or RTU(Remote Terminal Unit)
iam gonna use ASCII mode for this example

____________________________________________________________________________
| Content Address Functions
|-------------------------------------------------------------------------
| B1 B0
| 0 0 --> NO function
| Bit 0 - 1 0 1 --> Stop
| 1 0 --> Run
| 0x2000 1 1 --> Jog + Run
|
| Bit 2 - 3 Reserved
|
| B5 B4
| 0 0 --> No function
| Command Bit 4 - 5 0 1 --> FWD
| Read / Write 1 0 --> REV
| 1 1 --> Change Direction
|
| Bit 6 - 15 Reserved
|
| 0x2001 Frequency Command
|
|__________________________________________________________________________________


Command Address B15 B14 B13 B12 B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0 Hex Equalent
RUN 0x2000 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0x0012
STOP 0x2000 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0x0011
Format if data send to the VFD
':' --> Start bit in Ascii mode
\r\n --> Stop bit


*/

//commands values
#define VFD_START 1
#define VFD_STOP 2
#define VFD_SPEED 3

#define MAX_SIZE 20 // max size of data buffer

char speed_vfd[] = ":01062001";
const char start_vfd[] = ":010620000012C7\r\n";
const char stop_vfd[] = ":010620000011C8\r\n";
char data_buffer[MAX_SIZE];

void setup(){
Serial.begin(9600);
}//end of setup


void loop(){

serial_ask(); /* ask question the user to enter
1 to start the VFD
2 to stop the VFD
3 to set the speed of VFD */
int val = serial_check(); /* wait for user to enter the data and convert
it to Int and return value into function */
perform_action(val); /* perform the action based on the user entered value
which is passed to the function */

}//end of loop


/*
SERIAL_ASK() FUNCTION : this function is used to ask the user to enter the user choice via Serial monitor
*/
void serial_ask(){
Serial.println("Please Enter all values followed by \n");
Serial.println("Please enter the valid code to perform");
Serial.println("-------------------");
Serial.println("CODE\t ACTION");
Serial.print(VFD_START);Serial.println("\t START VFD");
Serial.print(VFD_STOP);Serial.println("\t STOP VFD");
Serial.print(VFD_SPEED);Serial.println("\t SET SPEED");
Serial.println("-------------------");
}//end of serial_ask() fucntion


/*
SERIAL_CHECK() FUNCTION : this function is used to receive the data into data_buffer
*/
int serial_check(){
while(!data_received())
{
//wait until full data is received
}//end of while
return atoi(data_buffer);
}//end of serial_check() function


boolean data_received(){
static byte index = 0;
while(!Serial.available())
{
//wait until user enter the data
}

if(Serial.available())
{
char input = Serial.read();
if(input !='\r')
{
data_buffer[index] = input;
index = index + 1;
}else
{
data_buffer[index] = 0;//null terminate the character array to make it string
index = 0;
return true;// we received the full code return true
}//end of ifelse condition
}
return false;
}//end of data_received()) function

void perform_action(int val){
switch(val)
{
case VFD_START:
Serial.println("VFD START");
VFD_control(start_vfd);
break;

case VFD_STOP:
Serial.println("VFD STOP");
VFD_control(stop_vfd);
break;

case VFD_SPEED:
Serial.println("SET SPEED");
set_speed();
break;

default:
error_message();

}//end of switch
}//end of perform action

void VFD_control(const char* command){
Serial.print(command);
Serial.println();
}

void set_speed(){
char freq_hex[4];//temporary string for sprintf
Serial.println("Set Speed");
Serial.println("enter the frequency");
int freq = serial_check();
Serial.print("the frequency you entered is");
Serial.println(freq);
sprintf(freq_hex,"%04X",freq);//convert it to hex using sprintf
strcat(speed_vfd,freq_hex);
cal_LRC();

}//end of set_speed() fucntion

void cal_LRC(){
int val = calculate(); //function to calculate the decimal value
convert_to_hex(val);// function to convert the decimal value to HEX
}//end of cal_LRC() fucntion


//CALCULATE() FUNCTION
int calculate(){
int val[strlen(speed_vfd)/2]; // val[] array is used to store the decimal value for two HEX digits
for (int i = 1, j = 0 ; i < strlen(speed_vfd); i = i+2, j++ ) //i = i+2 because we are finding the decimal equalent for two HEX values
{
val[j] = conv(speed_vfd[i],speed_vfd[i+1]); // function to convert Two Hex numbers into Decimal Value

}//end of for loop

int sum = find_sum(val); // function to calculate total sum of decimal equalents
return sum;
}//end of calculate() function

//FUNCTION_SUM() FUNCTION
int find_sum(const int * val) // we are passing an array to the function
{
int sum = 0;
for(int i=0;i<= (strlen(speed_vfd)/2) - 1;i++)
{
sum = sum + val[i];
}//end of for loop
return sum;
}//end of find_sum() function

//FUNCTION TO CONVERT HEX TO THE DECIMAL VALUE
int conv(char val1,char val2){
int val_a = toDec(val1); // convert to the decimal value
int val_b = toDec(val2);
return (val_a*16) + val_b; // converting decimal value into HEX decimal Equalent B1*16 + B0
}//end of conv() function

int toDec(char val){
if(val<='9')
{
return val - '0'; // please see the ASCII table for clarification
}
else
{
return val - '0'-7; // 7 is offset for capital letters please see the ASCII table
}

}//end of toDec() function

void convert_to_hex(int val){
char hex[5];
utoa((unsigned)val,hex,16); // utoa() function is used to convert unsigned int to HEX array (whatever the base we specified as third argument)

int hex_val = (int)strtol(hex,NULL,16);// strtol() is used to covert string into long int according to the given base

hex_val = ((~hex_val) + B01) & 0xff; /* finding the 2's complement of the number hex_val
'~' operator is the logical not and adding B01 to it and logical anding with 0xff
to omit any excess bites otherthan 8 bits or 1 byte
*/
Serial.print("the LRC value is : ");
Serial.println(hex_val,HEX);
char hex_val_str[4];
sprintf(hex_val_str,"%0.2X",hex_val);// putting hex value in the string back
Serial.print("the concated string is : ");
strcat(speed_vfd,hex_val_str);
char ter[] = "\r\n";
strcat(speed_vfd,ter);//adding terminators at the end STOP bits
Serial.println(speed_vfd);
}//end of convert_to_hex() fucntion


void error_message(){
Serial.println("You Entered Wrong Command");

}//end of error_message()

it actually doesn't do anything.. we can modify the code to send the modbus control to the VFD.
I don't have the hardware to test it But i made the code using VFD-m Manual
delta VFD-m

4 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. very interesting
    i am using arduino for my 2dof sim project and it drive rc servo
    now i can drive ac motor with the vfd but how can i have feed back added to this code to monitor the postion of the motor if warmbox conected to it

    Example
    https://www.youtube.com/watch?v=JQAZB3EnI_w

    ReplyDelete
  3. Hi, how did you connect the VFD to the arduino? Did you use the analog inputs and outputs on the VFD or serial port on the VFD?

    ReplyDelete
    Replies
    1. Using RS485 Via ModBus Protocol..
      Through TTL to RS485 Converter via Serial Communication.
      (FYI : I never got the Chance to Test this Code)

      Delete