Questions about MODBUS and kflop


Results 1 to 5 of 5

Thread: Questions about MODBUS and kflop

  1. #1
    Registered
    Join Date
    Feb 2016
    Posts
    2
    Downloads
    0
    Uploads
    0

    Default Questions about MODBUS and kflop

    Hi'

    I am working on a kflop install that talks to a koyo PLC using modbus and have some questions .


    I am using the example with the KMotionX github branch under examples/rs232/modbus master ver 1 and it looks good and appears to work. I have about 100 commands a second with no errors.

    Two problems:

    1. Testing with the default commands It appears to work but I can't seem to find the updated status in the kflop getstatus output. I am using coil input 7 with a switch and modified the address to match. Again it appears to work but I can't find the status reflected in getstatus. Is there anywhere that documents what each part of the getstatus output corresponds to? Some of the bits(hex) flip even when nothing is happening.

    2. I noticed the command for moving holding registers into the kflop is not implemented, its a switch that falls through. Only the input coils 0x4 is implemented. Thoughts and suggestions? I would like to use 0x3 for holding registers in Vmemory.

    That should do it.

    Thankyou

    Similar Threads:


  2. #2
    Member
    Join Date
    Jun 2004
    Location
    Scotland
    Posts
    355
    Downloads
    0
    Uploads
    0

    Default Re: Questions about MODBUS and kflop

    I'm sure Tom will likely comment, however Dynomotion is away at the ATX show this week.

    If you want to implement the 0x03 functionality, you need to add it yourself. The example is pretty much a bare bones example, which needs built upon.
    I use it with a Click PLC to control the turret on my lathe, and had to add the 0x03 bit myself, however you also need to add some extra lines to other functions within the file.


    Here's my modified ModBusMasterV1 -
    I can't remember exactly what I added, but it took me much trial and error at the time, and as a result I never fully commented what I did change once I did get it fully working (very poor I know!)
    From a quick look over, I had to change the MonitorList adding the registers I needed, add the required code to RegLoad, RegTransfer, and RegWrite to handle the required data transfers, and add the 0x03 to the ProcessData switch statement.
    You should be able to compare to the original, to see what I had to change/add, and point you in the right direction.
    Code:
    /*
    	ModbusMaster.c
    
    Description:
    
    	This code uses the serial port of the KFlop+KAnalog to connect to the DirectAutomation Koyo Click PLC (C0-00DD1-D)
    	This is a low cost solution to add 8 remote inputs and 6 remote outputs.
    	Virtual bits 48-55 are used for the inputs of the PLC.
    	Virtual bits 56-61 are sent to the outputs of the PLC.
    	It is easy to configure this code to use other virtual bits on the kflop or other memory areas of the PLC.
    	At 38400 baud (fastest allowed on the PLC) the inputs and outputs are read/written at ~40Hz. If you only need just
    		input or just output, ~80hz.
    	Note that the KFlop does not currently support parity. The PLC is connected through its port 2 which is configured
    		to use no parity, 38400 baud, 8 bit data, 1 stop bit.
    	
    	
    Implementation:
    	
    	An array of 16bit registers (MBRegisters) is used to make Modbus commands easier to specify.
    
    	RegLoad() and RegUnload() routines are used to marshal (move and format) data between MBRegisters and
    	KFlop memory.
    
    	There are two lists of PLC commands: Connection and Monitor
    	The connection list is used to read/write one time information, like SW version numbers.
    	The monitor list is used for the continual IO calls.
    	The Connection list is sent and then the Monitor list is looped through forever.
    	A command timeout flags a disconnect, and the very next successful command starts back at the start of the connection list.
    	This allows a PLC to be stopped and restarted or disconnect-reconnect, and the ModbusMaster will reinit.
    	
    	Console printing is designed to display information when anomalies occur, like disconnects or unknown commands.
    	
    Pseudocode for main loop:
    
    	When data will be written to the PLC, call RegLoad to marshal data from KFlop to MBRegisters.
    	Build the command using data from MBRegisters.
    	Send the command.
    	Wait for PLC response.
    		Resend for retryCount times.
    			if failed, then flag disconnect.
    	When the PLC responds, if data is received
    		place read information into MBRegisters and call RegUnload to marshal data to KFlop memory.
    	Move on to the next command in the list.
    
    */
    
    #include "KMotionDef.h"
    
    #include "ModBusMaster_cyclone.h"
    
    unsigned short MBRegisters[N_MB_REGISTERS];
    double delayT = 0;
    double delayT2 = 0;
    
    // Constants
    int ModbusMaster_MaxRetry=3;
    double ModbusMaster_Timeout=0.5; //seconds for no response for a send command
    double ModbusMaster_ResponseTime; //seconds for last PLC response
    double ModbusMaster_CommandSentTime;
    
    // status and performance counters
    double ModbusMaster_MonitorStartTime=0;	// start of most recent monitor cycle
    double ModbusMaster_MonitorCycleTime=0;	// seconds to call all commands in Monitor list
    int ModbusMaster_TallyConnections=0;	// Number of times Connection list has been sent
    int ModbusMaster_TallyCommands=0;	// Commands since connection
    int ModbusMaster_TallyRetries=0;	// Retries since connection
    
    // statuses, counters, etc
    int ModbusMaster_List=0;	// 0=connect, 1=monitor
    int ModbusMaster_Connected=0;
    int ModbusMaster_MonitorIndex=0;
    int ModbusMaster_ConnectIndex=0;
    int ModbusMaster_Idle=0;	// 0=idle, 1=await reply
    int ModbusMaster_Retry=0;
    
    double ModbusMaster_LastInTime=0;
    double ModbusMaster_EndOfPacketWait=3.5*10/9600; // wait 3.5 characters after a packet 9600=baud rate)
    char ModbusMaster_packetBuild[256]; // max length of modbus frame
    int ModbusMaster_packetSize=0;
    
    // Cyclone Addition
    double *TCPosition  = &persist.UserData[TCPOS];
    double *TCDesired = &persist.UserData[TCDES];
    // End Cyclone Addition
    
    typedef enum
    {
    	MBERROR_NONE = 0,
    	// Modbus codes; reported with Modbus error packet
    	MBERROR_ILLEGAL_FUNCTION = 1,
    	MBERROR_ILLEGAL_DATA_ADDRESS = 2,	// used
    	MBERROR_ILLEGAL_DATA_VALUE = 3,	// used
    	MBERROR_SLAVE_DEVICE_FAILURE = 4,
    	MBERROR_ACKNOWLEDGE = 5,
    	MBERROR_SLAVE_DEVICE_BUSY = 6,
    	MBERROR_NEGATIVE_ACKNOWLEDGE = 7,
    	MBERROR_MEMORY_PARITY_ERROR = 8,
    	// internal codes
    	INTERROR_WRONG_DEVICE = 9,
    	INTERROR_CHECKSUM = 10,
    	INTERROR_TIMEOUT = 11,
    } MBErrors;
    
    
    typedef struct ModbusMaster_sCmds
    {
    	char *start; // has "dev,cmd,adrhi,adrlo,lenhi,lenlo" bytes of modbus command. Not data and Not checksum.
    	int len; // length of start string. commonly 6
    	int reg; // reg# is the start index into the MBRegisters array for the command
    } ModbusMaster_Cmds;
    
    ModbusMaster_Cmds *ModbusMaster_SentPtr; // pointer to current command. used to send, resend, interpret response.
    
    ModbusMaster_Cmds ModbusMaster_ConnectList[] =
    {
    	// string is "dev,cmd,adrhi,adrlo,lenhi,lenlo" bytes of modbus command. bytelen, data, and checksum are added.
    	{"\x01\x04\xF0\x00\x00\x10", 6, 2},	// Collect PLC firmware info block MBRegisters[10] for 16 registers
    	{0,0,0}	// end flag
    };
    
    ModbusMaster_Cmds ModbusMaster_MonitorList[] =
    {
    	// string is "dev,cmd,adrhi,adrlo,lenhi,lenlo" bytes of modbus command. bytelen, data, and checksum are added as necessary.
    	{"\x01\x04\xE0\x00\x00\x01", 6, 0},	// Read inputs to MBRegisters[0]
    	{"\x01\x10\xE2\x00\x00\x01", 6, 1},	// Write outputs from MBRegisters[1]
    	{"\x01\x03\x00\x00\x00\x01", 6, 2},	// Read DS1 (???)
    	{"\x01\x10\x00\x01\x00\x01", 6, 3},	// Write DS2 (???)
    	{0,0,0}	// end flag
    };
    
    void ModbusMaster_Init()
    {
    	printf("\nModbus Master Init\n");
    	EnableRS232Cmds(RS232_BAUD_38400);
    	DoRS232Cmds = FALSE;  // turn off processing RS232 input as commands
    	ModbusMaster_LastInTime=Time_sec();
    	ModbusMaster_EndOfPacketWait=3.5*10.0/38400; // wait 3.5 characters after a packet
    	ModbusMaster_packetSize=0;
    	
    	ModbusMaster_Idle=0;
    	ModbusMaster_SentPtr=&ModbusMaster_ConnectList[0];
    
    	int c;
    	for (c=0;c<N_MB_REGISTERS;c++)
    		MBRegisters[c]=0;
    		
    	// make the register static arrays available to the other threads
    	persist.UserData[PERSIST_MBREG_BLOCK_ADR]=(int)MBRegisters;
    	//d printf("persist.UserData[%d]<=%08X\n",PERSIST_RWREG_BLOCK_ADR,MBRWRegisters); //debug
    }
    
    char* strncpy(char *dst,char* src,int len)
    {
    	int i;
    	for (i=0;i<len;i++)
    		dst[i]=src[i];
    	return dst;
    }
    
    // marshal and move values read from PLC/Slave into MBRegisters to KFlop memory
    void ModbusMaster_RegUnload()
    {
    	// Move 8 PLC inputs to virtual bits via MBRegisters[0]
    	// Note use SetStateBit which is Atomic and Thread Safe
    	
    	int i;
    	/*if(delayT2 < Time_sec()) // anything in here only gets handled once every tDelay seconds
    		{
    	delayT2 = Time_sec()+2;
    		//printf("Input dump%d\n", MBRegisters[0]);
    	if(MBRegisters[0] & 32){
    		//printf("&32Door Closed\n");
    	}
    	if(MBRegisters[0] & 64){
    		//printf("&64Lube Low\n");
    	}
    	}
    	for (i=0; i<8; i++)
    		SetStateBit(48+i,(MBRegisters[0]>>i)&1);  // 8 input bits */
    }
    
    // marshal and move values to be sent to PLC/Slave into MBRegisters
    void ModbusMaster_RegLoad()
    {
    	// Move 6 virtual bits to PLC outputs via MBRegisters[1]
    	MBRegisters[1] = (VirtualBits>>8)&0x3F;	// the six bits after the 8 input bits
    	int tcd = *TCDesired;
    	MBRegisters[3] = *TCDesired;
    	if(delayT < Time_sec()) // anything in here only gets handled once every tDelay seconds
    	{
    		printf("Desired-%d\n",tcd);
    		delayT = Time_sec()+2;
    	}
    }
    
    void ModbusMaster_RegTransfer()
    {
    	int tc = MBRegisters[2];
    	*TCPosition = tc;
    	if(delayT < Time_sec()) // anything in here only gets handled once every tDelay seconds
    	{
    		//printf("CLICK Register-%d\n",tc);
    		//delayT = Time_sec()+2;
    	}
    }
    
    void ModbusMaster_RegWrite()
    {
    	//MBRegisters[3] = persist.UserData[12];
    	MBRegisters[3] = 0x06;
    }
    
    static unsigned char auchCRCHi[] = {
    	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
    	0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    	0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
    	0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
    	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
    	0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
    	0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
    	0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
    	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
    	0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    	0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
    	0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    	0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
    	0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
    	0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
    	0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
    	0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
    	0x40
    } ;
    
    static char auchCRCLo[] = {
    	0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
    	0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
    	0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
    	0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
    	0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
    	0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
    	0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
    	0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
    	0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
    	0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
    	0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
    	0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
    	0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
    	0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
    	0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
    	0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
    	0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
    	0x40
    } ;
    
    
    unsigned short CRC16(unsigned char *puchMsg,unsigned short usDataLen)
    {
    	unsigned char uchCRCHi = 0xff;
    	unsigned char uchCRCLo = 0xff;
    	unsigned int uIndex;
    	while(usDataLen--)
    	{
    		uIndex = uchCRCLo ^ *puchMsg++;
    		uchCRCLo = uchCRCHi ^ auchCRCHi[uIndex];
    		uchCRCHi = auchCRCLo[uIndex];
    	}
    	return (uchCRCHi<<8|uchCRCLo);
    }
    
    void ModbusMaster_NextCmd(MBErrors ecode)
    {
    	if (ecode) printf("ModbusMaster_NextCmd(%d)\n",ecode); //debug
    	ModbusMaster_Idle=0; // ready to send a new command
    	if (INTERROR_TIMEOUT==ecode)
    	{
    		if (ModbusMaster_List)
    			ModbusMaster_Connected=0;
    	}
    	if (ModbusMaster_List)
    	{
    		ModbusMaster_MonitorIndex++;
    		if (!ModbusMaster_MonitorList[ModbusMaster_MonitorIndex].start)
    		{
    			ModbusMaster_MonitorIndex=0;
    			ModbusMaster_MonitorCycleTime=Time_sec()-ModbusMaster_MonitorStartTime;
    			ModbusMaster_MonitorStartTime=Time_sec();
    		}
    	}
    	else
    	{
    		ModbusMaster_ConnectIndex++;
    		if (!ModbusMaster_ConnectList[ModbusMaster_ConnectIndex].start)
    			ModbusMaster_List=1;	// continue monitor list, do not restart here
    	}
    	if (INTERROR_TIMEOUT!=ecode&&0==ModbusMaster_Connected)
    	{
    		ModbusMaster_Connected=1;
    		ModbusMaster_List=0;
    		ModbusMaster_ConnectIndex=0;
    
    		ModbusMaster_TallyConnections++;
    		ModbusMaster_TallyCommands=0;
    		ModbusMaster_TallyRetries=0;
    	}
    
    	if (!ModbusMaster_List)
    		ModbusMaster_SentPtr=&ModbusMaster_ConnectList[ModbusMaster_ConnectIndex];
    	else
    		ModbusMaster_SentPtr=&ModbusMaster_MonitorList[ModbusMaster_MonitorIndex];
    }
    
    void ModbusMaster_Send(int verbose)
    {
    	// send the command currently pointed to by ModbusMaster_SentPtr
    	//	printf("ModbusMaster_Send(%d)\n",verbose);
    	
    	char *chp;
    	int x;
    	unsigned char *xp;
    
    	if (!ModbusMaster_List)
    		printf("List:%d ConnectIndex:%d MonitorIndex:%d\n",
    				ModbusMaster_List,ModbusMaster_ConnectIndex,ModbusMaster_MonitorIndex);
    
    	if (!ModbusMaster_SentPtr->start)
    	{
    		printf("ModbusMaster_Send: Tried to execute at end list\n");
    		ModbusMaster_NextCmd(MBERROR_NONE);
    	}
    		
    	strncpy(ModbusMaster_packetBuild,ModbusMaster_SentPtr->start,ModbusMaster_SentPtr->len);
    	chp=&ModbusMaster_packetBuild[ModbusMaster_SentPtr->len];
    	switch(ModbusMaster_packetBuild[1])
    	{
    		case 0x10: // RW Write
    			ModbusMaster_RegLoad();
    			*chp++=ModbusMaster_packetBuild[5]*2;
    			for (x=0;x<ModbusMaster_packetBuild[5];x++)
    			{
    				*chp++=(MBRegisters[x+ModbusMaster_SentPtr->reg]>>8)&0xFF;
    				*chp++=MBRegisters[x+ModbusMaster_SentPtr->reg]&0xFF;
    			}
    			break;
    		case 0x02: // Bit Read
    		case 0x03:	// RO Read
    		case 0x04: // RW Read
    			break;
    		default:
    			printf("Unexpected default: ModbusMaster_Send(), Function %d\n",ModbusMaster_packetBuild[1]); //debug
    			break;
    	}
    	int csum=CRC16(ModbusMaster_packetBuild,chp-ModbusMaster_packetBuild);
    	*chp++=csum&0xFF;
    	*chp++=(csum>>8)&0xFF;
    
    	if (verbose) printf("Tx:"); //debug
    	for (xp=ModbusMaster_packetBuild;xp<chp;xp++)
    	{
    		RS232_PutChar(*xp);
    		if (verbose) printf("%02x;",*xp); //debug
    	}
    	if (verbose) printf("\n"); //debug
    	
    	ModbusMaster_LastInTime=Time_sec();
    	ModbusMaster_Idle=1;
    }
    
    MBErrors Process_Data(unsigned char *Buffer, unsigned char Count)
    {
    	int regndx;
    	int cnt;
    	int x;
    	unsigned short CRC = (((Buffer[Count-1]<<8)&0xFF00)|(Buffer[Count-2]&0xFF));	// Received CRC
    	unsigned short Recalculated_CRC = CRC16(Buffer,Count-2);	// Computed CRC
    	if(Recalculated_CRC != CRC)
    	{
    		printf("Count %d\n",Count);
    		printf("Checksum: Theirs:%04X Mine:%04X, %d chars\n",CRC,Recalculated_CRC,Count); //debug
    		return INTERROR_CHECKSUM;
    	}
    
    	//d printf("Packet %d\n",Function);    //debug
    
    	switch(Buffer[1])
    	{
    		case 0x02:
    			//ModbusMaster_BitUnload();
    			break;
    		case 0x03:
    			//printf((int)Buffer[3]);
    			//printf("Buffers-",Buffer[2]);
    			cnt=Buffer[2];
    			//printf("Buffers-%d\n",cnt);
    			//MBRegisters[2]=Buffer[4];
    			MBRegisters[2]=((Buffer[3]<<8)&0xFF00)|(Buffer[4]&0x00FF);
    			//printf("Register-%d\n",MBRegisters[2]);
    			ModbusMaster_RegTransfer();
    			break;
    		case 0x04:
    			regndx=ModbusMaster_SentPtr->reg;
    			cnt=Buffer[2];
    			//printf("Buffers-%d\n",cnt);
    			//printf(cnt);
    			for (x=0;x<cnt;x+=2)
    				MBRegisters[regndx++]=((Buffer[3+x]<<8)&0xFF00)|(Buffer[4+x]&0x00FF);
    			//printf(MBRegisters[1]);
    			ModbusMaster_RegUnload();
    			break;
    		case 0x10:
    			// no action on successful write
    			break;
    		default:
    			printf("Unexpected default: Process_Data(), Buffer[1]=%d\n",Buffer[1]);
    			break;
    	}
    	
    	return MBERROR_NONE;	//We made it to the end, return
    }
    
    
    
    void ModbusMaster_Monitor()
    {
    	char c;
    
    	if (pRS232RecIn != pRS232RecOut)
    	{
    		ModbusMaster_LastInTime=Time_sec();
    		while (pRS232RecIn != pRS232RecOut) // data in buffer
    		{
    			c=RS232_GetChar();
    			if (ModbusMaster_packetSize<255)
    				ModbusMaster_packetBuild[ModbusMaster_packetSize++]=c;
    			//d printf("%02x,",c&0xFF); //debug
    		}
    	}
    	else
    	{
    		if (ModbusMaster_LastInTime+ModbusMaster_EndOfPacketWait<Time_sec() && ModbusMaster_packetSize)
    		{
    			int rtrn=Process_Data(ModbusMaster_packetBuild,ModbusMaster_packetSize);
    			ModbusMaster_packetSize=0;	// ready for next packet
    			if (!rtrn)
    			{
    				ModbusMaster_TallyCommands++;
    				ModbusMaster_NextCmd(rtrn);
    				return;
    			}
    			printf("Error=%d, %f\n",rtrn,ModbusMaster_LastInTime+ModbusMaster_EndOfPacketWait-Time_sec());	//debug
    			//d printf("\n",c);	//debug
    		}
    		if (ModbusMaster_LastInTime+ModbusMaster_Timeout<Time_sec())	// retry test
    		{
    			ModbusMaster_Retry++;
    			ModbusMaster_TallyRetries++;
    			printf("ModbusMaster_Retry:%d\n",ModbusMaster_Retry); //debug
    			if (ModbusMaster_Retry>ModbusMaster_MaxRetry)
    			{
    				//d printf("Failed Monitor message %d\n",ModbusMaster_MonitorIndex); //debug
    				//ModbusMaster_ConnectIndex=0;	// reset connection
    				ModbusMaster_NextCmd(INTERROR_TIMEOUT);
    			}
    			else
    			{
    				ModbusMaster_Send(1);
    			}
    		}
    	}
    }
    
    
    void ModbusMaster_Loop()
    {
    	//d printf("ModbusMaster_Loop: ModbusMaster_Idle=%d\n",ModbusMaster_Idle); //debug
    	if(!ModbusMaster_Idle)
    	{
    		int x;
    		//if (ModbusMaster_LastInTime+ModbusMaster_EndOfPacketWait>Time_sec())
    		//	;
    		//printf("ModbusMaster_Loop: ModbusMaster_Idle=%d\n",ModbusMaster_Idle); //debug
    		ModbusMaster_Send(0);
    		//for (x=0;x<16;x++)
    		//{
    		//	printf("%04d ",(unsigned)MBRegisters[x]);
    		//	if ((x&7)==7) printf("\n");
    		//}
    		ModbusMaster_Retry=0;
    	}
    	else
    		ModbusMaster_Monitor();
    }
    
    
    
    main()
    {
    	ModbusMaster_Init();
    	int reportsecs=10;
    	double starttime;;
    	double MonitorStartTime=0;	// start of most recent monitor cycle
    	double MonitorCycleTime=0;	// seconds to call all commands in Monitor list
    	int TallyConnections=0;	// Number of times Connecion list has been sent
    	int TallyCommands=0;	// Commands since connection
    	int TallyRetries=0;	// Retries since connection
    	
    	starttime=Time_sec();
    	TallyCommands=ModbusMaster_TallyCommands;
    	
    	while(1)
    	{
    		ModbusMaster_Loop();
    		if (starttime+reportsecs<Time_sec())
    		{
    			printf("\nSeconds: %d\n",reportsecs);
    			printf("ModbusMaster_MonitorCycleTime=%f (%f/s)\n",ModbusMaster_MonitorCycleTime,1.0/ModbusMaster_MonitorCycleTime);
    			printf("ModbusMaster_TallyCommands/s=%0.lf\n",(ModbusMaster_TallyCommands-TallyCommands)/(double)reportsecs);
    			printf("ModbusMaster_TallyConnections=%d\n",ModbusMaster_TallyConnections);
    			printf("ModbusMaster_TallyRetries=%d\n",ModbusMaster_TallyRetries);
      
    			starttime=Time_sec();
    			TallyCommands=ModbusMaster_TallyCommands;
    		}
    	}
    }
    My original discussion about getting the Modbus example to work is over on the yahoo group - https://groups.yahoo.com/neo/groups/...ns/topics/8596
    It's probably worth a quick read of that, however there's a few messages where we realised the Kanalog port was numbered the wrong way around, which was why I couldn't get any communication initially.



  3. #3
    Member
    Join Date
    Jun 2004
    Location
    Scotland
    Posts
    355
    Downloads
    0
    Uploads
    0

    Default Re: Questions about MODBUS and kflop

    Also, are you aware that the KMotionX release is not an official Dynomotion Release?

    It was a port done by Par (I'm not sure if he's on here - I've only ever seen him post on the Dynomotion Yahoo Group), so I'm not sure how much the implementation will vary from the official release.
    TomK is very supportive of it, and helps where he can, however you're more likely to get support for it on the Yahoo Group as there are at least a couple users on there who have used KMotionX, and will be more likely to help than on here.



  4. #4
    Registered
    Join Date
    Feb 2016
    Posts
    2
    Downloads
    0
    Uploads
    0

    Default Re: Questions about MODBUS and kflop

    Thanks so much! That helps a lot.

    Yeah seems like there would be some documentation somewhere of what the output of getstatus is byte for byte. When I figure it out I will write it up and post it.

    Thanks for your copy of the modbus code!



  5. #5
    Member
    Join Date
    Jun 2004
    Location
    Scotland
    Posts
    355
    Downloads
    0
    Uploads
    0

    Default Re: Questions about MODBUS and kflop

    Here you go - Script Commands
    GetStatus

    Description

    Upload Main Status record in hex format. KMotion provides a means of quickly uploading the most commonly used status. This information is defined in the PC-DSP.h header file as the MAIN_STATUS structure. The entire stucture is uploaded as a binary image represented as 32-bit hexadecimal values.

    Parameters

    None

    Example

    GetStatus
    which leads onto the following extract from the PC-DSP.h -
    Code:
    typedef struct
    {
    	int VersionAndSize;   //bits 16-23 = version, bits 0-15 = size in words
    	int ADC[N_ADCS+2*N_ADCS_SNAP];
    	int DAC[N_DACS];
    	int PWM[N_PWMS+2*N_PWMS_SNAP];
    	double Position[N_CHANNELS];  
    	double Dest[N_CHANNELS];
    	unsigned char OutputChan0[N_CHANNELS];
    	  
    	int InputModes;      // 4 bits for each axis 
    	int InputModes2;     // 4 bits for each axis 
    	int OutputModes;     // 4 bits for each axis 
    	int OutputModes2;    // 4 bits for each axis 
    	int Enables;         // 1 bit  for each axis 
    	int AxisDone;        // 1 bit  for each axis 
    	
    	int BitsDirection[2];// KMotion - 64 bits of I/O direction 1 = output
    	int BitsState[2];    // KMotion - 64 bits of state lsb=I/O bit0
    
    	int SnapBitsDirection0;   // Snap - 32 bits of I/O direction 1=output 16-29 GPIO only, Card 0
    	int SnapBitsDirection1;   // Snap - 32 bits of I/O direction 1=output 16-29 GPIO only, Card 1
    	int SnapBitsState0;       // Snap - 32 bits of state  16-29 GPIO 0-7 Diff 8-15 OPTO, Card 0
    	int SnapBitsState1;       // Snap - 32 bits of state  16-29 GPIO 0-7 Diff 8-15 OPTO, Card 1
    	
    	int KanalogBitsStateInputs;   // Kanalog - 16 bits 128-143
    	int KanalogBitsStateOutputs;  // Kanalog - 24 bits 144-167
    
    	int RunOnStartUp;    // word Bits 1-7 selects which threads to execute on startup   
    	
    	int ThreadActive;    		// one bit for each thread, 1=active, bit 0 - primary
    	int StopImmediateState;    // Status of Stop Coordinated Motion Immediately
    
    	double TimeStamp;	// Time in seconds (since KFlop boot) this status was aquired
    	int	PC_comm[N_PC_COMM_PERSIST];// 8 persist Variables constantly uploaded to send misc commands/data to PC
    
    	int VirtualBits;		// Virtual I/O bits simulated in memory
    	int VirtualBitsEx0;		// only upload 32 1024 Expanded Virtual Bits 
    } MAIN_STATUS;
    It took me a while to figure out where the GetStatus function was, but finally realised it's a console command.



Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


About CNCzone.com

    We are the largest and most active discussion forum for manufacturing industry. The site is 100% free to join and use, so join today!

Follow us on


Our Brands

Questions about MODBUS and kflop

Questions about MODBUS and kflop