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

📄 mslp35xx.c

📁 modbus 运用事例
💻 C
字号:
/********* Sample Program ****************************************************


MSLP35xx.c	Copyright(c) 2003 Z-World Engineering.
					
Legal Notice	This program has been written by the Technical Support Staff at 
					Z-World in response to several customer requests.  As such, it 
					has NOT had the testing and validation procedures which our 
					"standard" software products have.  It is being made available 
					as a sample.  There is no warranty, implied or otherwise. 

DESCRIPTION:	Sample program demonstrating modbus slave control via RS485
					for the LP35xx SBC's (serial port F).
				
					This sample will allow control via a Modbus Master controller
					of the following;
					
					1. Read from/Write to  digital outputs
					2.	Read the status of digital inputs 
					3. Read the Analog inputs (Cal. Data).

MODBUS
COMMAND 
FUNCTIONS
USED:				
					01:	Discrete Coil Status
					01:	Discrete Coil Writing
					02:	Discrete Input Status
					03:	Holding Register Status
					03:	Holding Register Writing
					04:	Input Register Status
					 
					The modbus master software used with this sample can be 
					downloaded (Demo Version) via the following company link.
					
					WinTECH Software Systems incorporated
					
					http://www.win-tech.com
					(modscan32.exe)
					
NOTES:			This sample does show 1 technique on how to convert float
					values (in this case the analog channel values), to unsigned
					int register pairs for use with the Modbus master.
					          

*****************************************************************************/

/******   Start of user configurable macros *********************************/

// Define the number of channels for each type of input

// Number of analog inputs.
#define	ADC_AMOUNT			8
#define	ADC_GAINCODE		0



// Number of digitial I/O
#define	INPUT_AMOUNT		16
#define	OUTPUT_AMOUNT		10

// Provide an ID for the slave device.  It MUST BE UNIQUE from any other 
// Modbus device connected. (Address 0 is the Master device).
#define	SLAVE_ADDRESS		0x01

// The baudrate used for the MODBUS protocol.
#define	MODBUS_BAUDRATE	9600	// 9600 is default, 19200 works to.

// Choose the protocol type, 0 for ASCII, 1 for RTU.  This MUST match the
// Modbus master protocol selection.
#define	MODBUS_TYPE			1	

/******  Done with user configurable macros *********************************/

// Setup up the serial port buffer size
#define	FINBUFSIZE	31
#define	FOUTBUFSIZE	31

// Modbus slave library, it also calls ms_rab.lib
#use		"msz_rab.lib"

//	Digital Output Shadow Registers
char 		acShad[OUTPUT_AMOUNT + 1];
//	Analog Output Shadow Registers

/************************ MODBUS FUNCTIONS *********************************\

The following are the individual Modbus functions.  The function Names must
stay the same for they are used in the ms_rab.lib.  The content of the
function will change for each application.  The following functions are
required to be in you application;

msDone, msStart, and msRun  

msXinit, msXrx, msXtx (X = A,B,C,D,E or F for the serial port you are using).


/***************************************************************************/

/*=========================================================================*\
msDone:

	Called just after a received Modbus command has been
	processed and just before the reply is sent. This function is intended
	to be used to unlock resources that were locked by msStart(). Locking
	resources may or may not be required, depending on how the msIn(),
	msInput(), msOutRd() and msOutWr() functions are implemented in a
	particular Modbus slave application. Note that Modbus command handler
	functions in MS_RAB.LIB may make multiple calls to those functions while
	responding to a single Modbus command.
	
\*=========================================================================*/
		
nodebug
void msDone(void)
{
	// place any locked resources required.
	 
}

/*=========================================================================*\
msStart:

	Called just before a received Modbus packet is processed,
	this function is primarily intended to be used to lock resources so
	that data returned in one Modbus response packet are atomic. Locking
	resources may or may not be required, depending on how the msIn(),
	msInput(), msOutRd() and msOutWr() functions are implemented in a
	particular Modbus slave application. Note that Modbus command handler
	functions in MS_RAB.LIB may make multiple calls to those functions while
	responding to a single Modbus command.

\*=========================================================================*/

nodebug
void msStart(void)
{
	// place any locked resources required.
	
}


/*=========================================================================*\
msDinit:
	Sets up and opens the serial port.  default settings are 8 data bits
	1 stop bit, no parity, no flow control.  You can change the settings 
	to match the Modbus serial control of your system.

\*=========================================================================*/

int msFinit(unsigned qBaud)
{
	// Open the serial port.  THIS MUST BE DONE PRIOR TO SETTING THE
	// DATA BITS AND PARITY SETTINGS.
	serFopen(qBaud); 
	  
	// setup parity.  Either PARAM_OPARITY, PARAM_EPARITY, PARAM_NOPARITY, 
	// or PARAM_2STOP  
	serFparity(PARAM_NOPARITY);
	 
	// setup data bits. Either PARAM_7BIT, or PARAM_8BIT  
	serFdatabits(PARAM_8BIT);
	
  	// Set the Serial port mode. Used for Zworld SBC's only.  
	serMode(0);  
	return(1);
}

/*=========================================================================*\
msDtx:
	User definable function for enabling the rs485 transmitter (if needed).
	If you are doing RS232 simply leave the function blank.  The function
	itself must be present.

\*=========================================================================*/

void msFtx()
{
	// Turn on the transmitter. 
	ser485Tx();
}

/*=========================================================================*\
msDrx:
	User definable function for disabling the rs485 transmitter (if needed).
	If you are doing RS232 simply leave the function blank. The function  
	itself must be present.

\*=========================================================================*/

void msFrx()
{	
	// Make sure all of the data has been sent by;
	// 1.) checking the write buffer for any bytes left
	// 2.) checking the status of the Write interrupt transmit bit (2).
	// 3.) checking the status of the Write interrupt data bit (3)
	while (serFwrUsed() || BitRdPortI(SFSR,2) || BitRdPortI(SFSR,3)); 
	// turn off the transmitter
	ser485Rx();
	// Since we echo what we send, flush the read buffer, so that you are
	// ready for the next packet.
	serFrdFlush();	 
}

/*=========================================================================*\
	msOutRd:	(01:   Discrete Coil Status)
	
		Used for reading output coil status.  A user defined shadow register
		is required in your code which will  be updated when digital
		outputs change states using the msOutWr function.
		
		registers used;    
			0x00001 -> 	0x00016 	Digital Output 0 -> Digital Output 9    
		    
\*=========================================================================*/

int msOutRd(unsigned wCoil, int *pnState)
{
	//  Check to see if a valid output channel is being called.
	if (wCoil > (OUTPUT_AMOUNT) )	return MS_BADADDR;
	// copy the contents of the coil shadow element.
	*pnState = acShad[wCoil];
	return 0;
}

/*=========================================================================*\
	msOutWr:	(01:  Discrete Coil Writing)  
		Used for Writing to individual output coils, as well as updating
		the shadow register used in the above function msOutRd. 
		 
		registers used;
			0x00001 -> 	0x00016 (Digital Output 0 -> Digital Output 9)    
		 
\*=========================================================================*/

int msOutWr(unsigned wCoil, int bState)
{
	//  Check to see if a valid output channel is being called.  
	if ( wCoil > (OUTPUT_AMOUNT) )	return MS_BADADDR;
	//  update the shadow used in the msOutRd function.
	acShad[wCoil] = bState;
	// Update the digital outpu;
	digOut(wCoil,bState);
	return 0;
}

/*=========================================================================*\
	msIn:	(02:	Discrete Input Status)
		Used for reading the state of the individual digital inputs.
		
	  registers used;	   
	 		0x10001 -> 	0x10024 (Digital Input 0 -> Digital Input 15) 
	 			   
\*=========================================================================*/

int msIn(unsigned wCoil, int *pnState)
{
	//  Check to see if a valid input channel is being called.    
	if (wCoil > INPUT_AMOUNT)	return MS_BADADDR;
	//  Read the input and store it.
	*pnState = digIn(wCoil);
	return 0;
}

/*=========================================================================*\
	msInput:	(04:	Reading from a Input Register)  
		   
		Setup to read the individual CALIBRATED values of each adc inputs.
		Since Modbus deals with unsigned ints (words), and our VDC input
		function returns a float, the function will need to store the value
		as two registers type casted into unsigned ints for the Modbus 
		protocol to accept properly.  How this is done must be the same for
		both the Master and the slave.  This example shows one way to 
		accomplish that.  The Master must use the same method for decoding
		the two unsigned ints and convert it back to a float.  A sample of
		this is the msWrite function that converts 2 unsigned ints into a
		float for use with the DAC outputs.
		
		registers used;
		  	0x30001 -> 0x30002 = Float val of ADC 0    
			0x30003 -> 0x30004 = Float val of ADC 1  
			0x30005 -> 0x30006 = Float val of ADC 2  
			0x30007 -> 0x30008 = Float val of ADC 3  
			0x30009 -> 0x30010 = Float val of ADC 4    
			0x30011 -> 0x30012 = Float val of ADC 5  
			0x30013 -> 0x30014 = Float val of ADC 6  
			0x30015 -> 0x30016 = Float val of ADC 7  

\*=========================================================================*/

int msInput(unsigned wReg, unsigned *pwValue)
{
	static float calVal;
	static unsigned int  uiVal[2];
	// Since it will take two registers per input, you must double the 
	// amount of register neccessary.
	if (wReg > (ADC_AMOUNT * 2) )	return MS_BADADDR;
	
	// if the input is odd the get the new adc value
	if ( !(wReg % 2) )
	{
  		// You must divide the wReg value by 2 when getting the proper channel	
		calVal = anaInVolts(wReg/2,ADC_GAINCODE);    
		// move the adc float value int a holding array of 4 bytes
		*(float *) & uiVal[0] = calVal;
		// copy the first 2 bytes of the holding array into the register value
		*pwValue = uiVal[0];    
	}
	// if the register is even
	else
	{
		// copy the last 2 bytes of the holding array into the register value.
		// DO NOT recalculate the input value.
		*pwValue = uiVal[1];	   
	}
	return 0;
}

/******************* End of Modbus Functions  ******************************/


/******************* Main Function *****************************************\

	Basic setup of the controller.  Once Modbus is setup, a call to msRun()
	needs to be called continually called.  Other functionalities can be
	added as long as they do not block. (i.e while loops for loops etc.).

\***************************************************************************/

void main(void)
{
	auto int loop;
	// Clear the output shadow arrays at startup of this sample
	memset(acShad, 0, sizeof(acShad));	
		  
	// initialize the SBC
	brdInit();
	devPowerSet(RS485DEV, 1);   
	
#if	(!MODBUS_TYPE)	 
	// Open Serial port D in ASCII mode 
	msaFinit(SLAVE_ADDRESS, MODBUS_BAUDRATE);
#else
	// Open Serial port D in RTU mode
	msrFinit(SLAVE_ADDRESS, MODBUS_BAUDRATE);  
#endif
	// If there are analog outputs required, get the cal. constants from the  
	// eeprom.
 	for( ;; )								
	{
 		// Modbus slave handler function.  It must be in a continous loop.
		msRun();     
		//	Other Costates Here!!! (Make sure your code does not block.)
	}
}

⌨️ 快捷键说明

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