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

Modbus slave with PIC24FJ128GA204

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



Joined: 07 Sep 2003
Posts: 56

View user's profile Send private message

Modbus slave with PIC24FJ128GA204
PostPosted: Tue Dec 27, 2016 12:03 pm     Reply with quote

Hello Guys,

I made some modifications in the example modbus_slave, to use the PIC24FJ128GA204, but it's not working.

Tested hardware with a program for RS485 network and is running.

I put a break point, below the while (! modbus_kbhit ());, but the program gets stuck in while (! modbus_kbhit ());

To test I'm using the program ModbusMAT 1.1

Can anyone help?

Thank you


Code:
#include <24FJ128GA204.h>

#device ICD=TRUE

#FUSES NOOSCIO
#FUSES PR
#FUSES HS
#FUSES NOWDT                    // No Watch Dog Timer
#FUSES NOJTAG                   // JTAG disabled
#FUSES NOCKSNOFSM               // Clock Switching is disabled, fail Safe clock monitor is disabled
#FUSES NOIESO                   // Internal External Switch Over mode disabled
#FUSES NOWPFP                   // Write/Erase Protect Page Start/End Location, set to page 0
#FUSES NOBROWNOUT               // No brownout reset
#FUSES NODSBOR                  // BOR disabled in Deep Sleep
#FUSES NODSWDT                  // Deep Sleep Watchdog Timer disabled
#FUSES NODS                     // Deep Sleep operation is always disabled

#use delay(clock=20MHz, crystal)

#pin_select U2TX=PIN_C0         
#pin_select U2RX=PIN_C2
//#use rs232(UART2, baud=9600,enable=PIN_C1,errors, stream=RS485)

#define MODBUS_TYPE                     MODBUS_TYPE_SLAVE
#define MODBUS_SERIAL_TYPE              MODBUS_RTU
#define MODBUS_SERIAL_RX_BUFFER_SIZE    64
#define MODBUS_SERIAL_BAUD              9600                 // 9600
#define MODBUS_SERIAL_INT_SOURCE        MODBUS_INT_RDA2      // Uses hardware UART
#define MODBUS_SERIAL_ENABLE_PIN        PIN_C1               // Controls DE pin for RS485
#define MODBUS_ADDRESS                  0x01

#define MODBUS_TIMER_USED               MODBUS_TIMER_T2   
#define MODBUS_TIMER_UPDATE             MODBUS_TIMER_ISR 

#include <modbus.c>

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()
{
   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);
   
   modbus_init();

   while(TRUE)
   {
     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] || 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
               {
                   int8 data;

                   if(modbus_rx.func == FUNC_READ_COILS)
                        data = coils>>(modbus_rx.data[1]);      //move to the starting coil
               
                   else
                       data = inputs>>(modbus_rx.data[1]);      //move to the starting input

                  data = data & (0xFF>>(8-modbus_rx.data[3]));  //0 out values after quantity

                  if(modbus_rx.func == FUNC_READ_COILS)
                       modbus_read_coils_rsp(MODBUS_ADDRESS, 0x01, &data);
                  else
                       modbus_read_discrete_input_rsp(MODBUS_ADDRESS, 0x01, &data);

                  event_count++;
               }
               
               break;
           
            case FUNC_READ_HOLDING_REGISTERS:
           
            case FUNC_READ_INPUT_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
                 {
                  if(modbus_rx.func == FUNC_READ_HOLDING_REGISTERS)
                     modbus_read_holding_registers_rsp(MODBUS_ADDRESS,(modbus_rx.data[3]*2),hold_regs+modbus_rx.data[1]);
                  else
                     modbus_read_input_registers_rsp(MODBUS_ADDRESS,(modbus_rx.data[3]*2),input_regs+modbus_rx.data[1]);

                  event_count++;
                 }
             
               break;
           
            case FUNC_WRITE_SINGLE_COIL:      //write coil
               if(modbus_rx.data[0] || modbus_rx.data[3] || modbus_rx.data[1] > 8)
                  modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS);
               else if(modbus_rx.data[2] != 0xFF && modbus_rx.data[2] != 0x00)
                  modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_VALUE);
               else
               {
                  if(modbus_rx.data[2] == 0xFF)
                     bit_set(coils,modbus_rx.data[1]);
                  else
                     bit_clear(coils,modbus_rx.data[1]);

                  modbus_write_single_coil_rsp(MODBUS_ADDRESS,modbus_rx.data[1],((int16)(modbus_rx.data[2]))<<8);

                  event_count++;
               }
           
               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[2],modbus_rx.data[3]);

                  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],modbus_rx.data[j+1]);

                  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);
         }
      }
  }
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Dec 27, 2016 12:53 pm     Reply with quote

