CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

sending coils data from master to slave

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
micro_man



Joined: 05 Jun 2013
Posts: 14

View user's profile Send private message

sending coils data from master to slave
PostPosted: Tue Jul 23, 2013 1:51 am     Reply with quote

Hi
i want to send coils data from modbus master to slave.
first i write the slave program and sends the data from modbus poll (using PC). it works well. the code for the slave is
Code:

#include "16f870.h"
#fuses HS,NOLVP,NOWDT,NOBROWNOUT,PROTECT, PUT
#use delay(clock=20M)

#define MODBUS_TYPE MODBUS_TYPE_SLAVE
#define MODBUS_SERIAL_RX_BUFFER_SIZE 40
#define MODBUS_SERIAL_BAUD 19200

#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7,parity=E, stream=MODBUS_SERIAL)
#define MODBUS_SERIAL_INT_SOURCE MODBUS_INT_RDA
#define MODBUS_SERIAL_ENABLE_PIN   PIN_C4   // Controls DE pin for RS485

#include "modbus.c"

#define MODBUS_ADDRESS 0x05

/*This function may come in handy for you since MODBUS uses MSB first.*/
int8 swap_bits(int8 c)
{
 return ((c&1)?128:0)|((c&2)?64:0)|((c&4)?32:0)|((c&8)?16:0)|((c&16)?8:0)
        |((c&32)?4:0)|((c&64)?2:0)|((c&128)?1:0);
}

void main()

   int i,one_time=0;
   int8 coils1  = 0b11111111;
   int8 inputs = 0b11111111;
   int poll=0;
   setup_timer_0(RTCC_INTERNAL);
   modbus_init();
   
   while(1)
   {
      if(one_time==1)
      {
         one_time=0;
         if(bit_test (coils1, 0)) output_bit(PIN_A0,1); else output_bit(PIN_A0,0);
         if(bit_test (coils1, 1)) output_bit(PIN_A1,1); else output_bit(PIN_A1,0);
         if(bit_test (coils1, 2)) output_bit(PIN_B4,1); else output_bit(PIN_B4,0);
         if(bit_test (coils1, 3)) output_bit(PIN_B5,1); else output_bit(PIN_B5,0);
      }
      poll++;               
     
      if(modbus_kbhit()!=1)
      {
      }
      else
      {
         poll=0;
     
         //check address against our address, 0 is broadcast
         if((modbus_rx.address == MODBUS_ADDRESS) || modbus_rx.address == 0)
         {     
            switch(modbus_rx.func)
            {
               case FUNC_WRITE_MULTIPLE_COILS:
               if(modbus_rx.data[0] || modbus_rx.data[2] ||
               modbus_rx.data[1] >= 8 || modbus_rx.data[3]+modbus_rx.data[1] > 8)
               {
                  modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
               }
               else
               {
                  int i,j;                 
                  modbus_rx.data[5] = swap_bits(modbus_rx.data[5]);                 
                 
                  for(i=modbus_rx.data[1],j=0; i < modbus_rx.data[1]+modbus_rx.data[3];++i,++j)
                  { 
                     if(bit_test(modbus_rx.data[5],j))
                     bit_set(coils1,7-i);
                     else
                     bit_clear(coils1,7-i);
           
                  }
                  one_time=1;
                  modbus_write_multiple_coils_rsp(MODBUS_ADDRESS,
                                 make16(modbus_rx.data[0],modbus_rx.data[1]),
                                 make16(modbus_rx.data[2],modbus_rx.data[3]));
               }
               break;
             
               default:    //We don't support the function, so return exception
               modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_FUNCTION);
            }   
         }
      }
   } //while
}   //main


Then i write the program for master as follows.

Code:

#include "16f870.h"
#fuses HS,NOLVP,NOWDT,NOBROWNOUT,PROTECT, PUT
#use delay(clock=20M)


#define MODBUS_TYPE MODBUS_TYPE_MASTER
#define MODBUS_SERIAL_TYPE MODBUS_RTU
#define MODBUS_SERIAL_RX_BUFFER_SIZE 64
#define MODBUS_SERIAL_BAUD 19200       
#define MODBUS_SERIAL_TIMEOUT 10000
#USE RS232(BAUD=19200, XMIT=PIN_C6, RCV=PIN_C7, PARITY=E, STREAM=MODBUS_SERIAL)
#define MODBUS_SERIAL_INT_SOURCE MODBUS_INT_RDA
#define MODBUS_SERIAL_ENABLE_PIN   PIN_C5
#include "C:\Documents and Settings\Administrator\Desktop\testing\modbus.c"

