Friday, 8 May 2015

LRC calculation for MODBUS ASCII Protocol In Arduino

In MODBUS Ascii mode each 8 bit data is the combination of two ascii characters
for ex: a 1 byte data 64H is shown as '64' in ASCII, consist of '6'(36 Hex) and '4'(34 Hex) (i still need to figure out the difference between those and standard ASCII values)

to calculate LRC for frame ":010304010001"
we need to add 01H + 03H + 04H + 01H + 00H + 01H = 0aH,
the 2's complement negation of 0aH is f6H

code to perform this is

/*
Author : Kunchala Anil
Calculating the LRC of HEXA numbers used in MODBUS ASCII

In MODBUS ASCII protocol : is used as starting word
The special function used in this code is utoa() and strlen() and sprintf()

utoa() --> unsigned integer to String for base conversion

syntax : utoa((unsigned int)val , string , base)

where val : is the value to be converted into base N format
string : is the temporary string to store the converted value
base : base is the Radix which val is converted (in this code it is 16)

strtol() --> string to long int

syntax : strtol(str,end_ptr,radix)
str : string to be converted
end_ptr : end pointer (NULL)
base : radix of the system

sprintf() --> string print function

syntax : sprintf(str,format)
str : destination string where output is stored

*/
char a[] = ":010304010001"; // ASCII string lrc being added

void setup(){
Serial.begin(9600); // start the serial communication
Serial.print("The string to which LRC is calculated is : ");
Serial.println(a);
int val = calculate(); //function to calculate the decimal value
convert_to_hex(val);// function to convert the decimal value to HEX
}//end of setup()

void loop(){
//do nothing here
}//end of loop()

//CALCULATE() FUNCTION
int calculate(){
int val[strlen(a)/2]; // val[] array is used to store the decimal value for two HEX digits
for (int i = 1, j = 0 ; i < strlen(a); i = i+2, j++ ) //i = i+2 because we are finding the decimal equalent for two HEX values
{
val[j] = conv(a[i],a[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(a)/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(a,hex_val_str);
char ter[] = "\r\n";
strcat(a,ter);//adding terminators at the end or STOP bits
Serial.println(a);
}//end of convert_to_hex() fucntion


output
LRC_output

No comments:

Post a Comment