Go into the file that has the modbus_kbhit() function in it and put
breakpoints in it. Find out what line of code is causing the problem.
Quote:
c:\program files\picc\drivers\modbus_app_layer.c

It calls modbus_check_timeout(), in this file:
Quote:
c:\program files\picc\drivers\modbus_phy_layer_rtu.c

That routine calls get_ticks() and modbus_timeout_now().

Anyway, you can keep placing breakpoints farther inside (if necessary)
until you find the line of code that's causing the problem.
Ttelmah



Joined: 11 Mar 2010
Posts: 19329

View user's profile Send private message

PostPosted: Tue Dec 27, 2016 1:08 pm     Reply with quote

I think you may find this is your problem:

#define MODBUS_SERIAL_ENABLE_PIN PIN_C1 // Controls DE pin for RS485

The CCS driver has two defines controlling the buffer. The comment in the file is not very clear.

The MODBUS_SERIAL_ENABLE_PIN is used to control the buffer on/off pin.
MODBUS_SERIAL_RX_ENABLE, is the line used to control the buffer direction.

Normally you don't need MODBUS_SERIAL_ENABLE_PIN, however you must have MODBUS_SERIAL_RX_ENABLE to control the bus direction. Obviously if the bus is not being set to receive, then your receive interrupt will never see anything.....
Orcino



Joined: 07 Sep 2003
Posts: 56

View user's profile Send private message

PostPosted: Tue Dec 27, 2016 4:07 pm     Reply with quote

Hi Ttelmah,

I changed the lines you mentioned, but not solved.

When the program is compiled, shows the following messages.

--- Info 300 "C:\Program Files (x86)\PICC\Drivers\modbus_phy_layer_rtu.c" Line 25(1,1): More info: Timer 1 tick time is 102,40 us
>>> Warning 216 "exemplo_modbus_slave.c" Line 251(1,2): Interrupts disabled during call to prevent re-entrancy: (modbus_enable_timeout)
>>> Warning 216 "exemplo_modbus_slave.c" Line 251(1,2): Interrupts disabled during call to prevent re-entrancy: (modbus_calc_crc)


Is that why does not work ?
Ttelmah



Joined: 11 Mar 2010
Posts: 19329

View user's profile Send private message

PostPosted: Wed Dec 28, 2016 4:11 am     Reply with quote

No. They use the CRC routine both inside and outside the interrupt (silly, they should just duplicate it), and the enable is a tiny routine, so 'fair enough'.

I'd be going through your hardware really carefully. How is the RS485 buffer actually wired?. The 'standard' way is to have the buffer permanently enabled (hence not needing the DE line), and setup so it receives all the time it is not transmitting. Then the RX enable controls the actual direction it is working. You should also have a pull-up resistor on the RX line out of the buffer (otherwise you can get spurious 'garbage' received when it is not receiving). Similarly, have you got the bus properly biased when idle?. This wouldn't cause a problem sending simple messages each way, but will with Modbus.

Do you have a logic analyser or scope?. You need to verify that your PIC is receiving data when the PC program sends. Then you will know that the buffer is setup the correct way for this driver.

Once you are sure that data is actually arriving at the PIC, step into PCM_programmer's suggestion and debug deeper into the routine that hangs.
Orcino



Joined: 07 Sep 2003
Posts: 56

View user's profile Send private message

PostPosted: Wed Dec 28, 2016 12:04 pm     Reply with quote

Thanks Ttelmah.

The problem was in the configuration of the communication. Parity was disabled on the MASTER.

I'm with a doubt. How to write the records ? I want to use the function 3 -HOLDING_REGISTERS.

I need to send 4 variables to the PLC.
Orcino



Joined: 07 Sep 2003
Posts: 56

View user's profile Send private message

PostPosted: Wed Dec 28, 2016 1:42 pm     Reply with quote

I found out just put the values in the hold_regs[].

Thanks
Ttelmah



Joined: 11 Mar 2010
Posts: 19329

View user's profile Send private message

PostPosted: Thu Dec 29, 2016 2:34 am     Reply with quote

Well spotted.

Sounds as if you have moved nicely forwards. Smile
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