#define MODBUS_SLAVE_ADDRESS 0x05

void main()
{
   modbus_init();
   
   unsigned int8 coils=0x10,i=0;
   
   while(1)
   {
      if(!(modbus_write_multiple_coils(MODBUS_SLAVE_ADDRESS,0,8,coils)))
      {
         for(i=0;i<(modbus_rx.len);++i)
         {
         }
      }
      delay_ms(500);
   }
}


i want to know that is this program is correct? when i run the programs, some leds on the slave side ON/OFF. Kindly tell me if i am somewhere wrong.
Actually i want to send multiple coils from master to slave but initially i am sending one coil to the slave to understand the operation.
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Tue Jul 23, 2013 3:37 am     Reply with quote

You don't need to have a #use rs232 for the serial port used for modbus. modbus.c does that for you, and it's definition will override yours.

Code:

// This is wrong.
if(!(modbus_write_multiple_coils(MODBUS_SLAVE_ADDRESS,0,8,coils)))

// You need to give a pointer to the "coils" like this:
if(!(modbus_write_multiple_coils(MODBUS_SLAVE_ADDRESS,0,8,&coils)))


There may be other problems, but I've not tried to compile nor run your code.

In the slave it's better to implement all of the commands relating to each data type rather than just the one you expect to use. In this case, FUNC_READ_COILS, FUNC_WRITE_SINGLE_COIL, as well as just FUNC_WRITE_MULTIPLE_COILS. This will allow you to read back the coil/s you've just set. Good for diagnostics and for understanding.

Also be aware that for simplicity the example code implements eight of each data type. Its up to you to extend that to suit your application.
micro_man



Joined: 05 Jun 2013
Posts: 14

View user's profile Send private message

PostPosted: Tue Jul 23, 2013 5:40 am     Reply with quote

when i change the coil variable manually.it send the data to slave
e.g unsigned int8 coils=0x01,unsigned int8 coils=0x02,unsigned int8 coils=0x03 slave get those values.

But i want to do it automatically by incrementing the variable like
coils=coils+1; but this is not working

Code:

void main()
{
   modbus_init();
   
   unsigned int8 coils=0x01,i=0;
   
   while(1)
   {
      if(!(modbus_write_multiple_coils(MODBUS_SLAVE_ADDRESS,0,8,&coils)))
      {
         for(i=0;i<(modbus_rx.len);++i)
         {
         }
      }
      coils=coils + 1;
      delay_ms(500);
   }
}
oxo



Joined: 13 Nov 2012
Posts: 219
Location: France

View user's profile Send private message

PostPosted: Tue Jul 23, 2013 9:03 am     Reply with quote

I may be wrong, but I thought that you cannot pass a local variable by reference?

Try making your coils variable either a global, or a static local.
micro_man



Joined: 05 Jun 2013
Posts: 14

View user's profile Send private message

PostPosted: Wed Jul 24, 2013 2:05 am     Reply with quote

I look into the modbus driver file and found that data is send in terms of an array e.g values[i]
Code:

exception modbus_write_multiple_coils(int8 address, int16 start_address, int16 quantity,
                           int8 *values)
{
   int8 i,count;
   
   count = (int8)((quantity/8));
   
   if(quantity%8)
      count++;     

   modbus_serial_send_start(address, FUNC_WRITE_MULTIPLE_COILS);

   modbus_serial_putc(make8(start_address,1));
   modbus_serial_putc(make8(start_address,0));

   modbus_serial_putc(make8(quantity,1));
   modbus_serial_putc(make8(quantity,0));

   modbus_serial_putc(count);

   for(i=0; i < count; ++i)
      modbus_serial_putc(values[i]);

   modbus_serial_send_stop();

   MODBUS_SERIAL_WAIT_FOR_RESPONSE();

   return modbus_rx.error;
}

so i change my variable to an array but it is still not working
Code:
void main()
{
   unsigned int8 coils[1]={0x01},i=0;
   
   modbus_init();
   
   while(1)
   {
      if(!(modbus_write_multiple_coils(MODBUS_SLAVE_ADDRESS,0,8,coils)))
      {
         for(i=0;i<(modbus_rx.len);++i)
         {
         }
      }
      coils[0]=coils[0] + 1;
      if(coils[0]>8)
      {
         coils[0]=1;
      }
      delay_ms(500);
   }
}

But the code is not working yet. Someone tell me where i am wrong?
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Wed Jul 24, 2013 2:50 am     Reply with quote

Your posts don't manage to report a problem clearly.

What is "not working"? No response from slave, error message from slave? Send MODBUS data correct/not
correct when watched with a monitor tool? etc...
micro_man



