【问题标题】:Read after restart - RS232 Serial communication using Serial Library - C++重启后读取 - 使用串行库的 RS232 串行通信 - C++
【发布时间】:2015-06-15 15:44:59
【问题描述】:

我正在尝试通过使用 C++ 的串行库和在以下位置找到的一些示例,通过串行连接从 RS-232 读取数据: http://www.codeproject.com/Articles/992/Serial-library-for-C

是否有任何信号检测方法或事件让我知道。 我使用串行到 USB 连接器将 RxNeutral 仅连接到电路板,并使用 Visual Studio 2013 中的串行库并用 C++ 编写代码。

我想在手动重启时将从我的电路板传输的 ASCII 数据写入文本文件,这样我就可以轻松地解析文本文件中的数据。

我的板子只有在重新启动时才会发送数据。 我是串行连接的新手,我无法弄清楚如何让我的程序在电路板重置时读取数据。

我正在使用监听程序:

#define STRICT
#include <tchar.h>
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include "Serial.h"

//C++ headers
#include <iostream>
#include <fstream>
#include <string>

enum { EOF_Char = 27 };

int ShowError (LONG lError, LPCTSTR lptszMessage)
{
    // Generate a message text
    TCHAR tszMessage[256];
    wsprintf(tszMessage,_T("%s\n(error code %d)"), lptszMessage, lError);

    // Display message-box and return with an error-code
    ::MessageBox(0,tszMessage,_T("Listener"), MB_ICONSTOP|MB_OK);
    return 1;
}

//int __cdecl _tmain (int /*argc*/, char** /*argv*/)
int WINAPI _tWinMain(HINSTANCE /*hInst*/, HINSTANCE /*hInstPrev*/, LPTSTR /*lptszCmdLine*/, int /*nCmdShow*/)
{
    CSerial serial;
    LONG    lLastError = ERROR_SUCCESS;

    const char* Port_name = "COM3";

    // Attempt to open the serial port (COM1)
    lLastError = serial.Open(_T(Port_name),0,0,false);
    if (lLastError != ERROR_SUCCESS)
        return ::ShowError(serial.GetLastError(), _T("Unable to open COM-port"));

    // Setup the serial port (9600,8N1, which is the default setting)
    lLastError = serial.Setup(CSerial::EBaud9600,CSerial::EData8,CSerial::EParNone,CSerial::EStop1);
    if (lLastError != ERROR_SUCCESS)
        return ::ShowError(serial.GetLastError(), _T("Unable to set COM-port setting"));

    // Register only for the receive event
    lLastError = serial.SetMask(CSerial::EEventBreak |
                                CSerial::EEventCTS   |
                                CSerial::EEventDSR   |
                                CSerial::EEventError |
                                CSerial::EEventRing  |
                                CSerial::EEventRLSD  |
                                CSerial::EEventRecv);
    if (lLastError != ERROR_SUCCESS)
        return ::ShowError(serial.GetLastError(), _T("Unable to set COM-port event mask"));

    // Use 'non-blocking' reads, because we don't know how many bytes
    // will be received. This is normally the most convenient mode
    // (and also the default mode for reading data).
    lLastError = serial.SetupReadTimeouts(CSerial::EReadTimeoutNonblocking);
    if (lLastError != ERROR_SUCCESS)
        return ::ShowError(serial.GetLastError(), _T("Unable to set COM-port read timeout."));

    // Keep reading data, until an EOF (CTRL-Z) has been received
    bool fContinue = true;
    do
    {
        // Wait for an event
        lLastError = serial.WaitEvent();
        if (lLastError != ERROR_SUCCESS)
            return ::ShowError(serial.GetLastError(), _T("Unable to wait for a COM-port event."));
        else
            return ::ShowError(serial.GetLastError(), _T("Waiting for a COM-port event."));

        // Save event
        const CSerial::EEvent eEvent = serial.GetEventType();

        // Handle break event
        if (eEvent & CSerial::EEventBreak)
        {
            printf("\n### BREAK received ###\n");
        }

        // Handle CTS event
        if (eEvent & CSerial::EEventCTS)
        {
            printf("\n### Clear to send %s ###\n", serial.GetCTS()?"on":"off");
        }

        // Handle DSR event
        if (eEvent & CSerial::EEventDSR)
        {
            printf("\n### Data set ready %s ###\n", serial.GetDSR()?"on":"off");
        }

        // Handle error event
        if (eEvent & CSerial::EEventError)
        {
            printf("\n### ERROR: ");
            switch (serial.GetError())
            {
            case CSerial::EErrorBreak:      printf("Break condition");          break;
            case CSerial::EErrorFrame:      printf("Framing error");            break;
            case CSerial::EErrorIOE:        printf("IO device error");          break;
            case CSerial::EErrorMode:       printf("Unsupported mode");         break;
            case CSerial::EErrorOverrun:    printf("Buffer overrun");           break;
            case CSerial::EErrorRxOver:     printf("Input buffer overflow");    break;
            case CSerial::EErrorParity:     printf("Input parity error");       break;
            case CSerial::EErrorTxFull:     printf("Output buffer full");       break;
            default:                        printf("Unknown");                  break;
            }
            printf(" ###\n");
        }

        // Handle ring event
        if (eEvent & CSerial::EEventRing)
        {
            printf("\n### RING ###\n");
        }

        // Handle RLSD/CD event
        if (eEvent & CSerial::EEventRLSD)
        {
            printf("\n### RLSD/CD %s ###\n", serial.GetRLSD()?"on":"off");
        }

        // Handle data receive event
        if (eEvent & CSerial::EEventRecv)
        {
            // Read data, until there is nothing left
            DWORD dwBytesRead = 0;
            char szBuffer[101];
            do
            {
                // Read data from the COM-port
                lLastError = serial.Read(szBuffer,sizeof(szBuffer)-1,&dwBytesRead);
                if (lLastError != ERROR_SUCCESS)
                    return ::ShowError(serial.GetLastError(), _T("Unable to read from COM-port."));

                if (dwBytesRead > 0)
                {
                    // Finalize the data, so it is a valid string
                    szBuffer[dwBytesRead] = '\0';

                    //writing data to text file
                    std::ofstream o("save.txt");
                    o << "Data: " << szBuffer << std::endl << "BytesRead: " <<dwBytesRead <<std::endl;

                    // Display the data
                    printf("%s", szBuffer);

                    // Check if EOF (CTRL+'[') has been specified
                    if (strchr(szBuffer,EOF_Char))
                        fContinue = false;
                }
            }
            while (dwBytesRead == sizeof(szBuffer)-1);
        }
    }
    while (fContinue);

    // Close the port again
    serial.Close();
    return 0; 
}

