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

PIC16F887 Modbus RTU Slave over RS485

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



Joined: 23 Dec 2015
Posts: 2

View user's profile Send private message

PIC16F887 Modbus RTU Slave over RS485
PostPosted: Tue Jan 05, 2016 9:09 am     Reply with quote

Hello ALL,
I am very new to the forum and beginner. I got some code around this forum and used example Modbus slave code from CCS, modified to match with my controller. Finally I am trying to test a PIC 16F887 as Modbus RTU slave to communicate with a PLC through RS 485 for one of my simple application. Half duplex, used Max 485 at PIC side. The communication is ok, but when I try to read the data from PLC , I am getting MODBUS_RTU_SLAVE_ERROR 0x96. I am just trying to read single Holding registers and write an LED. Could anyone please help me to move further? Thank you all in advance! My code is here: I am using CCS compiler Version 5.052
Code:

////////////////////////////////////////////////////////////////////////////////
 ////                         Slave                                                        ////
 ////                                                                                        ////
 //////////////////////////////////////////////////////////////////////////////

 //#define USE_WITH_PC 1
 #include <16F887.h>   


#fuses HS,NOWDT
#use delay(clock=16000000)


 #ZERO_RAM
 #define MODBUS_SERIAL_INT_SOURCE  MODBUS_INT_RDA
 #define MODBUS_TYPE  MODBUS_TYPE_SLAVE
 #define MODBUS_SERIAL_TYPE  MODBUS_RTU     //use MODBUS_ASCII for ASCII mode
// #define MODBUS_SERIAL_RX_BUFFER_SIZE 64
 #define MODBUS_SERIAL_BAUD 9600



#define MODBUS_SERIAL_TX_PIN  PIN_C6   // Data transmit pin
#define MODBUS_SERIAL_RX_PIN  PIN_C7  // Data receive pin

#define MODBUS_SERIAL_ENABLE_PIN  PIN_B1   // Controls DE pin for RS485
#define MODBUS_SERIAL_RX_ENABLE  PIN_B1   // Controls RE pin for RS485


#include <modbus.c>

#define MODBUS_ADDRESS 0x01

#define LED_1 PIN_A3   

#define HIGH_ADDRESS_READ_DATA1      0x00
#define LOW_ADDRESS_READ_DATA1      0x02

#define HIGH_ADDRESS_WRITE_LED_1      0x00
#define LOW_ADDRESS_WRITE_LED_1      0x05