Joined: 05 Jun 2013
Posts: 14

View user's profile Send private message

PostPosted: Wed Jul 24, 2013 3:43 am     Reply with quote

The problem is slave not responding.
I have some leds on the slave side. When master will send data to the slave, according to the coil bits leds will be on and off.
Firstly i write a program for slave and test it with modbus poll software (on computer). It was working fine.
Then i write a program for master and connect it with the slave, but i am not getting results as i was getting with the master (modbus poll).

But i am not sure about my master program. Is it the right way to send the data to slave or not?
micro_man



Joined: 05 Jun 2013
Posts: 14

View user's profile Send private message

PostPosted: Thu Jul 25, 2013 1:17 am     Reply with quote

guys any idea...
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Thu Jul 25, 2013 1:51 pm     Reply with quote

I say: KISS

There are many things where your code can go wrong. If it is not working as expected then you have to make things simpler. Create the most basic MODBUS connection you can think of and get this working, then expand from what is working. When it fails again, like in your case, then you have to go back again to what is working and make an even smaller step in adding functionality.
Best if you get yourself an In Circuit Debugger so you can set breakpoints and step through the code, this will save you so much time now and in the future.
Without ICD you have to add many debug output commands so you can see what is happening. Preferably write debug texts to a serial port or LCD. If you don't have these output devices then use LEDs in different output combinations.

You are there sitting behind the real hardware setup, that means you can do all the experiments. We from our computer can only read your program and guess.

One thing that worries me is that in your slave you have:
Code:
                  modbus_rx.data[5] = swap_bits(modbus_rx.data[5]);                 
                 
                  for(i=modbus_rx.data[1],j=0; i < modbus_rx.data[1]+modbus_rx.data[3];++i,++j)
                  {
                     if(bit_test(modbus_rx.data[5],j))
                     bit_set(coils1,7-i);
                     else
                     bit_clear(coils1,7-i);
           
                  }
The swap macro reverses all bit in the bytes, but then in the for-loop you do again a reverse. Perhaps this is good, I don't know but it is complicating things.
I would remove all code from the slave, except the code for receiving a message. Then on every message I would toggle one LED. Don't do fancy things with 4 LEDs.

O yes, one other thing: your master is now counting 1 - 7. Even when things are working as you want them to, then only 3 LEDs would be activated in the slave and not all 4.
micro_man



Joined: 05 Jun 2013
Posts: 14

View user's profile Send private message

PostPosted: Mon Jul 29, 2013 2:29 am     Reply with quote

i simplify the program as follows

MASTER
Code:

#include "16f870.h"
#fuses HS,NOLVP,NOWDT,NOBROWNOUT,PROTECT, PUT
#use delay(clock=20M)

#define MODBUS_TYPE MODBUS_TYPE_MASTER
#define MODBUS_SERIAL_TYPE MODBUS_RTU
#define MODBUS_SERIAL_RX_BUFFER_SIZE 64
#define MODBUS_SERIAL_BAUD 19200       
#define MODBUS_SERIAL_TIMEOUT 10000
#USE RS232(BAUD=19200, XMIT=PIN_C6, RCV=PIN_C7, PARITY=E, STREAM=MODBUS_SERIAL)
#define MODBUS_SERIAL_INT_SOURCE MODBUS_INT_RDA
#define MODBUS_SERIAL_ENABLE_PIN   PIN_C5
#include "C:\Documents and Settings\Administrator\Desktop\testing\modbus.c"

#define MODBUS_SLAVE_ADDRESS 0x05

void main()
{
   unsigned int8 coils=0x02,i=0;
   int1 a=0;
   modbus_init();
   
   while(1)
   {
      modbus_write_multiple_coils(MODBUS_SLAVE_ADDRESS,0,8,&coils);
      {
         for(i=0;i<(modbus_rx.len);++i)
         {
         }
      }
      coils=coils + 1;
      if(coils>8)
      {
         coils=1;
      }
      delay_ms(500);
   }
}


SLAVE
Code:

#include <18F26K22.h>
#FUSES HSH,NOPLLEN,NOWDT,PUT,NOLVP
#use delay(clock=20M)
#use rs232(baud=9600,xmit=PIN_B6,rcv=PIN_B7, stream=gsm)

#define MODBUS_TYPE MODBUS_TYPE_SLAVE
#define MODBUS_SERIAL_RX_BUFFER_SIZE 40
#define MODBUS_SERIAL_BAUD 19200

#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7,parity=E, stream=MODBUS_SERIAL)
#define MODBUS_SERIAL_INT_SOURCE MODBUS_INT_RDA
#define MODBUS_SERIAL_ENABLE_PIN   PIN_C5   // Controls DE pin for RS485

