📄 mslp35xx.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 + -