#BYTE TRISA = 0x85
#BYTE TRISB = 0x86   
#BYTE TRISC = 0X87
#BYTE PORTA = 0x05   
#BYTE PORTB = 0x06   
#BYTE PORTC = 0x07   
#USE fast_io(A)
#USE fast_io(B)
#USE fast_io(C)
int8 data1=60;

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

 /*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()
 {
    set_tris_a(0b11110111);
    set_tris_b(0b11011100);
    set_tris_c(0b10111111);
    port_b_pullups(true);
    int8 coils = 0b00000101;
    int8 inputs = 0b00001001;
    int16 hold_regs[] = {0x8800,0x7700,0x6600,0x5500,0x4400,0x3300,0x2200,0x1100};
    int16 input_regs[] = {0x1100,0x2200,0x3300,0x4400,0x5500,0x6600,0x7700,0x8800};
    int16 event_count = 0;
     
    setup_adc_ports(NO_ANALOGS);
    output_low(LED_1);
    delay_ms(500);

     modbus_init();
     
    while(TRUE)
    {
       data1=~data1+99;
       while(!modbus_kbhit());
       
       delay_us(50);
       //check address against our address, 0 is broadcast
       if((modbus_rx.address == MODBUS_ADDRESS) || modbus_rx.address == 0)
       {
          switch(modbus_rx.func)
          {
         
             case FUNC_READ_COILS:    //read coils
             case FUNC_READ_DISCRETE_INPUT:    //read inputs
                 
     
                 if((modbus_rx.data[0]== HIGH_ADDRESS_READ_DATA1) && (modbus_rx.data[1]==LOW_ADDRESS_READ_DATA1)){
                modbus_read_discrete_input_rsp(MODBUS_ADDRESS,1,&data1);
                 }

                 
              else
                 {
                    modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
              }
                break;
             case FUNC_READ_HOLDING_REGISTERS:
                 if((modbus_rx.data[0]== HIGH_ADDRESS_READ_DATA1) && (modbus_rx.data[1]==LOW_ADDRESS_READ_DATA1)){
                modbus_read_discrete_input_rsp(MODBUS_ADDRESS,1,&data1);
                 }

              else
                 {
                    modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
              }
             case FUNC_READ_INPUT_REGISTERS:
                 if((modbus_rx.data[0]== HIGH_ADDRESS_READ_DATA1) && (modbus_rx.data[1]==LOW_ADDRESS_READ_DATA1)){
                modbus_read_discrete_input_rsp(MODBUS_ADDRESS,1,&data1);
                 }

              else
                 {
                    modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
              }
                break;
                 
             case FUNC_WRITE_SINGLE_COIL:      //write coil
             
                 if((modbus_rx.data[0]== HIGH_ADDRESS_WRITE_LED_1) && (modbus_rx.data[1]==LOW_ADDRESS_WRITE_LED_1)){
                    if(modbus_rx.data[2] == 0xFF){   
                        output_high(LED_1);
                    }
                    else{
                       output_low(LED_1);}
                 }
                  else{
                    modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
              }
                break;
                 
             case FUNC_WRITE_SINGLE_REGISTER:
                if(modbus_rx.data[0] || modbus_rx.data[1] >= 8)
                   modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
                else
                {
               
                   hold_regs[modbus_rx.data[1]] = make16(modbus_rx.data[3],modbus_rx.data[2]);

                   modbus_write_single_register_rsp(MODBUS_ADDRESS,
                                make16(modbus_rx.data[0],modbus_rx.data[1]),
                                make16(modbus_rx.data[2],modbus_rx.data[3]));
                }
                break;
                 
             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(coils,7-i);
                      else
                         bit_clear(coils,7-i);
                   }

                   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]));
                   
                   event_count++;
                }
                break;
                 
             case FUNC_WRITE_MULTIPLE_REGISTERS:
                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;

                   for(i=0,j=5; i < modbus_rx.data[4]/2; ++i,j+=2)
                      hold_regs[i] = make16(modbus_rx.data[j+1],modbus_rx.data[j]);

                   modbus_write_multiple_registers_rsp(MODBUS_ADDRESS,
                                  make16(modbus_rx.data[0],modbus_rx.data[1]),
                                  make16(modbus_rx.data[2],modbus_rx.data[3]));
                 
                   event_count++;
                }
                break;           
             default:    //We don't support the function, so return exception
                modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_FUNCTION);
          }
       }
   }
 }
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Tue Jan 05, 2016 10:05 am     Reply with quote

A number of things: first, you need to use the code button to keep the formatting of your code. It makes it much easier to read, like this:

Code:
#ZERO_RAM    // Do you really need this? Probably not. Just included because someone else did maybe?

#define MODBUS_SERIAL_INT_SOURCE MODBUS_INT_RDA  // This uses the hardware UART.
#define MODBUS_TYPE MODBUS_TYPE_SLAVE  // Slave mode - fine, but you talk about talking to a PLC, which is also a slave, probably...
#define MODBUS_SERIAL_TYPE MODBUS_RTU //use MODBUS_ASCII for ASCII mode
// #define MODBUS_SERIAL_RX_BUFFER_SIZE 64  // Fine, the driver will default to this anyway.
#define MODBUS_SERIAL_BAUD 9600  // Good, its the commonest MODBUS speed.


// Don't define the serial pins. You've selected the hardware UART, and that's enough. Anything else can cause confusion.
//#define MODBUS_SERIAL_TX_PIN PIN_C6 // Data transmit pin
//#define MODBUS_SERIAL_RX_PIN PIN_C7 // Data receive pin

// Don't define both enables if you are connecting both to one pin. Just use the MODBUS_SERIAL_ENABLE_PIN only.
#define MODBUS_SERIAL_ENABLE_PIN PIN_B1 // Controls DE pin for RS485

// This may well be what's causing the problem.
//#define MODBUS_SERIAL_RX_ENABLE PIN_B1 // Controls RE pin for RS485

#include <modbus.c>

#define MODBUS_ADDRESS 0x01  \\ Are you sure this is okay? personally I'd select something less likely to already have been used...


#define LED_1 PIN_A3


#define HIGH_ADDRESS_READ_DATA1 0x00
#define LOW_ADDRESS_READ_DATA1 0x02

#define HIGH_ADDRESS_WRITE_LED_1 0x00
#define LOW_ADDRESS_WRITE_LED_1 0x05


// Don't try to use fast_io unless you really a) need it and b) know how it works.
//  Let the compiler do it all for you - it will make fewer mistakes than you! Also, you can override the settings used by the MODBUS driver.
//#BYTE TRISA = 0x85
//#BYTE TRISB = 0x86
//#BYTE TRISC = 0X87
//#BYTE PORTA = 0x05
//#BYTE PORTB = 0x06
//#BYTE PORTC = 0x07
//#USE fast_io(A)
//#USE fast_io(B)
//#USE fast_io(C)

// Also don't use the set tris functions.


I do not know what MODBUS error 0x96 is, it is not a standard MODBUS error. It's probably specific to whatever master you are using to talk to the bus. So you need to look up in whatever documentation you have for it to find out what it means.

I don't like the 50us delay after checking modbus_kbhit(). MODBUS is timing dependant and, while I doubt 50us will have all that much of an effect, its possible it will cause problems. Why did you put it in?

I can't be sure you've not got some addressing problems with the read and write functions. The lack of formatting makes that code very hard to read.

I'm also going to assume you've got the hardware set up correctly, particularly the terminating and biassing resistors, not to mention the decoupling capacitors. Get any of that wrong, and it can be very difficult to debug. Personally, I would have gone with slower, lower power bus drivers, such as the MAX483, which can be rather more forgiving and easier to use.
LogicM



Joined: 23 Dec 2015
Posts: 2

View user's profile Send private message

PIC16F887 Modbus RTU Slave over RS485
PostPosted: Thu Jan 07, 2016 1:17 pm     Reply with quote

Hi RF_Developer,

Thank you for your quick response and help! Sorry for the late reply, its took some time to get fixed everything..

Now its working fine, great support! Thanks Again!
ngthuy1190



Joined: 07 Jan 2022
Posts: 1

View user's profile Send private message

Re: PIC16F887 Modbus RTU Slave over RS485
PostPosted: Fri Jan 07, 2022 3:05 am     Reply with quote

LogicM wrote:
Hi RF_Developer,

Thank you for your quick response and help! Sorry for the late reply, its took some time to get fixed everything..

Now its working fine, great support! Thanks Again!

hi, i am also facing the same problem as you, can you share the finished code for me, thanks
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