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 RTU example code explanation
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
lisek_lichu



Joined: 27 Aug 2012
Posts: 23

View user's profile Send private message

modbus RTU example code explanation
PostPosted: Sun Aug 11, 2013 3:22 pm     Reply with quote

hello,

I am trying to use modbus with my PIC16f628A microcontroller and I started to read and analyze example codes given from CCS modbus.c, ex_modbus_slave.

I have few questions about using some variables:


1) I see that 2 byte modbus_serial_crc.b is used to calculate CRC of each data received byte by byte and also when we send data. When we finish sending data, two bytes CRC calculated are sent at the end. But for what is 16bit modbus_serial_crc.d?

We set it to 0xFFFF at the beginning of modbus_serial_send_start() and also set it to 0xFFFF at the end of modbus_serial_send_stop().

Additionally we set it to 0xFFFF at timer2 interrupt routine only when we are in MODBUS_GETADDY state.

And at the end we check it in timer2 interrupt routine if it is 0x0000 but when it could change to 0x0000 and for what is this variable?


2) for what is variable modbus_serial_new?

at the beginning it is zero (FALSE).

We can start parsing incoming char in incomming_modbus_serial() only if modbus_serial_new==FALSE
in modbus_kbhit() routine we return FALSE if modbus_serial_new==FALSE
and also in some other functions it appears so what is this variable describing? For what is it?
What means if it is TRUE and what means if it is FALSE?

3) In interrupt routine incomming_modbus_serial() at the end we turn on timer modbus_enable_timeout(TRUE), why it is set to count 20ms? should that value be always 20ms or it can be changed? what does it depend?

4) Why in incomming_modbus_serial() in state MODBUS_GETDATA we compare length of received data with buffer width and if we reach limit of buffer we override last char with new one instead of sending some exception? Or maybe it is left like that because CRC then will be not correct so we will know that something is not good with received data.

5) In ex_modbus_slave modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS); shouldn't it has instead of modbus_rx.func something like modbus_rx.func || 0x80? because in exception in response function code should have 1 in MSB or am I wrong?

Ohhhh I think it is enough for today Smile i need to sleep with everything i have read today and start tomorrow to continue.

Thanks in advance a lot for answers.
Lisek
lisek_lichu



Joined: 27 Aug 2012
Posts: 23

View user's profile Send private message

PostPosted: Tue Aug 13, 2013 4:14 pm     Reply with quote

I think that i gave too many questions at one time so nobody wants to answer it Smile

5) I get answer for this. In modbus_exception_rsp function in modbus.c file is added one bit in MSB "func|0x80"
But it was the most simple question from this list, the rest it not so easy for me


so 4 questions has left.
Mvedovetto



Joined: 17 Aug 2007
Posts: 28

View user's profile Send private message Send e-mail

Re: modbus RTU example code explanation
PostPosted: Sat Feb 29, 2020 12:20 pm     Reply with quote

lisek_lichu wrote:

1) I see that 2 byte modbus_serial_crc.b is used to calculate CRC of each data received byte by byte and also when we send data. When we finish sending data, two bytes CRC calculated are sent at the end. But for what is 16bit modbus_serial_crc.d?

We set it to 0xFFFF at the beginning of modbus_serial_send_start() and also set it to 0xFFFF at the end of modbus_serial_send_stop().

Additionally we set it to 0xFFFF at timer2 interrupt routine only when we are in MODBUS_GETADDY state.

And at the end we check it in timer2 interrupt routine if it is 0x0000 but when it could change to 0x0000 and for what is this variable?


2) for what is variable modbus_serial_new?

at the beginning it is zero (FALSE).

We can start parsing incoming char in incomming_modbus_serial() only if modbus_serial_new==FALSE
in modbus_kbhit() routine we return FALSE if modbus_serial_new==FALSE
and also in some other functions it appears so what is this variable describing? For what is it?
What means if it is TRUE and what means if it is FALSE?


Lisek


It looks a no sense: I don't understand too. No one else tried to explain in these years here or in other threads?


lisek_lichu wrote:


4) Why in incomming_modbus_serial() in state MODBUS_GETDATA we compare length of received data with buffer width and if we reach limit of buffer we override last char with new one instead of sending some exception? Or maybe it is left like that because CRC then will be not correct so we will know that something is not good with received data.
Lisek


I agree: correct CRC, but somewhere a control is needed

lisek_lichu wrote:


5) In ex_modbus_slave modbus_exception_rsp(MODBUS_ADDRESS,modbus_rx.func,ILLEGAL_DATA_ADDRESS); shouldn't it has instead of modbus_rx.func something like modbus_rx.func || 0x80? because in exception in response function code should have 1 in MSB or am I wrong?
Lisek


Legal function codes are 1..127: MSb must be 0
temtronic



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

View user's profile Send private message

PostPosted: Sun Mar 01, 2020 6:17 am     Reply with quote

I don't use MODBUS however you should get a book about it. I'l assume the names CCS uses are the same or similar to the 'industry'. I have no doubt the CCS examples will work( the 'master' does compile using the 628A) !
Pay careful attention to hardware especially bus pullup values.
Once you get the master-slave program working, copy them to 'my-master, my_slave' and modufy the COPIES , as you need to.
Do NOT modify the original CCS supplied programs.
Ttelmah



