Problem:
In the development of embedded system, Modbus protocol is a widely used protocol in industrial control system. This is used to simulate the Modbus protocol simply by generating a data frame that conforms to the protocol and parsing the obtained data.
Assume that the device uses the protocol send data format as follows:
<slaveaddress, 1 byte> <function, 1 byte> <start Address, 2 bytes> <numberofbytes, 2 Bytes> <Ch Ecksum, 2 bytes>
The first four items will be given in the input conditions, the last is CRC checksum, according to the first four data, according to the CRC algorithm calculation. Note the length of the data, more than 1byte high in front, low in the rear. The CRC check algorithm is described as follows:
1) The CRC is assigned a value of 0xFFFF.
2) The first byte (8 bits) of the initial information is assigned to the CRC, which is different or operation.
3) Move the CRC data one bit to the right and the top (left) to 0.
4) If the CRC lowest bit (the right end) is 1 before the right shift, the CRC with the 0xa001 will be XOR and the result will be assigned to the CRC. Otherwise, skip this step.
5) Repeat 3, 4 steps 8 times (i.e. 8 bits on the right).
6) The next byte of the initial information is also performed 2,3,4,5, until all the bytes in the information have performed the same steps.
7) The high 8-bit and low 8-bit exchange of the CRC value obtained at this time, that is, the CRC checksum.
The corresponding receive format is as follows:
<SlaveAddress,1Byte> <Function,1Byte> <NumberofBytes,1Byte> <DataIEEE32,xByte> < Checksum,2bytes>
Where DataIEEE32 is one or more 32-bit floating-point numbers defined by the IEEE754 standard, the length of the data is determined by the Numberofbytes item (for example, Numberofbytes is 4, the DataIEEE32 item is 4 bytes, Represents exactly one floating-point number, or 8, the DataIEEE32 entry is 8 bytes, which represents two floating-point numbers. The subject requires programming to convert from IEEE32 data (such as "420b999a") to floating-point numbers (such as 34.9) to resolve floating-point values.
Hint: You can design the conversion algorithm according to the IEEE754 standard, or directly take advantage of the C language float type implementation characteristics: x86 Linux, the GCC compiler will c language code "float f = 34.9;" Compiled into the assembly code "MOVL $0x420b999a, -4 (%EBP)" (t x86 assembly format), that is, the single-precision floating point number 34.9 in memory is represented by the integer 0x420b999a, you can use this feature to complete the conversion.
Input
Input contains multiple sets of data, ending with EOF
Each group of data is divided into two rows.
The first line has a total of four decimal integers, each of which is required for the protocol format: <slaveaddress, 1 byte>,<function, 1 Byte>,<start Address, 2 bytes>,< Numberofbytes, 2 bytes>, separated by commas ",".
such as: 1,4,40,2
Where: 1 is slaveaddress;4 for function;40 for start address;2 for Numberofbytes.
The second behavior conforms to the receiving format of the data frame (16 binary representation), from which to parse the received data, its length is less than 64 characters, floating-point data up to 4 (that is, DataIEEE32 data items up to 32bytes).
such as: 010404420b999a7405
Among them: 01 is slaveaddress;04 for function;04 for Numberofbytes, 420b999a dataieee32;7405 for checksum.
Output
Each set of data output is a total of two rows.
The first line: According to the first line of input results, output a complete data frame in accordance with the Protocol send format, the data is in 16 uppercase, each part of the length is required to conform to the protocol format, such as the start address entry if less than 2 bytes, you need to fill 0 on the left.
such as: 010400280002f1c3
Where: 01 is slaveaddress;04 for function;0028 for start address;0002 for numberofbytes;f1c3 for checksum.
Second line: According to the second line of the input results, parse the IEEE32 data sequentially, convert it to a floating point number, and print the result (one digit after the decimal point). The CRC checksum must be checked before parsing, if the checksum fails, print crc_error directly. If there are multiple data, separate them with commas.
Example: 34.9
The floating-point value is the value that corresponds to 420b999a.
Sample Input
1,4,40,2
010404420b999a7405
1,4,40,2
010404420b999a7404
2,4,383,4
02040841cc0000477f2100df85
Sample Output
010400280002f1c3
34.9
010400280002f1c3
Crc_error
0204017f0004c1de
25.5,65313.0
Reply:
#include <string.h>
Char strout[100], recv[100], recv_hd[100];
unsigned short slaveadd, func, NB, Startadd;
unsigned short CRC;
float result[5];
Char *pt;
DO_CYC (unsigned short data)
{
int i;
unsigned short tmp;
CRC = Data ^ CRC;
for (i=0; i<8; i++)
{
TMP = CRC & (0X0001);
CRC = CRC >> 1;
if (tmp = = 1)
{
CRC = 0xa001 ^ CRC;
}
}
}
unsigned short GET_CRC ()
{
CRC = 0xFFFF;
DO_CYC (Slaveadd & 0X00FF);
Do_cyc (func & 0X00FF);
DO_CYC ((Startadd & 0xff00) >> 8);
DO_CYC (Startadd & 0X00FF);
Do_cyc (NB & 0xff00) >> 8);
Do_cyc (NB & 0X00FF);
unsigned short swap;
swap = CRC;
CRC = (CRC >> 8) & 0x00ff;
CRC = CRC | (Swap << 8) & 0xff00);
}
float conv (int data)
{
FLOAT ret;
memcpy (&ret, &data, sizeof (int));
return ret;
}
void Pre_handle ()
{
int I, data;
PT = recv;
CRC = 0xFFFF;
strncpy (RECV_HD, PT, 2);
RECV_HD[2] = ' + ';
SSCANF (RECV_HD, "%hx", &slaveadd);
PT + = 2;
DO_CYC (Slaveadd & 0X00FF);
strncpy (RECV_HD, PT, 2);
RECV_HD[2] = ' + ';
SSCANF (RECV_HD, "%hx", &func);
PT + = 2;
Do_cyc (func & 0X00FF);
strncpy (RECV_HD, PT, 2);
RECV_HD[2] = ' + ';
SSCANF (RECV_HD, "%hx", &NB);
PT + = 2;
Do_cyc (NB & 0X00FF);
for (i=0; I<NB/4; i++)
{
strncpy (RECV_HD, PT, 8);
SSCANF (RECV_HD, "%x", &data);
Result[i] = conv (data);
DO_CYC ((unsigned short) ((Data & 0xff000000) >> 24));
DO_CYC ((unsigned short) ((Data & 0x00ff0000) >> 16));
DO_CYC ((unsigned short) ((Data & 0x0000ff00) >> 8));
DO_CYC (unsigned short) (Data & 0x000000ff));
PT + = 8;
}
unsigned short swap;
swap = CRC;
CRC = (CRC >> 8) & 0x00ff;
CRC = CRC | (Swap << 8) & 0xff00);
}
int main (int argc, char *argv[])
{
Char cmp[10];
while (EOF! = scanf ("%hd,%hd,%hd,%hd", &slaveadd, &func, &startadd, &NB))
{
GET_CRC ();
sprintf (Strout, "%02x%02x%04x%04x%04x", Slaveadd, Func, Startadd, NB, CRC);
printf ("%s\n", strout);
scanf ("%s", recv);
Pre_handle (recv);
sprintf (CMP, "%hx", CRC);
if (0! = strcmp (CMP, PT))
{
printf ("crc_error\n");
Continue
}
int i;
for (i=0; i<nb/4-1; i++)
printf ("%.1f,", Result[i]);
printf ("%.1f\n", Result[i]);
}
}
Analog Modbus Protocol issues