我确实在我的 while 语句中设置了一些断点,并试图重新启动电路板。然后我像这样将数据写入我的文本文件。

步道 1:

数据:“H¢~A,B™žX
字节读取:100

路径 2:

数据:x]Ãßÿ$¢œŒ2Y¶SIeó1ñ\@ó8¬!)þ
字节读取:30

我知道这个数据不正确,我应该得到 ASCII 数据。 是否有任何库支持解决我的问题?

UART重启后我需要读取数据,一旦停止接收数据,它应该将所有数据写入文本文件。

请帮帮我,非常感谢。

【问题讨论】:

  • 使用许多串行终端应用程序中的任何一个来验证您的接线和端口设置是否正确,并且您正在以预期的格式获取数据。
  • 是的@BenVoigt,我做到了,我使用了Eltima Advanced 串口终端软件。打开端口后,我重新启动板后获取数据。但目标是为这个问题编写一个 C++ 程序。
  • 但是您没有显示现有软件中使用的设置,也没有显示您希望获得的数据。您的问题甚至没有提到接线和发送器板已使用现有软件进行了测试。特别是,流控制设置往往非常重要,您的代码会完全忽略它们。
  • 好的,我会努力的。谢谢。
  • 另外,EReadTimeoutNonblockingwhile (dwBytesRead == sizeof(szBuffer)-1) 放在一起没有意义。

标签: c++ serialization serial-port serial-communication


【解决方案1】:

在设置函数中设置错误的波特率会导致输出错误。

 lLastError = serial.Setup(CSerial::EBaud115200,CSerial::EData8,CSerial::EParNone,CSerial::EStop1);

还有

std::ofstream output_file;
        //Creating a text file
        output_file.open("save_test.txt", std::ios_base::app);
            //writing data to text file
                output_file /*<< "Data: "*/ << szBuffer;

而不是下面的这段代码(每次都会覆盖文本文件并且看不到数据)

  //writing data to text file
                    std::ofstream o("save.txt");
                    o << "Data: " << szBuffer << std::endl << "BytesRead: " <<dwBytesRead <<std::endl;

将数据附加到文本文件中,这将使通过RS232传输的完整数据可以在文本文件中看到。

【讨论】:

    猜你喜欢
    • 2015-07-03
    • 2011-11-15
    • 2016-01-06
    • 2019-04-11
    • 2019-05-20
    • 1970-01-01
    • 2014-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多