Joined: 11 Mar 2010
Posts: 19375

View user's profile Send private message

PostPosted: Sun Mar 01, 2020 7:28 am     Reply with quote

This is a relaunch of a thread that is seven years old. Forget it.

In fact the questions were basic not understanding C (so there is a union
giving the .b and .d variables, and the poster didn't understand how a union
worked).....
Mvedovetto



Joined: 17 Aug 2007
Posts: 28

View user's profile Send private message Send e-mail

PostPosted: Sun Mar 01, 2020 8:30 am     Reply with quote

Thank you all for reply!

Ttelmah, I know this is an old thread, but, apart from union, I did not understand how variable modbus_serial_new works in CCS modbus driver.

I miss to understand how modbus_kbhit() works too and I need to understand code before using it.

I was looking for some explanation on the forum and just this thread seemed to fit my needs.

I'm using 5.092 PCM compiler.

Marco
Mvedovetto



Joined: 17 Aug 2007
Posts: 28

View user's profile Send private message Send e-mail

PostPosted: Sun Mar 01, 2020 9:06 am     Reply with quote

temtronic wrote:
I don't use MODBUS however you should get a book about it. I'l assume the names CCS uses are the same or similar to the 'industry'. I have no doubt the CCS examples will work( the 'master' does compile using the 628A) !
Pay careful attention to hardware especially bus pullup values.
Once you get the master-slave program working, copy them to 'my-master, my_slave' and modufy the COPIES , as you need to.
Do NOT modify the original CCS supplied programs.


I studied MODBUS on official specification and I defined the whole structure of data that I need for my application, also I wrote some code to test. It compiles, but app does not run as expected.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Mar 01, 2020 9:22 am     Reply with quote

Regarding 'modbus_serial_new', I think it's a flag used to tell the program
if it's processing an existing message, or it's finished and waiting for a new
message.

Look at this routine: incomming_modbus_serial()
In this file: modbus_phy_layer_ascii.c
In the code below, if the state is "stop", and if we got a newline character
then we've found the end of the incoming message, so we're now waiting
for a new message to arrive. So 'modbus_serial_new' is set to TRUE.
Code:

      else if(modbus_serial_state==MODBUS_STOP)
      {
         if(c=='\n')
         {
            modbus_serial_lrc=((0xFF-modbus_serial_lrc)+1);
            if(modbus_serial_lrc==data)
               modbus_serial_new=TRUE;
         }
         modbus_serial_state=MODBUS_START;
         two_characters=0;
      }
Mvedovetto



Joined: 17 Aug 2007
Posts: 28

View user's profile Send private message Send e-mail

PostPosted: Sun Mar 01, 2020 10:02 am     Reply with quote

I'm using RTU. I'm trying to workout with slave.

incomming_modbus_serial() receives from USART char c and saves the byte into modbus_rx struct if modbus_serial_new=FALSE.
So it's the same as for ASCII. In RTU mode, modbus_serial_new is set only here:
Code:

// Purpose:    Handles a timeout when waiting for a response
// Inputs:     None
// Outputs:    None
// Not used for ASCII mode
void modbus_timeout_now(void)
{
   if((modbus_serial_state == MODBUS_GETDATA) && (modbus_serial_crc.d == 0x0000) && (!modbus_serial_new))
   {
      modbus_rx.len-=2;
      modbus_serial_new=TRUE;
   } else {
      modbus_serial_new=FALSE;
   }

   modbus_serial_crc.d=0xFFFF;
   modbus_serial_state=MODBUS_GETADDY;
   modbus_enable_timeout(FALSE);
}


this function is called from this one:


Code:
// Purpose:    Check if we have timed out waiting for a response
// Inputs:     None
// Outputs:    None
// Not used for ASCII mode
void modbus_check_timeout(void)
{
   #if (MODBUS_TIMER_UPDATE == MODBUS_TIMER_NOISR)
    // declaring #USE TIMER with NOISR make get_ticks() increment the upper bits of the tick timer
    // so the function modbus_check_timeout must be called more often than the timer overflow
    // rate. The get_ticks() below will not always be called due to short circuit evaluation
    get_ticks();
   #endif
   // modbus_timeout_enabled must be checked before get_ticks()
   // so that if an interrupt happens it cannot be enabled after
   // an old timer value is used in comparison
   if(modbus_timeout_enabled && (get_ticks() > MODBUS_GETDATA_TIMEOUT))
   {
     modbus_timeout_now();
   }
}


and in ex_modbus_slave.c only if modbus_kbhit() returns TRUE it is possible to process FRAME.

in modbus_app_layer :

Code:

// Purpose:    Get a message from the RS485 bus and store it in a buffer
// Inputs:     None
// Outputs:    TRUE if a message was received
//             FALSE if no message is available
// Note:       Data will be filled in at the modbus_rx struct:
int1 modbus_kbhit()
{
   #if(MODBUS_SERIAL_TYPE == MODBUS_RTU)
   modbus_check_timeout();
   #endif

   if(!modbus_serial_new)
     return FALSE;
   else if(modbus_rx.func & 0x80)           //did we receive an error?
   {
      modbus_rx.error = modbus_rx.data[0];  //if so grab the error and return true
      modbus_rx.len = 1;
   }
   modbus_serial_new=FALSE;
   return TRUE;
}


So I don't understand in which way an RTU FRAME is recognized and then mosbus_kbhit() can return TRUE.

Moreover... to calculate timeout is used #USE TIMER:
Code:

 #USE TIMER(TIMER=1,TICK=.1ms,BITS=16, ISR)


but no isr routine has been defined in drivers!

I have this version created by the upgrade of CCS compiler:

Code:


//////////////////////////////////////////////////////////////////////////////////////////
////                                                                                  ////
//// Revision history:                                                                ////
////  May 8, 2009       Made PCD Compatible                                           ////
////  August 21, 2009   Added Modbus ASCII protocol                                   ////
////  May 20, 2010      Changed variables to unsigned for PCD and if #device ANSI is  ////
////                    used for PCM or PCH. Fixed bug when multiple UARTS are used   ////
////                    on PIC.                                                       ////
////  July 20, 2011     Seperated modbus.c into 7 files, including this one. The code ////
////                    was seperated into header and c files for the Physical and    ////
////                    Application layers, and RTU code and ASCII code.              ////
////  November 1, 2011  Added Modbus TCP/IP protocol.                                 ////
////  Janurary 9, 2013  Added support for Even and Odd Parity for RTU and ASCII       ////
////                    modes.                                                        ////
////                                                                                  ////
//////////////////////////////////////////////////////////////////////////////////////////




Perhaps, it's very simple, but I'm not able to see it.
Mvedovetto



Joined: 17 Aug 2007
Posts: 28

View user's profile Send private message Send e-mail

[#USE TIMER ... NOISR
PostPosted: Mon Mar 02, 2020 2:12 am     Reply with quote

If #USE TIMER has the option NOISR, it seems to run
Ttelmah



Joined: 11 Mar 2010
Posts: 19375

View user's profile Send private message

PostPosted: Mon Mar 02, 2020 3:07 am     Reply with quote

The modbus physical layer uses a timer. You can change it by setting
the #define 'MODBUS_TIMER_USED', to MODBUS_TIMER_T2. By default
it is using Timer1, so your use of timer1, interferes with it.....
Mvedovetto



Joined: 17 Aug 2007
Posts: 28

View user's profile Send private message Send e-mail

PostPosted: Mon Mar 02, 2020 4:08 am     Reply with quote

Ttelmah wrote:
The modbus physical layer uses a timer. You can change it by setting
the #define 'MODBUS_TIMER_USED', to MODBUS_TIMER_T2. By default
it is using Timer1, so your use of timer1, interferes with it.....


Thank you for reply.
I don't use any timer: I just send in loop three words with delay_ms(1000).

Anyway I'll try to change timer also if I don't find any isr routine that matches
Code:
#USE TIMER(TIMER=1,TICK=.1ms,BITS=16, ISR)
or
Code:
#USE TIMER(TIMER=2,TICK=.1ms,BITS=16, ISR])
temtronic



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

View user's profile Send private message

PostPosted: Mon Mar 02, 2020 5:37 am     Reply with quote

You need to understand that MODBUS is a 'try-to-do-everything-for-everyone' serial communications protocol or driver. As such it's overly complicated and only needs to be used when you have real MODBUS devices.It's very important to read every comment in the drivers and CCS example programs ! As Mr. T points out MODBUS NEEDS to use a timer, Timer1 is what CCS chose to use. Details....always need to read the 'fine print' !
Mvedovetto



Joined: 17 Aug 2007
Posts: 28

View user's profile Send private message Send e-mail

PostPosted: Mon Mar 02, 2020 6:08 am     Reply with quote

temtronic wrote:
You need to understand that MODBUS is a 'try-to-do-everything-for-everyone' serial communications protocol or driver. As such it's overly complicated and only needs to be used when you have real MODBUS devices.It's very important to read every comment in the drivers and CCS example programs ! As Mr. T points out MODBUS NEEDS to use a timer, Timer1 is what CCS chose to use. Details....always need to read the 'fine print' !


I have to communicate between my own devices. So I defined code for master and code for slave using CCS examples (I don't need to communicate with other "real" MODBUS devices). So I can tailor solution as well as I need.
I already defined data structure and I need just one modbus standard function (0x10 write multiple registers) in broadcast.
So everything should not bring to a lot of troubles.
To help me understand code, simply one of my question was where I can find isr timer1 routine, if it isn't a nonsense question.
In earlier messages I specified what's the matter for me. I ask here because, obviously, I can't find the answer.
temtronic



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

View user's profile Send private message

PostPosted: Mon Mar 02, 2020 6:31 am     Reply with quote

I opend the example 'ex_modbus' program. did a search for 'timer', located it ! Though my version uses timer2. I have an old version of compiler BTW so it's possible CCS has changed the code, using timer 1 instead of timer 2.

Jay
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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