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 Master/Slave Switch by parameter

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



Joined: 21 Mar 2020
Posts: 22

View user's profile Send private message

Modbus Master/Slave Switch by parameter
PostPosted: Thu Nov 26, 2020 4:06 pm     Reply with quote

Hi guys,

As you know the standard modbus library allows to switch master or slave via macro. But I need to switch it by a flag which will be controlled remotely and save into the eeprom. So I removed all MODBUS2_TYPE == xxxx statements successfully.

Modbus slave works very well. And the mcu sends a query to the slave node and the node reply. I have checked the interrupt and saw that the mcu receives. But there is a problem in the interrupt function below. The state doesn't jump to another state. I'm debugging with numbers to steps. It prints always 111. If I put debug_writeln(modbus2_serial_state); debugging function into each "if" statements, then it jumps to the another state.

Have you ever done similar project? How can I read the response of slave device properly?

Notes:
* MCU is PIC18F46K80
* Compiler version is 5.091.
* UART1 and INT_RDA are used with Modbus RTU
* Master and slave aren't allowed to run at same time
* I'm using modbus TCP/IP at same time. So I renamed library as modbus1 for TCP/IP and modbus2 for RTU.
* debug_writeln is my debugging function which includes printf with a soft-uart port

Code:
void incomming_modbus2_serial() {
   char c;

   c=fgetc(MODBUS2_SERIAL);

   if (!modbus2_serial_new)
   {
      if(modbus2_serial_state == MODBUS2_GETADDY)
      {
        [b]debug_writeln("111");[/b]
         modbus2_serial_crc.d = 0xFFFF;
         modbus2_rx.address = c;
         modbus2_serial_state++;
         modbus2_rx.len = 0;
         modbus2_rx.error=0;
      }
      else if(modbus2_serial_state == MODBUS2_GETFUNC)
      {
         [b]debug_writeln("222");[/b]
         modbus2_rx.func = c;
         modbus2_serial_state++;
      }
      else if(modbus2_serial_state == MODBUS2_GETDATA)
      {
         [b]debug_writeln("333");[/b]
         if (modbus2_rx.len>=MODBUS2_SERIAL_RX_BUFFER_SIZE)
        {
          modbus2_rx.len=MODBUS2_SERIAL_RX_BUFFER_SIZE-1;
        }
         modbus2_rx.data[modbus2_rx.len]=c;
         modbus2_rx.len++;
     }
     modbus2_enable_timeout(TRUE);
     modbus2_calc_crc(c);
   }

   //#if (MODBUS2_TYPE == MODBUS2_TYPE_MASTER)
      modbus2_serial_wait=MODBUS2_SERIAL_TIMEOUT;
   //#endif
}

_________________
Compiler v5.091+ Windows 10
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Nov 27, 2020 12:30 am     Reply with quote

Post the code for debug_writeln().
salihonur



Joined: 21 Mar 2020
Posts: 22

View user's profile Send private message

PostPosted: Fri Nov 27, 2020 11:19 am     Reply with quote

Hi,

Here is the debug file.

config file of the project
Code:

#define DEBUG                           TRUE
#define PIN_DBG_TX                      PIN_B7
#define PIN_DBG_RX                      PIN_A6


Debug.h

Code:
/*
 * File:   Debug.h
 * Author: SOZ
 *
 * Created on 06 Nisan 2019 Cumartesi, 01:23
 */

#ifndef DEBUG_H
#define   DEBUG_H

typedef union{
  char bytes[64]; 
}string;

#ifndef DEBUG_LED
#define DEBUG_LED                       FALSE
#endif

#ifndef DBG_BAUDRATE
#define DBG_BAUDRATE                    115200
#endif

#ifndef PIN_DBG_TX
#define PIN_DBG_TX                      PIN_C6
#define PIN_DBG_RX                      PIN_C7
#endif

#include "Debug.c"

#endif   /* DEBUG_H */



Debug.c
Code:

/*
 * File:   Debug.c
 * Author: SOZ
 *
 * Created on 06 Nisan 2019 Cumartesi, 01:23
 */

#ifndef DEBUG_C
#define   DEBUG_C

#ifdef DEBUG

/*
Format ===================
The format takes the generic form %nt. n is optional and may be 1-9 to specify how many characters are to be outputted, or 01-09 to indicate leading zeros, or 1.1 to 9.9 for floating point and %w output. t is the type and may be one of the following:
c   : Character
s   : String or character
u   : Unsigned int
d   : Signed int
Lu  : Long unsigned int
Ld  : Long signed int
x   : Hex int (lower case)
X   : Hex int (upper case)
Lx  : Hex long int (lower case)
LX  : Hex long int (upper case)
f   : Float with truncated decimal
g   : Float with rounded decimal
e   : Float in exponential format
w   : Unsigned int with decimal place inserted. Specify two numbers for n. The first is a total field width. The second is the desired number of decimal places.
 
 fprintf (stream, cstring, values...)
 fputc(cdata, stream)
 fputs (string, stream)
 */

#use rs232(baud=DBG_BAUDRATE, parity=N, xmit=PIN_DBG_TX, rcv=PIN_DBG_RX, bits=8, errors, stream=DEBUG_PORT)

void debug_write(int *p)
{
    restart_wdt();
    fprintf(DEBUG_PORT, p);
    restart_wdt();
}

void debug_write(int32 num)
{
    restart_wdt();
    fprintf(DEBUG_PORT, "%lu", num);
    restart_wdt();
}

void debug_write(float num)
{
    restart_wdt();
    fprintf(DEBUG_PORT, "%f", num);
    restart_wdt();
}

void debug_write_ip(unsigned int32 ipDouble)
{
    union
    {
        unsigned int8 v[4];
        unsigned int32 d;
    } ipUnion;

    ipUnion.d = ipDouble;
   
    for(int i=0; i<4; i++)
    {
        if(i != 0)
            debug_write(".");
        debug_write(ipUnion.v[i]);
    }
}

void debug_writeln(int *p)
{
    restart_wdt();
    fprintf(DEBUG_PORT, p);
    fprintf(DEBUG_PORT, "\r");
    restart_wdt();
}

void debug_writeln(int32 num)
{
    restart_wdt();
    fprintf(DEBUG_PORT, "%lu", num);
    fprintf(DEBUG_PORT, "\r");
    restart_wdt();
}

void debug_writeln(float num)
{
    restart_wdt();
    fprintf(DEBUG_PORT, "%f", num);
    fprintf(DEBUG_PORT, "\r");
    restart_wdt();
}

void debug_bytes_in_hex(int *bytes, int16 size)
{
    for(int16 i=0; i<size; i++)
    {
        if(i>0)
            fprintf(DEBUG_PORT, " ");
        fprintf(DEBUG_PORT, "%2X", bytes[i]);
        restart_wdt();
    }
}
#endif

#endif   /* DEBUG_C */


_________________
Compiler v5.091+ Windows 10
temtronic



Joined: 01 Jul 2010
Posts: 9107
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Nov 27, 2020 3:22 pm     Reply with quote

One problem I have is the fact you've got the WDT enabled. Typically for 'debug' purposes' WDT would NOT be enabled, and only enabled once the product was properly tested and ready for sale.

While I don't used MODbus, the 'library' should be 'stable' so I suspect the problem is in whatever code you've added.

Jay
salihonur



Joined: 21 Mar 2020
Posts: 22

View user's profile Send private message

PostPosted: Fri Nov 27, 2020 3:44 pm     Reply with quote

temtronic wrote:
One problem I have is the fact you've got the WDT enabled. Typically for 'debug' purposes' WDT would NOT be enabled, and only enabled once the product was properly tested and ready for sale.

While I don't used MODbus, the 'library' should be 'stable' so I suspect the problem is in whatever code you've added.

Jay


I have never had a problem with WDT. WDT isn't timeout yet. Actually this project has been working since 2014. I used to activate RTU Slave or TCP/IP via macro. But I needed to add master feature. First I splitted and renamed libraries for TCP/IP and RTU. Then I decided to activate modbus master automatically if the Modbus ID is set to 1, otherwise it will stay as a slave. I have no problem on RTU slave and TCP/IP. The problem only appears on master.
_________________
Compiler v5.091+ Windows 10
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Nov 27, 2020 5:50 pm     Reply with quote

Your complaint is that it fails with the line in bold below. It doesn't
advance to the next state.
Quote:

if(modbus2_serial_state == MODBUS2_GETADDY)
{
debug_writeln("111");
modbus2_serial_crc.d = 0xFFFF;
modbus2_rx.address = c;
modbus2_serial_state++;
modbus2_rx.len = 0;
modbus2_rx.error=0;
}

But if you replace the line in bold above with this, it works:
Quote:
debug_writeln(modbus2_serial_state);


The only thing I can think of is this: You're using function over-loading.
What if it doesn't work correctly in your version ? What if there's a bug
in the compiler ? You might get problems.

Try it with unique function names for your debug routines.
Rename the routines as shown below in bold.
Quote:

void debug_writeln_string(int *p)
{
restart_wdt();
fprintf(DEBUG_PORT, p);
fprintf(DEBUG_PORT, "\r");
restart_wdt();
}

void debug_writeln_int32(int32 num)
{
restart_wdt();
fprintf(DEBUG_PORT, "%lu", num);
fprintf(DEBUG_PORT, "\r");
restart_wdt();
}

void debug_writeln_float(float num)
{
restart_wdt();
fprintf(DEBUG_PORT, "%f", num);
fprintf(DEBUG_PORT, "\r");
restart_wdt();
}



Then edit your isr code to use the appropriate one for each test.
Example:
Quote:

if (!modbus2_serial_new)
{
if(modbus2_serial_state == MODBUS2_GETADDY)
{
debug_writeln_string("111");
modbus2_serial_crc.d = 0xFFFF;
modbus2_rx.address = c;
modbus2_serial_state++;
modbus2_rx.len = 0;
modbus2_rx.error=0;
}
else if(modbus2_serial_state == MODBUS2_GETFUNC)
{
debug_writeln_string("222");
modbus2_rx.func = c;
modbus2_serial_state++;
}
else if(modbus2_serial_state == MODBUS2_GETDATA)
{
debug_writeln_string("333");
if (modbus2_rx.len>=MODBUS2_SERIAL_RX_BUFFER_SIZE)
{
modbus2_rx.len=MODBUS2_SERIAL_RX_BUFFER_SIZE-1;
}
modbus2_rx.data[modbus2_rx.len]=c;
modbus2_rx.len++;
}
salihonur



Joined: 21 Mar 2020
Posts: 22

View user's profile Send private message

PostPosted: Sat Nov 28, 2020 2:18 pm     Reply with quote

I guess I couldn't explain the problem very well. Normally I don't need to debug what is going on there. I put some debug prints to track where the problem is. INT_RDA works very well. I can see incoming data.

I discovered that modbus2_serial_state isn't increased even though the it enters to if(modbus2_serial_state == MODBUS2_GETADDY) state. I track the state number by printing numbers like 111, 222, 333. But I don't see any other numbers except 111. I captured with the regular printf. You can see that it isn't get into the next state if I don't print it in every all state below.

Note: Of course Modbus data is validated by crc function. But there is a problem before it. There isn't any data validation check at this step.






Modbus query of master and the response of slave


_________________
Compiler v5.091+ Windows 10
salihonur



Joined: 21 Mar 2020
Posts: 22

View user's profile Send private message

PostPosted: Sat Nov 28, 2020 2:44 pm     Reply with quote

Eureka!!!!

I found the problem. I had disabled the timer setting in the Modbus library to use my timer setting and interrupt function. My timeout setting is lower than library's setting. I multiplied GET_DATA_TIMEOUT by 10, then it started to read the slave very well.



_________________
Compiler v5.091+ Windows 10
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