View previous topic :: View next topic |
Author |
Message |
lisek_lichu
Joined: 27 Aug 2012 Posts: 23
|
modbus RTU example code explanation |
Posted: Sun Aug 11, 2013 3:22 pm |
|
|
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 i need to sleep with everything i have read today and start tomorrow to continue.
Thanks in advance a lot for answers.
Lisek |
|
![](templates/subSilver/images/spacer.gif) |
lisek_lichu
Joined: 27 Aug 2012 Posts: 23
|
|
Posted: Tue Aug 13, 2013 4:14 pm |
|
|
I think that i gave too many questions at one time so nobody wants to answer it
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. |
|
![](templates/subSilver/images/spacer.gif) |
Mvedovetto
Joined: 17 Aug 2007 Posts: 28
|
Re: modbus RTU example code explanation |
Posted: Sat Feb 29, 2020 12:20 pm |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9176 Location: Greensville,Ontario
|
|
Posted: Sun Mar 01, 2020 6:17 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19375
|
|
Posted: Sun Mar 01, 2020 7:28 am |
|
|
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)..... |
|
![](templates/subSilver/images/spacer.gif) |
Mvedovetto
Joined: 17 Aug 2007 Posts: 28
|
|
Posted: Sun Mar 01, 2020 8:30 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Mvedovetto
Joined: 17 Aug 2007 Posts: 28
|
|
Posted: Sun Mar 01, 2020 9:06 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Mar 01, 2020 9:22 am |
|
|
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;
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
Mvedovetto
Joined: 17 Aug 2007 Posts: 28
|
|
Posted: Sun Mar 01, 2020 10:02 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
Mvedovetto
Joined: 17 Aug 2007 Posts: 28
|
[#USE TIMER ... NOISR |
Posted: Mon Mar 02, 2020 2:12 am |
|
|
If #USE TIMER has the option NOISR, it seems to run |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19375
|
|
Posted: Mon Mar 02, 2020 3:07 am |
|
|
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..... |
|
![](templates/subSilver/images/spacer.gif) |
Mvedovetto
Joined: 17 Aug 2007 Posts: 28
|
|
Posted: Mon Mar 02, 2020 4:08 am |
|
|
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]) |
|
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9176 Location: Greensville,Ontario
|
|
Posted: Mon Mar 02, 2020 5:37 am |
|
|
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' ! |
|
![](templates/subSilver/images/spacer.gif) |
Mvedovetto
Joined: 17 Aug 2007 Posts: 28
|
|
Posted: Mon Mar 02, 2020 6:08 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9176 Location: Greensville,Ontario
|
|
Posted: Mon Mar 02, 2020 6:31 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
|