⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 modbus_rtu.c

📁 linux下的modbus协议,很好用,欢迎大家下载,在国外网站上获得的
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 		modbus_rtu.c    By P.Costigan email: phil@pcscada.com.au http://pcscada.com.au   These library of functions are designed to enable a program send and   receive data from a device that communicates using the Modbus protocol.   Copyright (C) 2000 Philip Costigan  P.C. SCADA LINK PTY. LTD.   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2 of the License, or   (at your option) any later version.   This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.   You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   The functions included here have been derived from the    Modicon Modbus Protocol Reference Guide   which can be obtained from Schneider at www.schneiderautomation.com.   This code has its origins with    paul@pmcrae.freeserve.co.uk (http://www.pmcrae.freeserve.co.uk)   who wrote a small program to read 100 registers from a modbus slave.      I have used his code as a catalist to produce this more functional set   of functions. Thanks paul.*/#include <fcntl.h>	/* File control definitions */#include <stdio.h>	/* Standard input/output */#include <string.h>#include <stdlib.h>#include <termio.h>	/* POSIX terminal control definitions */#include <sys/time.h>	/* Time structures for select() */#include <unistd.h>	/* POSIX Symbolic Constants */#include <errno.h>	/* Error definitions */#include "modbus_rtu.h"//#define DEBUG		/* uncomment to see the data sent and received */int char_interval_timeout;/*************************************************************************   modbus_query( packet, length)Function to add a checksum to the end of a packet.Please note that the packet array must be at least 2 fields longer thanstring_length.**************************************************************************/void modbus_query( unsigned char *packet , size_t string_length ){	int temp_crc;	/* declaration */	unsigned int crc(unsigned char buf[],int start,int cnt);	temp_crc = crc( packet, 0, string_length );		packet[ string_length++ ] = temp_crc >> 8;	packet[ string_length++ ] = temp_crc & 0x00FF;	packet[ string_length ] = 0;	}/***********************************************************************   send_query( file_descriptor, query_string, query_length )Function to send a query out to a modbus slave.************************************************************************/int send_query( int ttyfd, unsigned char *query, size_t string_length ){	int write_stat;#ifdef DEBUG	int i;#endif	modbus_query( query, string_length );	string_length += 2; 	#ifdef DEBUG// Print to stderr the hex value of each character that is about to be// sent to the modbus slave.	for( i = 0; i < string_length; i++ )	{		fprintf( stderr, "[%0.2X]", query[ i ] );	}	fprintf( stderr, "\n" );#endif	tcflush( ttyfd, TCIOFLUSH );	/* flush the input & output streams */		write_stat = write( ttyfd, query, string_length );	tcflush( ttyfd, TCIFLUSH );	/* maybe not neccesary */	return( write_stat );}/*********************************************************************	modbus_response( response_data_array, query_array )   Function to the correct response is returned and that the checksum   is correct.   Returns:	string_length if OK		0 if failed		Less than 0 for exception errors	Note: All functions used for sending or receiving data via	      modbus return these return values.**********************************************************************/int modbus_response( unsigned char *data, unsigned char *query, int fd ){	int response_length;	unsigned short crc_calc = 0;	unsigned short crc_received = 0;	unsigned char recv_crc_hi;	unsigned char recv_crc_lo;	/* local declaration */	int receive_response( unsigned char *received_string, int ttyfd );	unsigned int crc(unsigned char buf[],int start,int cnt);	response_length = receive_response( data, fd );	if( response_length )	{		crc_calc = crc( data, 0, response_length - 2 );			recv_crc_hi = (unsigned) data[ response_length - 2 ];		recv_crc_lo = (unsigned) data[ response_length - 1 ];		crc_received = data[ response_length - 2 ];		crc_received = (unsigned) crc_received << 8;		crc_received = 		      crc_received |(unsigned)data[response_length -1];		/*********** check CRC of response ************/		if (crc_calc != crc_received)		{			fprintf( stderr, "crc error received ");			fprintf( stderr, "%0X - ", crc_received);			fprintf( stderr, "crc_calc %0X\n",crc_calc);					response_length = 0;				}						/********** check for exception response *****/		if( response_length && data[ 1 ] != query [ 1 ] )		{			response_length = 0 - data[ 2 ];		}	}	return( response_length );}/***********************************************************************	receive_response( array_for_data )   Function to monitor for the reply from the modbus slave.   This function blocks for timeout seconds if there is no reply.   Returns:	Total number of characters received.***********************************************************************/int receive_response(  unsigned char *received_string, int ttyfd ){	int rxchar = PORT_FAILURE;	int data_avail = FALSE;	int bytes_received = 0;	int read_stat;	int timeout = 1;			/* 1 second */	fd_set rfds;	struct timeval tv;	tv.tv_sec = timeout;	tv.tv_usec = 0;	FD_ZERO( &rfds );	FD_SET( ttyfd, &rfds );#ifdef DEBUG	fprintf( stderr, "Waiting for response.\n");#endif		/* wait for a response */	data_avail = select( FD_SETSIZE, &rfds, NULL, NULL, &tv );	if( !data_avail )	{		bytes_received = 0; 		fprintf( stderr, "Comms time out\n" );	}	tv.tv_sec = 0;	tv.tv_usec = char_interval_timeout;	FD_ZERO( &rfds );	FD_SET( ttyfd, &rfds );		while( data_avail )	{		/* if no character at the buffer wait char_interval_timeout */		/* before accepting end of response			    */		if( select( FD_SETSIZE, &rfds, NULL, NULL, &tv ) )		{			read_stat = read( ttyfd, &rxchar, 1 );			if( read_stat < 0 )			{				bytes_received = PORT_FAILURE;				data_avail = FALSE;			}			else			{				rxchar = rxchar & 0xFF;				received_string[ bytes_received ++ ] = rxchar;			}			if( bytes_received >= MAX_RESPONSE_LENGTH )			{				bytes_received = PORT_FAILURE;				data_avail = FALSE;			}#ifdef DEBUG			/* display the hex code of each character received */			fprintf( stderr, "<%0.2X>", rxchar );#endif		}		else		{			data_avail = FALSE;		}	}	#ifdef DEBUG	fprintf( stderr, "\n" );#endif	if( bytes_received > 2 )	{		bytes_received -= 2;	}	return( bytes_received );}/***********************************************************************	The following functions construct the required query into	a modbus query packet.***********************************************************************/#define REQUEST_QUERY_SIZE 6	/* the following packets require          */#define CHECKSUM_SIZE 2		/* 6 unsigned chars for the packet plus   */				/* 2 for the checksum.                    */void build_request_packet( int slave, int function, int start_addr,			   int count, unsigned char *packet ){	packet[ 0 ] = slave,	packet[ 1 ] = function;	start_addr -= 1;	packet[ 2 ] = start_addr >> 8;	packet[ 3 ] = start_addr & 0x00ff;	packet[ 4 ] = count >> 8;	packet[ 5 ] = count &0x00ff;}/************************************************************************	read_IO_status	read_coil_stat_query and read_coil_stat_response interigate	a modbus slave to get coil status. An array of coils shall be	set to TRUE or FALSE according to the response from the slave.	*************************************************************************/int read_IO_status( int function, int slave, int start_addr, int count, 			    int *dest, int dest_size, int ttyfd ){	/* local declaration */	int read_IO_stat_response( int *dest, int dest_size, int coil_count,					unsigned char *query, int fd );	int status;	unsigned char packet[ REQUEST_QUERY_SIZE + CHECKSUM_SIZE ];	build_request_packet( slave, function, start_addr, count, packet );	if( send_query( ttyfd, packet, REQUEST_QUERY_SIZE ) > -1 )	{		status = read_IO_stat_response( dest, dest_size,						count, packet, ttyfd );	}	else	{		status = PORT_FAILURE;	}	return( status );}/************************************************************************	read_coil_status 	reads the boolean status of coils and sets the array elements	in the destination to TRUE or FALSE*************************************************************************/int read_coil_status( int slave, int start_addr, int count,			  int *dest, int dest_size, int ttyfd ){	int function = 0x01;	int status;	status = read_IO_status( function, slave, start_addr, count, 						dest, dest_size, ttyfd );	return( status );}/************************************************************************	read_input_status	same as read_coil_status but reads the slaves input table.************************************************************************/int read_input_status( int slave, int start_addr, int count,			   int *dest, int dest_size, int ttyfd ){	int function = 0x02;	/* Function: Read Input Status */	int status;	status = read_IO_status( function, slave, start_addr, count,						 dest, dest_size, ttyfd );	return( status );}/**************************************************************************	read_IO_stat_response	this function does the work of setting array elements to TRUE	or FALSE.**************************************************************************/int read_IO_stat_response( int *dest, int dest_size, int coil_count,				unsigned char *query, int fd ){	unsigned char data[ MAX_RESPONSE_LENGTH ];	int raw_response_length;	int temp, i, bit, dest_pos = 0;	int coils_processed = 0;	raw_response_length = modbus_response( data, query, fd );		if( raw_response_length > 0 )	{		for( i = 0; i < ( data[2] ) && i < dest_size; i++ )		{			/* shift reg hi_byte to temp */			temp = data[ 3 + i ] ;			for( bit = 0x01; bit & 0xff && 				coils_processed < coil_count; )			{				if( temp & bit )				{					dest[ dest_pos ] = TRUE;				}				else				{					dest[ dest_pos ] = FALSE;				}				coils_processed++;				dest_pos++;				bit = bit << 1;			}		}	}	return( raw_response_length );}/************************************************************************	read_registers	read the data from a modbus slave and put that data into an array.************************************************************************/int read_registers( int function, int slave, int start_addr, int count, 			  int *dest, int dest_size, int ttyfd ){	/* local declaration */	int read_reg_response( int *dest, int dest_size, 					unsigned char *query, int fd );	int status;	unsigned char packet[ REQUEST_QUERY_SIZE + CHECKSUM_SIZE ];	build_request_packet( slave, function, start_addr, count, packet );	if( send_query( ttyfd, packet, REQUEST_QUERY_SIZE ) > -1 )	{		status = read_reg_response( dest, dest_size, packet, ttyfd );	}	else	{		status = PORT_FAILURE;	}		return( status );}/************************************************************************	read_holding_registers	Read the holding registers in a slave and put the data into	an array.*************************************************************************/int read_holding_registers( int slave, int start_addr, int count,				int *dest, int dest_size, int ttyfd ){	int function = 0x03;    /* Function: Read Holding Registers */	int status;	if( count > MAX_READ_REGS )	{		count = MAX_READ_REGS;#ifdef DEBUG		fprintf( stderr, "Too many registers requested.\n" );#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -