문제

I'm completely new to Modbus protocoll. My setup consists of three devices with different addresses. They're all connected to COM1 via RS232. I've used Modbus Poll to check the input-data, which works properly. What I want to do now, is reading the holding registers in a vc++ (MFC) application. For serial communication I use the MSComm class. I have written a little code, but I don't get Input at all.

My code at the moment:

BOOL Crs232test4Dlg::OpenConnection ()
{
    char error [513];

    try
    {
        if (! m_MSComm.GetPortOpen ())
        {
            m_MSComm.SetCommPort (1);
            m_MSComm.SetSettings ("9600,N,8,1");
            m_MSComm.SetInputLen (4);
            // Receive Data as Text
            m_MSComm.SetInputMode (0);
            m_MSComm.SetPortOpen (true);
            m_MSComm.SetCommID (1);
           return m_MSComm.GetPortOpen ();
        }
        AfxMessageBox ("Success!!!!", MB_OK);
        return TRUE;
    }

    catch (CException *e)
    {
        e->GetErrorMessage (error, 512);
        AfxMessageBox (error, MB_OK);
        return FALSE;
    }
}


void Crs232test4Dlg::OnVaisalaComm ()
{
    if (m_MSComm.GetCommEvent () == 2)
    {
        COleVariant in_dat;
        in_dat = m_MSComm.GetInput ();
        Sleep (100);
        CString strInput (in_dat.bstrVal);
        m_Input = m_Input + strInput;
        UpdateData (FALSE);
    }
}

I want to put out m_Input now, but it hasn't changed a bit. I also get the warning (Property is read-only) when setting SetCommID, which I don't think is important.

Can anyone please guide me, since I'm really clueless at the moment.

Regards

EDIT: According to a communication example, I've tried to handle the device like a file.

m_hCom = CreateFile(m_sComPort, 
        GENERIC_READ | GENERIC_WRITE,
        0, // exclusive access
        NULL, // no security
        OPEN_EXISTING,
        0, // no overlapped I/O
        NULL); // null template
// :(colon) Address=1 Function=3 Starting register= 40001 (To write 400001 or 0?)
Registers to read=4 checksum CR LF
char    strASCII[] = "3A 30 31 30 33 30 30 30 30 30 30 30 34 46 38 0D 0A";

bWriteRC = WriteFile (m_hCom, strASCII, strlen(strASCII), &iBytesWritten, NULL);

memset(sBuffer,0,sizeof(sBuffer));
// Reading output of the M3
bReadRC = ReadFile (m_hCom, &sBuffer, 1, &iBytesRead, NULL);

if (bReadRC && iBytesRead > 0)
    {
        sResult = sBuffer;
    }
    else
    {
        sResult = "Read Failed";
        dwError = GetLastError();

        sprintf(sMsg, "Read length failed: RC=%d Bytes read=%d, "
                "Error=%d ",
                bReadRC, iBytesRead, dwError);
        AfxMessageBox(sMsg);
    } 

I get the read length failed error. strASCII isn't separated normally, only for better overview now. I have checked the communication in Modbus Poll. My output is right, but it doesn't seem to get the data.

EDIT: I got it. Thank you very much for your help. I had put the wrong checksum.

도움이 되었습니까?

해결책 2

not an answer, but a guide for trouble shotting.

  • your best friends should be:

    1) null modem 232female<->232female cable with second computer that has com port (or laptop with usb->serial converter) ... soldering cable by your self wire to wire is maybe best solution.

    2) windows hyper-terminal simple but reliable application preinstalled on most windows... started in comPort mode, with same bitrate/parity/stopbits parameters that you expect from modules.


  • first check if connection and cable is ok by running hterm on both comps and 'chat' few sentences
  • second check if your program ok by running it on first comp, and hterm on other
  • Modbus modules sometimes do not send anything before Master sends some query on module address, so maybe your program need to send something first (for that investigation you can log your modbusPool with other comp connected instead MBUS-modules)

... with all respects to windows signaling queues and MSCOmm class that is probably ok, but to eliminate all possible reasons for communication failure in project start, maybe you should prefer simple threating COM port as file, and reading from it inside some while loop ... some short version of this example... Setting serial parameters at start and reading file named comX.

above link has good cSerialClass implementation on download, but simple primer without any error checking is here at pastebin .

다른 팁

MODBUS is by far more complex than just reading simple data via the serial port. Is is a complex data packet oriented protocol with complex synchronisation features. It specifies a master and a slave operation. You will not get anything out of a MODBUS device by using MSComm or Hyperterminal. The MODBUS protocol is pretty good documented already but not to that easy to get implemented. Many variations also exists. It will probably require some thousand lines of code to get the basics. A known and mature commercial library is maybe the better approach and this also include technical support, which is essential for this kind of products. For example, SuperCom, a commercial software library that offers MODBUS for serial and TCP data communications and also supports the MFC. Client (Master) and Slave functionality also included. And it offers many samples for well known compilers. There surely exist more commercial solutions there.

Two issues here:

1/ You cannot have three devices connected together with RS232. RS232 is point-to-point, which means only two devices can be connected together.

2/ A slave only sends data when queried by the master. If the master does not send a MODBUS request first, you'll never get a reply from the slaves.

PS: I've got a feeling that m_MSComm.SetCommID() should be called before the port is opended, not after.

In order to create the proper request, you can refer to the standard:

The first document will instruct you how to build the request (PDU), while the second document details how the request must be encapsulated in a "transport" frame (ADU), suitable for the serial communication.

The most common request is "Read Holding Registers" (func. #3). If your slave device has address 5, and you want to read two registers starting at address 10, then your request will look something like: 0x05 0x03 0x000A 0x0002 0x???? (where '????' is the CRC16 value, which I'm too lazy to calculate).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top