Email: Password: Remember Me | Create Account (Free)

Back to Subject List

Old thread has been locked -- no new posts accepted in this thread
???
12/31/04 07:10
Read: times


 
#84158 - Modbus
Responding to: ???'s previous message

Normally the hub would be dumb - it has no microprocessor. My normal application using a PC would have an ethernet to modbus converter by Advantech or Moxa. These can be dispensed with if you use a FTDI usb->serial chip , a handful of 75176's(or max485...) a 74hc30 and 74hc04. The FTDI chip has an output that goes high when it wants to send - this takes care of the rx/tx direction without any special software - the FTDI chip 'knows' when it sends. The FTDI tx output goes to all the 75176 tx inputs, the 75176 rx lines go through the 74hc30 nand gate and then through a 74hc04 inverter to put the x signal the right way then into the FTDI rx input. The direction output from the FTDI chip goes to pin 2 & 3 of all the 75176's. This gives you a RS485 hub and interface in one (and powered by the USB port!).

Modbus ascii is easier to implement on the PC side as it doesn't rely on end of packet timing which can be hard to achieve on a PC.

Because Modbus is a polled system, there is no concept of high priority interrupts - a slave waits until it is polled. Obviously, the more slaves there is the slower a complete poll cycle will take.

You can have an intelligent hub if you wish - the Modbus protocol doesn't cover such things. Your intelligent hub would use modbus to talk to the slaves and use another modbus like to connect to the PC - the hub software would make the link whichever way you would like. Because modbus is half duplex - when you send a message to a slave you either get a response from the slave or you timeout after a period. It's up to your software to do this.

Here is some sample interrupt code to send/receive modbus - it is not complete and uses the second serial port -easy enough to change for serial port1

<pre>
void SCON1_int(void) interrupt 7
{
static char a;
/*
Modbus RTU comms is strange that the end of packet
is delimited by a timeout. After X character times
we expect the packet is complete. So for each character
we receive we load timer2 with the timeout value.
When timer2 fires we check the crc of the received packet
If the CRC fails we reject the packet and look for another

*/
if (RI_1 ==1)
{
a = SBUF1; //get the rx char
RI_1 = 0;
if (modbus_type == ASCII)
{
if (serial_rx_pkt !=0 ) return; //we haven't finished processing the previous pkt!
if (a == ':')
{
serial_rx_cksm = 0;
serial_rx = modbus_buf;
serial_rx_count = 0;
serial_rx_state = 1;
}
else
{
switch(serial_rx_state)
{
case 0:
break;
case 1:
if ((a >=0x30 ) && ( a <= 0x39))
{
a -=0x30;
*serial_rx = a<<4;
serial_rx_state = 2;
}
else if ((a >= 0x41) && (a <= 0x46))
{
a -=0x37;
*serial_rx = a<<4;
serial_rx_state = 2;
}
else if ( a == CR ) //carriage return (end of packet)
{
if (serial_rx_cksm == 0) //if the checksum was good
{
serial_rx_state = 0;
if ((modbus_buf[0] == modbus_addr) && (serial_rx_count >= 6))
// if ((serial_rx_count >= 6))
{
serial_rx_pkt=serial_rx_count;
}
serial_rx = modbus_buf;
serial_rx_count=0;
}
}
else
{
serial_rx_state = 0; //illegal character
}
break;
case 2:
if ((a >= '0' ) && ( a <= '9'))
{
a -=0x30;
*serial_rx |= a;
serial_rx_cksm += *serial_rx++; //accumulate the checksum
serial_rx_count++;
serial_rx_state = 1;
}
else if ((a >= 'A') && (a <= 'F'))
{
a -=0x37;
*serial_rx |= a;
serial_rx_cksm += *serial_rx++; //accumulate the checksum
serial_rx_count++;
serial_rx_state = 1;
}
else
{
serial_rx_state = 0; //illegal character! reject the packet
}
break;
}//end switch
}

}//end modbus ascii
else
{
if ((serial_rx_pkt == 0) && (serial_rx_count < sizeof(modbus_buf) ) )
{
*serial_rx++ = a; /* store the rx char */
serial_rx_count++; /* char count ++ */
TR2=0; /* reload the end of packet timeout */
TH2=0xf9;
TL2=0x99; /* 3 character times at 19200 baud*/
TR2=1;
}
}
}//end rx interrupt

if (TI_1 == 1)
{ /* transmit interrupt? */
if (modbus_type == ASCII)
{
TI_1 = 0;
switch(serial_tx_state)
{
case 0: //send the high nibble
a = *serial_tx; //get the data to send
serial_tx_cksm += a; //accumulate the checksum
SBUF1 = ascii_xlate[a>>4];
serial_tx_state = 1; //send low nibble next
break;
case 1: //send the low nibble
a = *serial_tx; //get the data to send
SBUF1 = ascii_xlate[a & 0x0f];
serial_tx++; //-> next byte
serial_tx_count --;
serial_tx_state = 0; //default the next state
if (serial_tx_count == 1) //checksum??
{
*serial_tx = 0-serial_tx_cksm; //store the checksum
}
if (serial_tx_count == 0)
{
serial_tx_state = 2; //end of the packet, send the CR next
}
break;
case 2: //send the CR
SBUF1 = CR;
serial_tx_state = 3;
break;
case 3: //send the LF
SBUF1 = LF;
serial_tx_state = 4;
break;
case 4: //do nothing! wait for other code to reset us
default:
break;
}//end switch
}//end modbus ascii tx

else //Modbus RTU

{
TI_1 = 0; /* reset the int flag */
/* check for message complete */
if (serial_tx_count==0) ENB485=1;
else
{ /* continue sending */
SBUF1 = *serial_tx++; /* send next character */
--serial_tx_count; /* dec count of characters */
}
}
}//end tx interrupt
}
/*

If timer2 times out, we expect to find a MODBUS packet in our buffer.
Check for address and size then alert the comms task


*/
void T2_int(void) interrupt 5
{
TR2=0; /* stop timer 2 running */
TF2=0; /* clear the overflow flag */
if ((modbus_buf[0] == modbus_addr) && (serial_rx_count > 6))
{
serial_rx_pkt = serial_rx_count; //setting serial_rx_pkt to non-zero activates the comms task
}
serial_rx = modbus_buf;
serial_rx_count=0;
}

(/pre>



List of 27 messages in thread
TopicAuthorDate
Control system            01/01/70 00:00      
   buses for industrial            01/01/70 00:00      
      CAN or RS-485            01/01/70 00:00      
         one way of master slave            01/01/70 00:00      
         RS485            01/01/70 00:00      
   Control system            01/01/70 00:00      
   Modbus            01/01/70 00:00      
      modbus or not            01/01/70 00:00      
   rs-485            01/01/70 00:00      
      Rs485 vs CAN            01/01/70 00:00      
      CAN            01/01/70 00:00      
         rs-485,high speed?            01/01/70 00:00      
            UART speed            01/01/70 00:00      
            Speed            01/01/70 00:00      
               Go Speed Racer!            01/01/70 00:00      
                  comments on speed and the above            01/01/70 00:00      
                     Daisy chain            01/01/70 00:00      
                        Daisy,Daisy.....            01/01/70 00:00      
                        no repeat            01/01/70 00:00      
                           Modbus            01/01/70 00:00      
                              Modbus            01/01/70 00:00      
                                 Hub ?            01/01/70 00:00      
   Modbus            01/01/70 00:00      
      Modbus            01/01/70 00:00      
         More modbus            01/01/70 00:00      
            Modbus            01/01/70 00:00      
               failed links            01/01/70 00:00      

Back to Subject List