This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Regarding Modbus

Hai 

I am doing project  on modbus communication.I have a small doubt in this.

My objective is i want to monitor the slave device(socomec energy meter)data from my microcontroller for this i written the code like this but i am not getting any data reply back.please suggest me i am new with modbus communication whre i did wrong.

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/rom.h"
#include "grlib/grlib.h"
#include "drivers/cfal96x64x16.h"
#include "driverlib/pin_map.h"

void tx(unsigned char);
void clearbuff(void);
void data(unsigned char *);
void Crc_cal(void);

unsigned char m[150],mess1[10];
unsigned char mess[10];
//unsigned char message[]={'0x05','0x03','0xc5','0x52','0x00','0x02','0x58','0x92','\0'};
//const char message[]={&H05,&H03,&Hc5,&H52,&H00,&H02,&H58,&H92};
unsigned int low_byte,high_byte;
int count=0,count10=0,count1=0;
int j;
unsigned short int crc,this_byte,i,shift,lastbit;

void
UARTIntHandler(void)
{

++count10;
SysCtlDelay(10000);
uint32_t ui32Status;

//
// Get the interrrupt status.
//
ui32Status = ROM_UARTIntStatus(UART0_BASE, true);

//
// Clear the asserted interrupts.
//
ROM_UARTIntClear(UART0_BASE, ui32Status);

//
// Loop while there are characters in the receive FIFO.
//
while(ROM_UARTCharsAvail(UART0_BASE))

{
/* while(!ADCIntStatus(ADC0_BASE, 1, false))
{
}*/
m[count]=ROM_UARTCharGetNonBlocking(UART0_BASE);

// ROM_UARTCharPutNonBlocking(UART0_BASE,m[count]);

count++;

if(count>=100)
{
//clearbuff();
// if(count==100)
count=0;
// clearbuff((unsigned char *)m);
}

}


// count10=0;
}

 

int
main(void)
{
//tRectangle sRect;
//tContext sContext;

//
// Enable lazy stacking for interrupt handlers. This allows floating-point
// instructions to be used within interrupt handlers, but at the expense of
// extra stack usage.
//
ROM_FPULazyStackingEnable();

//
// Set the clocking to run directly from the crystal.
//
ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_16MHZ);

ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);

GPIOPinConfigure(GPIO_PA0_U0RX);

GPIOPinConfigure(GPIO_PA1_U0TX);

ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

ROM_UARTConfigSetExpClk(UART0_BASE, ROM_SysCtlClockGet(), 9600,
(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
UART_CONFIG_PAR_NONE));

UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);

// UARTStdioConfig(0, 115200, 16000000);

UARTFIFOEnable(UART0_BASE);

UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX1_8, UART_FIFO_RX1_8);

UARTTxIntModeSet(UART0_BASE, UART_TXINT_MODE_FIFO);

// ROM_UARTIntDisable(UART0_BASE, UART_INT_TX);

ROM_UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT);

ROM_IntEnable(INT_UART0);

UARTEnable(UART0_BASE);

while(1)
{

data("0x05");
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);

data("0x03");
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);

data("0xC5");
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);

data("0x52");
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);


data("0x00");
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);

data("0x02");
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);


data("0x58");
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);

data("0x92");
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);
SysCtlDelay(SysCtlClockGet() / 12);

}
}

