📄 modbus_rtu.c
字号:
} status = read_registers( function, slave, start_addr, count, dest, dest_size, ttyfd ); return( status);}/************************************************************************ read_input_registers Read the inputg registers in a slave and put the data into an array. *************************************************************************/int read_input_registers( int slave, int start_addr, int count, int *dest, int dest_size, int ttyfd ){ int function = 0x04; /* Function: Read Input Reqisters */ int status; if( count > MAX_INPUT_REGS ) { count = MAX_INPUT_REGS;#ifdef DEBUG fprintf( stderr, "Too many input registers requested.\n" );#endif } status = read_registers( function, slave, start_addr, count, dest, dest_size, ttyfd ); return( status );}/************************************************************************ read_reg_response reads the response data from a slave and puts the data into an array.************************************************************************/int read_reg_response( int *dest, int dest_size, unsigned char *query, int fd ){ unsigned char data[ MAX_RESPONSE_LENGTH ]; int raw_response_length; int temp,i; raw_response_length = modbus_response( data, query, fd ); if( raw_response_length > 0 ) raw_response_length -= 2; if( raw_response_length > 0 ) { for( i = 0; i < ( data[2] * 2 ) && i < (raw_response_length / 2); i++ ) { /* shift reg hi_byte to temp */ temp = data[ 3 + i *2 ] << 8; /* OR with lo_byte */ temp = temp | data[ 4 + i * 2 ]; dest[i] = temp; } } return( raw_response_length );}/*********************************************************************** preset_response Gets the raw data from the input stream.***********************************************************************/int preset_response( unsigned char *query, int fd ) { unsigned char data[ MAX_RESPONSE_LENGTH ]; int raw_response_length; raw_response_length = modbus_response( data, query, fd ); return( raw_response_length );}/************************************************************************* set_single sends a value to a register in a slave. **************************************************************************/int set_single( int function, int slave, int addr, int value, int fd ){ int status; unsigned char packet[ REQUEST_QUERY_SIZE ]; packet[ 0 ] = slave; packet[ 1 ] = function; addr -= 1; packet[ 2 ] = addr >> 8; packet[ 3 ] = addr & 0x00FF; packet[ 4 ] = value >> 8; packet[ 5 ] = value & 0x00FF; if( send_query( fd, packet, 6 ) > -1 ) { status = preset_response( packet, fd ); } else { status = PORT_FAILURE; } return( status );}/************************************************************************* force_single_coil turn on or off a single coil on the slave device*************************************************************************/int force_single_coil( int slave, int coil_addr, int state, int fd ){ int function = 0x05; int status; if( state ) state = 0xFF00; status = set_single( function, slave, coil_addr, state, fd ); return( status );}/************************************************************************* preset_single_register sets a value in one holding register in the slave device*************************************************************************/int preset_single_register(int slave, int reg_addr, int value, int fd ){ int function = 0x06; int status; status = set_single( function, slave, reg_addr, value, fd ); return( status );}/************************************************************************ set_multiple_coils Takes an array of ints and sets or resets the coils on a slave appropriatly.*************************************************************************/#define PRESET_QUERY_SIZE 210int set_multiple_coils( int slave, int start_addr, int coil_count, int *data, int fd ){ int byte_count; int i, bit, packet_size = 6; int coil_check = 0; int data_array_pos = 0; int status; unsigned char packet[ PRESET_QUERY_SIZE ]; if( coil_count > MAX_WRITE_COILS ) { coil_count = MAX_WRITE_COILS;#ifdef DEBUG fprintf( stderr, "Writing to too many coils.\n" );#endif } packet[ 0 ] = slave; packet[ 1 ] = 0x0F; start_addr -= 1; packet[ 2 ] = start_addr >> 8; packet[ 3 ] = start_addr & 0x00FF; packet[ 4 ] = coil_count >> 8; packet[ 5 ] = coil_count & 0x00FF; byte_count = (coil_count / 8) + 1; packet[ 6 ] = byte_count; bit = 0x01; for( i = 0; i < byte_count; i++) { packet[ ++packet_size ] = 0; while( bit & 0xFF && coil_check++ < coil_count ) { if( data[ data_array_pos++ ] ) { packet[ packet_size ] |= bit; } else { packet[ packet_size ] &=~ bit; } bit = bit << 1; } bit = 0x01; } if( send_query( fd, packet, ++packet_size ) > -1 ) { status = preset_response( packet, fd ); } else { status = PORT_FAILURE; } return( status );}/************************************************************************* preset_multiple_registers copy the values in an array to an array on the slave.***************************************************************************/int preset_multiple_registers( int slave, int start_addr, int reg_count, int *data, int fd ){ int byte_count, i, packet_size = 6; int status; unsigned char packet[ PRESET_QUERY_SIZE ]; if( reg_count > MAX_WRITE_REGS ) { reg_count = MAX_WRITE_REGS;#ifdef DEBUG fprintf( stderr, "Trying to write to too many registers.\n" );#endif } packet[ 0 ] = slave; packet[ 1 ] = 0x10; start_addr -= 1; packet[ 2 ] = start_addr >> 8; packet[ 3 ] = start_addr & 0x00FF; packet[ 4 ] = reg_count >> 8; packet[ 5 ] = reg_count & 0x00FF; byte_count = reg_count * 2; packet[ 6 ] = byte_count; for( i = 0; i < reg_count; i++ ) { packet[ ++packet_size ] = data[ i ] >> 8; packet[ ++packet_size ] = data[ i ] & 0x00FF; } if( send_query( fd, packet, ++packet_size ) > -1 ) { status = preset_response( packet, fd ); } else { status = PORT_FAILURE; } return( status );}/********************************************************************************************************* [ BEGIN: crc ] ***********************************************************************************************************INPUTS: buf -> Array containing message to be sent to controller. start -> Start of loop in crc counter, usually 0. cnt -> Amount of bytes in message being sent to controller/OUTPUTS: temp -> Returns crc byte for message.COMMENTS: This routine calculates the crc high and low byte of a message. Note that this crc is only used for Modbus, not Modbus+ etc. ****************************************************************************/unsigned int crc(unsigned char *buf,int start,int cnt) { int i,j; unsigned temp,temp2,flag; temp=0xFFFF; for (i=start; i<cnt; i++) { temp=temp ^ buf[i]; for (j=1; j<=8; j++) { flag=temp & 0x0001; temp=temp >> 1; if (flag) temp=temp ^ 0xA001; } } /* Reverse byte order. */ temp2=temp >> 8; temp=(temp << 8) | temp2; temp &= 0xFFFF; return(temp);}/************************************************************************ set_up_comms This function sets up a serial port for RTU communications to modbus.**************************************************************************/int set_up_comms( char *device, int baud_i, char *parity ){ int ttyfd; struct termios settings; speed_t baud_rate;#ifdef DEBUG fprintf( stderr, "opening %s\n", device );#endif switch( baud_i ) { case 110: baud_rate = B110; char_interval_timeout = TO_B110; break; case 300: baud_rate = B300; char_interval_timeout = TO_B300; break; case 600: baud_rate = B600; char_interval_timeout = TO_B600; break; case 1200: baud_rate = B1200; char_interval_timeout = TO_B1200; break; case 2400: baud_rate = B2400; char_interval_timeout = TO_B2400; break; case 4800: baud_rate = B4800; char_interval_timeout = TO_B4800; break; case 9600: case 0: baud_rate = B9600; char_interval_timeout = TO_B9600; break; case 19200: baud_rate = B19200; char_interval_timeout = TO_B19200; break; case 38400: baud_rate = B38400; char_interval_timeout = TO_B38400; break; case 57600: baud_rate = B57600; char_interval_timeout = TO_B57600; break; case 115200: baud_rate = B115200; char_interval_timeout = TO_B115200; break; default: baud_rate = B9600; char_interval_timeout = TO_B9600; fprintf(stderr, "Unknown baud rate %d for %s.", baud_i, device); } if(( ttyfd = open( device,O_RDWR) ) < 0 ) { fprintf( stderr, "Error opening device %s. ", device ); fprintf( stderr, "Error no. %d \n",errno ); exit( 1 ); /* stop the program. This maybe should */ /* be a bit kinder but will do for now.*/ }#ifdef DEBUG fprintf( stderr, "%s open\n", device );#endif /* read your man page for the meaning of all this. # man termios */ /* Its a bit to involved to comment here */ cfsetispeed( &settings, baud_rate );/* Set the baud rate */ cfsetospeed( &settings, baud_rate ); settings.c_line = 0; settings.c_iflag |= IGNBRK; settings.c_iflag |= IGNPAR; settings.c_iflag &=~ PARMRK; settings.c_iflag &=~ INPCK; settings.c_iflag &=~ ISTRIP; settings.c_iflag &=~ INLCR; settings.c_iflag &=~ IGNCR; settings.c_iflag &=~ ICRNL; settings.c_iflag &=~ IUCLC; settings.c_iflag &=~ IXON; settings.c_iflag |= IXANY; settings.c_iflag &=~ IXOFF; settings.c_iflag &=~ IMAXBEL; settings.c_oflag |= OPOST; settings.c_oflag &=~ OLCUC; settings.c_oflag &=~ ONLCR; settings.c_oflag &=~ OCRNL; settings.c_oflag |= ONOCR; settings.c_oflag &=~ ONLRET; settings.c_oflag &=~ OFILL; settings.c_oflag &=~ OFDEL; settings.c_cflag &=~ CSIZE; settings.c_cflag |= CS8; settings.c_cflag &=~ CSTOPB; settings.c_cflag |= CREAD; if( strncmp( parity, "none", 4 ) == 0 ) { settings.c_cflag &=~ PARENB; settings.c_cflag &=~ PARODD; } else if( strncmp( parity, "even", 4 ) == 0 ) { settings.c_cflag |= PARENB; settings.c_cflag &=~ PARODD; } else { settings.c_cflag |= PARENB; settings.c_cflag |= PARODD; } settings.c_cflag &=~ HUPCL; settings.c_cflag |= CLOCAL; settings.c_cflag &=~ CRTSCTS; settings.c_lflag &=~ ISIG; settings.c_lflag &=~ ICANON; settings.c_lflag &=~ ECHO; settings.c_lflag |= IEXTEN; settings.c_cc[VMIN] = 0; settings.c_cc[VTIME] = 0; if( tcsetattr( ttyfd, TCSANOW, &settings ) < 0 ) { fprintf( stderr, "tcsetattr failed\n"); exit( 1 ); } return( ttyfd );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -