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

📄 mssmartstar.c

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


MSSmartStar.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 SmartStar expandable system.
				
					This sample will allow control via a Modbus Master controller
					of the following;
					
					1. Relay output card
					1. Digital I/O card
					1. Analog input card (0-10VDC was used). 
						(Will read both RAW data and Calibrated VDC data.)
					
					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          

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

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

// This sets up the individual card locations, for this sample.  Put the
// slot number next to the corresponding macro.

// Relay card location

#define	RELAY_SLOT			1

// Digital IO card location

// this was setup using a single card with 16 inputs and 8 outputs, so the
// slot number will be the same for both.
#define	INPUT_SLOT			2
#define	OUTPUT_SLOT			2

// Analog input card location

#define	ADC_SLOT				0

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

// Number of analog inputs on that slot
#define	ADC_AMOUNT			10

// Number of relay outputs
#define	RELAY_AMOUNT		8

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

// This sets up the MODBUS address.  It MUST be unique from any other modbus
// device that is on the bus.
#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	DINBUFSIZE	31
#define	DOUTBUFSIZE	31

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

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

/*

/*=========================================================================*\
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.

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

int msDinit(unsigned qBaud)
{
	// Open the serial port.  THIS MUST BE DONE PRIOR TO SETTING THE  
	// DATA BITS AND PARITY SETTINGS.

	serDopen(qBaud);

	// setup parity.  Either PARAM_OPARITY, PARAM_EPARITY, PARAM_NOPARITY,
	// or PARAM_2STOP

	serDparity(PARAM_EPARITY);

	// setup data bits. Either PARAM_7BIT, or PARAM_8BIT

	serDdatabits(PARAM_8BIT);

  	// Set the Serial port mode. Used for Zworld SBC's only.

	serMode(0);

	return(1);
}

/*=========================================================================*\
msDtx:
	This functions is used for enabling the RS485 transmitter.

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

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

/*=========================================================================*\
msDrx:
	This functions is used for disabling the RS485 transmitter.

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

void msDrx()
{	
	// 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 (serDwrUsed() || BitRdPortI(SDSR,2) || BitRdPortI(SDSR,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.
	serDrdFlush();	 
}

/*=========================================================================*\
	msOutRd:	(01  Coil Status)
		Used for reading output coil status.  A user defined shadow register
		is required in your code which will need to be updated when digital/relay
		outputs are toggled. The function below only sends the value, it does
		not update it.
\*=========================================================================*/

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

/*=========================================================================*\
	msOutWr:	(01  Coil Writing)  
		Used for Writing to individual output coils.  This sample sets up
		the first OUTPUT_AMOUNT of coils to be the digital, and the rest
		to be the RELAY_AMOUNT coils.  
\*=========================================================================*/

int msOutWr(unsigned wCoil, int bState)
{
	//  Check to see if a valid output channel is being called.  
	if ( wCoil > (OUTPUT_AMOUNT + RELAY_AMOUNT) )	return MS_BADADDR;
	//  update the shadow used in the msOutRd function.
	acShad[wCoil] = bState;
	// If the Coil is a Digital Output;
	if (wCoil <= OUTPUT_AMOUNT) digOut(ChanAddr(OUTPUT_SLOT,wCoil),bState);
	// If the coil is a Relay Output;
	else  relayOut( ChanAddr(RELAY_SLOT, wCoil - OUTPUT_AMOUNT) ,bState) ;
	
	return 0;
}

/*=========================================================================*\
	msIn:	(02:	Input Status)
		Used for reading the state of the individual digital inputs.    
\*=========================================================================*/

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(ChanAddr(INPUT_SLOT, wCoil));
	return 0;
}

/*=========================================================================*\
	msRead:	(03:	Reading from a Holding Register)  
		Used (in this sample)    
		For reading the individual CALIBRATED value 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 will put the Most 
		Significant word of the float into the odd register, and the least
		significant word into the even register. (ie register 1 and register
		2 will hold the float value of adc input 0, register 3 and 4 will
		hold adc input 1 etc.).  
\*=========================================================================*/

int msRead(unsigned wReg, unsigned *pwValue)
{
	static float calVal;
	static char  cVal[6];
	// 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(ChanAddr(ADC_SLOT, wReg/2));    
		// move the adc float value int a holding array of 4 bytes
		*(float *) & cVal[0] = calVal;
		// copy the first 2 bytes of the holding array into the register value
		*pwValue = *(unsigned int *) &cVal[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 = *(unsigned int *) &cVal[2];	   
	}
	return 0;
}

/*=========================================================================*\
	msWrite:	(03:	Writing to Holding Register)  
		Not used in this sample.   
		This could be used for write to a DAC card channel, much like reading
		from a ADC card channel shown in msRead.
		
\*=========================================================================*/

nodebug
int msWrite(unsigned wReg, unsigned wValue)
{
	// Place code here.
	return 0;
}

/*=========================================================================*\
	msInput:	(04:	Input Register)
		Used (in this sample)
		For reading the individual RAW DATA of each adc input.  
\*=========================================================================*/

int msInput(unsigned wReg, unsigned *pwValue)
{
	if ( wReg > ADC_AMOUNT )return MS_BADADDR;
	// move the analog value into the register.
	*pwValue = anaIn(ChanAddr(ADC_SLOT, wReg));	
	return 0;
}

void main(void)
{
	auto int loop;
	
	// Clear the output shadow array at startup of this sample
	memset(acShad, 0, sizeof(acShad));	
	
	// initialize the SBC
	brdInit();
#if	(!MODBUS_TYPE)	 
	// Open Serial port D in ASCII mode 
	msaDinit(SLAVE_ADDRESS, MODBUS_BAUDRATE);
#else
	// Open Serial port D in RTU mode
	msrDinit(SLAVE_ADDRESS, MODBUS_BAUDRATE);  
#endif
	// If there are analog inputs required, get the cal. constants from the
	// eeprom.
	
	if (ADC_AMOUNT > 0)
	{
		for (loop = 0 ; loop < ADC_AMOUNT ; loop++)
			// read in the cal. constants.
			anaInEERd(ChanAddr(ADC_SLOT, loop));      
	}
	
	for( ;; )								
	{
		// This is the Modbus slave handler.
		msRun();
		
		//	Other Costates Here!!! (Make sure your code does not block.)
	}
}

⌨️ 快捷键说明

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