void data(unsigned char *z)
{
while(*z!='\0')
{
ROM_UARTCharPutNonBlocking(UART0_BASE, *z++);

}
}

  • A few quick observations
    - That's not valid output for Modbus RTU, it does not expect a set of strings.
    - From memory, I don't think that output is valid for Modbus ASCII either
    - The arbitrary delays are odd
    - I don't see where you are actually expecting a reply, you appear to just be sending in an infinite loop

    A couple of suggestions
    - If your peripheral supports Modbus ASCII, start with that. It's easier to program since it does not have strict timing and can be simulated/debugged with a terminal by hand and serial sniffers will produce logs easily hand parse-able
    - If this is a commercial enterprise seriously consider an available Modbus library (at least look at the possibility even if not a commercial project. I think there are open source versions you may be able to learn from).
    - Look at improving your skills and implement Test Driven Development. It would give you a solid set of tests to develop/maintain your protocol support.

    I'm presuming you have a document on the Modbus protocol and are not just depending on the manual for your meter.

    Robert
  • Hello Surendra,

    Though not an issue but the following code is not good. Why? because you have set the system to run from Clock A, configured the UART to get a baud from Clock A and then changed the UART to Clock B. In this case A=B=16MHz so it would not matter, but the PIOSC has a larger variation, so you may want to continue on Clock A.

    ROM_UARTConfigSetExpClk(UART0_BASE, ROM_SysCtlClockGet(), 9600,
    (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
    UART_CONFIG_PAR_NONE));

    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);

    The next thing to do is connect a scope on TX and RX and monitor what the response from the external device is for each command you send.

    Regards
    Amit
  • Thank you for your valuable reply.My slave is only support for Modbus RTU communication.I think it is valid format to send the data to the slave .Here i am sending the hexadecimal address.

    0x05 is the slave ID
    0x03 is the Function code(Here i want to read the read holding register data)
    0xC5 & 0x52 (dec 50512)is the address of the read holding register.
    0x00 & 0x02 ---indicates that no of registers
    0x58 & 0x92 is the CRC

    If it is not correct,then what is the possible way to follow?I should only follow the RTU frame format.
    one more thing before doing this i tested in the modscan software in the format of Modbus RTU ,there i got the data of particular register.
    now i am transmitting the same data from my conroller (where i am used the transmitted data in the modscan software.)
    please suggest me i am new with modbus communication.
  • surendra malampati said:
    My slave is only support for Modbus RTU communication

    OK, that's a harder task but certainly doable.  You may want to find an open source library to at least study.

    surendra malampati said:
    Here i am sending the hexadecimal address.

    No, you are not.  You are sending a string representation of a hexadecimal number and then inserting a large delay. Modbus RTU is sensitive to delays, I suspect it's going to see each string you send as a separate invalid packet.

    surendra malampati said:
    now i am transmitting the same data from my conroller (where i am used the transmitted data in the modscan software.)

    No and the best way to see that is to capture the output of modscan with a serial terminal program and compare that to a capture from your micro's output.  They will be very different. Modbus RTU is a binary protocol.

    There are multiple serial terminal programs that will do the job I'm sure.  One is realterm which will also display the serial data in hex which is likely to be useful to you.

    Robert

  • Hai robert thanks for your reply

    can i send Hex value like this 

    data(0x05);

    void data(unsigned char z)

    {

    ROM_UARTCharPutNonBlocking(UART0_BASE, z);

    }

  • Is there any free supporting modbus library for TM4C controllers?
  • lmgtfy.com

    You may not find something TIVA specific but there will likely be microcontroller versions. Modifying to use different serial ports and timers should be straightforward compared to writing it originally. You do have the Modbus specification, correct?

    Robert
  • Provided ROM_UARTCharPutNonBlocking is 8 bit clean (and I think it is) then that will send the 8 bit integer with the value of 5

    Note: This is a nit I'm picking but I think it is an important one since it suggests you do not understand what is happening
    - You are not sending a hex value, you are sending a byte (or better think of it as an unsigned 8 bit integer). data(5); data(0x5); data(05); and data('\05'); all are equivalent
    - the prototype for data is probably better as void data(uint8_t z); to emphasize you are not sending strings and characters.

    Make sure you read the timing requirements for Modbus RTU

    Robert
  • Make sure you read the timing requirements for Modbus RTU

    This is the important part. While the character/message handling is often handled in an easily portable way, the inter-character timeout and the inter-message timeout is very hardware specific, and most critical (for Modbus RTU). Modbus ASCII is easier to handle in this regard.

  • Still i am not getting an acknowledgement from a slave device please help me.I have been trying with different methods but i am not getting an acknowledgement. Modbus RTU is the hard task and i am strgulling with this .please help me

     

  • csn i use SSI(synchronous serial interface) for modbus application? 

  • surendra malampati said:

    csn i use SSI(synchronous serial interface) for modbus application? 

    Why would you think you might be able to?

    Robert

  • surendra malampati said:

    Still i am not getting an acknowledgement from a slave device please help me.I have been trying with different methods but i am not getting an acknowledgement. Modbus RTU is the hard task and i am strgulling with this .please help me

     

    You are going to need to do most of this  yourself.  I can only offer general guidelines for implementing

    Option 1:

    Find a free/open source Modbus library for microcontrollers and port

    Option 2:

    Find a commercial Modbus library for microcontrollers.  This is likely to still involve work to port

    Option 3:

    Build your own

    You will need (in addition to the compiler and other tools you already have)

    • A copy of the Modbus standard
    • A terminal emulator that will log data (preferably one that will show the data in hex)
    • Your brain in gear
    • Time and patience
    • A custom cable to snoop on the Modbus.
    • An oscilloscope (preferably a storage oscilloscope)

    Then proceed in steps

    1. Using the Modbus tool you have build a simple query and test it
    2. Using the terminal emulator capture the output of the Modbus tool
    3. Compare the output to the standard.  Make sure you understand what all the bytes mean and why they have the values they do
    4. Check the timing of the output from the Modbus tool.  Make sure you understand the allowable and mandatory timing both between characters and between packets. This is important
    5. Now you can emulate this message and see if you get a response. Verify with the oscilloscope and terminal emulator that you are actually sending the message over the wire and that the timing is correct.
    6. Create routines to generate rather than just send a preassembled packet. Use TDD to test on the PC before testing in the micro
    7. Test routines in the micro to verify they give the same result as the hand assembled packets
    8. Continue to build up the routines until you have enough to support your application
    9. Now you can write your application

    I really suggest one of the first two options but the build your own will give you lots of learning opportunities.  Just expect a few metaphorical skinned knuckles.

    One final thought occurs. Both your micro and the device you are communicating with are using the same serial driver? (IE RS-485 or RS-232) If not, then nothing else will matter.

    Robert

  • Perhaps others have noted - post has moved "far beyond" TM4C related - forum now is, "Any/All Help Central!"

    When fishing for big fish - ocean rather than small pond - is indicated.

    While Robert/few others have "tried to assist" - would not your "fishing" improve if you focused on a proper forum - or Modbus community? (that ain't here!)

    Contacting a manufacturer of such devices - and asking for references/resources - may turn up a list of skilled experts who will assist - but not for free!

    Elephant in this room remains - why do you become involved in projects (far) outside your experience & know-how? Results you now suffer are predictable - are they not - and suggest that "better choices" must be made...

    Your first line - your opening post - stated, "I have SMALL doubt!"    Is this (still) small?    Was that an honest assessment?   Does this not matter?