#include "C:\Documents and Settings\Administrator\Desktop\testing\modbus_hay.c"

#define MODBUS_ADDRESS 0x05

/*This function may come in handy for you since MODBUS uses MSB first.*/
int8 swap_bits(int8 c)
{
 return ((c&1)?128:0)|((c&2)?64:0)|((c&4)?32:0)|((c&8)?16:0)|((c&16)?8:0)
        |((c&32)?4:0)|((c&64)?2:0)|((c&128)?1:0);
}

void main()

   int one_time=0;
   int8 coils1  = 0b11111111;
   int8 inputs = 0b11111111;
   int poll=0;
   setup_timer_0(RTCC_INTERNAL);
   modbus_init();
   fprintf(gsm," testing ");
   while(1)
   {
      if(modbus_kbhit()!=1)
      {
      }
      else
      {
         //check address against our address, 0 is broadcast
         if((modbus_rx.address == MODBUS_ADDRESS) || modbus_rx.address == 0)
         {     
            switch(modbus_rx.func)
            {
               case FUNC_WRITE_MULTIPLE_COILS:
               
               if(modbus_rx.data[0] || modbus_rx.data[2] ||
               modbus_rx.data[1] >= 8 || modbus_rx.data[3]+modbus_rx.data[1] > 8)
               {
                  modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
                  fprintf(gsm,"\r\n *");
                  fprintf(gsm," %x ",modbus_rx.address);
                  fprintf(gsm," %x ",modbus_rx.data[0]);
                  fprintf(gsm," %x ",modbus_rx.data[1]);
                  fprintf(gsm," %x ",modbus_rx.data[2]);
                  fprintf(gsm," %x ",modbus_rx.data[3]);
                  fprintf(gsm," %x \r\n",modbus_rx.data[5]);
               }
               else
               {
                  //int i,j;                 
                  modbus_rx.data[5] = swap_bits(modbus_rx.data[5]);                 
                  //fprintf(gsm," %x ",modbus_rx.data[5]);
                  fprintf(gsm," %x ",modbus_rx.address);
                  fprintf(gsm," %x ",modbus_rx.data[0]);
                  fprintf(gsm," %x ",modbus_rx.data[1]);
                  fprintf(gsm," %x ",modbus_rx.data[2]);
                  fprintf(gsm," %x ",modbus_rx.data[3]);
                  fprintf(gsm," %x ",modbus_rx.data[5]);
                  modbus_write_multiple_coils_rsp(MODBUS_ADDRESS,
                                 make16(modbus_rx.data[0],modbus_rx.data[1]),
                                 make16(modbus_rx.data[2],modbus_rx.data[3]));
               }
               
               break;
             
               default:    //We don't support the function, so return exception
               modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_FUNCTION);
            }   
         }
      }
   } //while
}   //main


i added a serial port at slave side to see what data is coming and it shows an error here.
first time when i program the master and run it the slave receive data like
fprintf(gsm," %x ",modbus_rx.address);= 05 correct
fprintf(gsm," %x ",modbus_rx.data[0]);= 00 correct (starting address H)
fprintf(gsm," %x ",modbus_rx.data[1]);= 00 CORRECT (starting address L)
fprintf(gsm," %x ",modbus_rx.data[2]);= 00 correct (quantity H)
fprintf(gsm," %x ",modbus_rx.data[3]);= 08 correct (quantity L)
fprintf(gsm," %x ",modbus_rx.data[5]);= 40 wrong (data)

then
fprintf(gsm," %x ",modbus_rx.address);= 05 correct
fprintf(gsm," %x ",modbus_rx.data[0]);= 00 correct (starting address H)
fprintf(gsm," %x ",modbus_rx.data[1]);= 01 WRONG (starting address L)
fprintf(gsm," %x ",modbus_rx.data[2]);= 00 correct (quantity H)
fprintf(gsm," %x ",modbus_rx.data[3]);= 08 correct (quantity L)
fprintf(gsm," %x ",modbus_rx.data[5]);= 01 correct (data)


i think this address is a problem.but why i am getting it as master is fixed?
guys tell me about this.what i should check further?
oxo



Joined: 13 Nov 2012
Posts: 219
Location: France

View user's profile Send private message

PostPosted: Mon Jul 29, 2013 3:51 am     Reply with quote

Quote:
/*This function may come in handy for you since MODBUS uses MSB first.*/


Modbus uses ms BYTE first, not ms BIT first. You may need to swap BYTES, but never need to swap BITS.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group