来自串行GNSS设备的输入不可读 - 但不适用于PuTTY

时间:2016-10-17 13:02:55

标签: c++ serial-port nmea

我正在编写一个C ++程序来从通过串口连接的设备获取和解析GNSS数据。建立连接后,我得到的只是一些乱码而不是预期的NMEA句子。有谁知道我的错误在哪里? 当我使用PuTTY输出数据时,有部分乱码和部分好的NMEA句子。

我的主要代码:

#include <iostream>
#include "Serial.h"

int main()
{
    Serial serial;
    unsigned char buffer[256];
    std::string port = "COM19";
    const char *portaddress=port.data();
    std::cout<<serial.Open(portaddress,9600);
    //unsigned char *buffer;
    int read;
    int readlast;
    read=serial.Read(buffer, 255);
    unsigned char line[256];//=new int[];
    int counter=0;
    while(1)
    {
        while(read==0)
        {
            read=serial.Read(buffer, 255);
        }
        counter=0;
        line[counter]=read;
        counter++;
        while(read!=0)
        {
             //std::cout<<read;
             readlast=read;
             read=serial.Read(buffer, 255);
             line[counter]=read;
             counter++;
        }
        for(int i=0;i<sizeof(line)/sizeof(*line);i++)
        {
            std::cout<<line[i];
        }
        break;

    }

    return 0;
}

serial.Read():

int Serial::Read(unsigned char* buffer, int length) {
    WaitForSingleObject(m_Mutex, INFINITE);
    DWORD bytesRead = 0;
    ReadFile(m_SerialHandle, buffer, length, NULL, &m_Overlapped);
    GetOverlappedResult(m_SerialHandle, &m_Overlapped, &bytesRead, 1);
    ReleaseMutex(m_Mutex);

    return (int)bytesRead;
}

输出:

0                  ­<@ `▀F ÉòG $òG Ç@     $ ¶â.X■i >uñv       Iuñvÿ1V    fm~wç }w    $       ( ¶â.ÿ■i >uñv       Iuñv├ÿ1V    fm~wç }w    $   ä■i        þÆAö■i «kªv, Ç@ ÓêA     ¼■i àtªv©?½vý■i óiª   ssÑvjsÑvÀÿ1VÇ@ Ç@     ÓêA

当我离开break时,它没有变得更好。我的GNSS板的规范说输出应该是ASCII协议NMEA 0813 v4.0

编辑: 这是我使用HTerm.exe时的输出。有很多垃圾字节,但在两者之间你可以找到NMEA句子。设置是1个停止位,8个数据位,没有奇偶校验,9600波特(我在u-blox的u-center软件中也使用它,它就像魅力一样)。

?b<5><1><2><\0><6><\0><14>7?b<5><1><2><\0><6><\0>
<14>7?b<5><1><2><\0><6><1><15>8?b<5><1><2><\0><6><1>
<15>8?b<5><1><2><\0><6><1><15>8?b<5><1><2><\0><6><1>
<15>8?b<5><1><2><\0><6><1><15>8?b<5><1><2><\0><6><1>
<15>8?b<5><1><2><\0><6><1><15>8?b<5><1><2><\0><6><1>
<15>8?b<5><1><2><\0><6><1><15>8?b<2><20>,<\0><1><\0>
<\0><\0><4>)<\0><\0><4>)<\0><\0><4>)<\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0>??????<\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0>?8
$GNTXT,01,01,02,u-blox AG - www.u-blox.com*4E<\r><\n>
$GNTXT,01,01,02,HW UBX-M8030 00080000*60<\r><\n>
$GNTXT,01,01,02,EXT CORE 3.01 (b8bc67)*66<\r><\n>
$GNTXT,01,01,02,ROM BASE 2.01 (75331)*19<\r><\n>
$GNTXT,01,01,02,FWVER=HPG 1.11*5E<\r><\n>
$GNTXT,01,01,02,PROTVER=20.01*1B<\r><\n>
$GNTXT,01,01,02,MOD=NEO-M8P-2*7B<\r><\n>
$GNTXT,01,01,02,FIS=0xEF4015 (100111)*58<\r><\n>
$GNTXT,01,01,02,GPS;GLO;BDS*06<\r><\n>
$GNTXT,01,01,02,GNSS OTP=GPS;GLO*37<\r><\n>
$GNTXT,01,01,02,LLC=FFFFFFFF-FFFFFFED-FFFFFFFF-FFFFF79E-FFFFFF69*2E<\r><\n>
$GNTXT,01,01,02,ANTSUPERV=AC SD PDoS SR*3E<\r><\n>
$GNTXT,01,01,02,ANTSTATUS=OK*25<\r><\n>
$GNTXT,01,01,02,PF=300*4B<\r><\n>?b
<\n><6>x<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<11><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0>?<2>?b<\n><\b><28><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\n>
<\0><6><\0><\0><\0><20><\0><6><\0><\0><11><20><\0>
<\0>w??b<\n><7><24><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0>)E?b<\n><2>x<\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0>?<17><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><1><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0>?<\0><\0><\0>?<\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><1><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0>???b<\n><9><<\0><\0>?<1><\0>
<\0><\0><\0><\0><\0>@<1><\0>??<1><\0>d<\0>?<3><2><1>
<\0>???<1><\0><\n><11><\f><\r><14><15><1><\0><2>
<3>?<16>?<18>D65E?^<\0><\0><\0><\0>??<1><\0><\0><\0>
<\0><\0>%??b<\n><11><28><\0>/?w?f<\0><\0><\0>????????????<\0>
<\0><\0><\0><\0><\0><\0><\0>]Y?b<2><20>,<\0><1>
<\0><\0><\0>?*<\0><\0>?*<\0><\0>?*<\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0>??????<\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0>???b<2><21><16>
<\0><\0><\0><\0><\0><\0><\0>$@<\0><\0><17><\0><\0>
<1>?+M<29>?b<1><6>4<\0>?*<\0><\0><\0><\0><\0><\0><\0>
<\0><\0>@?C<4>&<\0><\0><\0><\0><\0><\0><\0><\0>???&<\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>?<7><\0>
<\0><15>'<2><\0>?xq<3><18>A?b<1><7>\<\0>?*<\0><\0>?<7><\n>
<18><\0><\0><11>?????<\0><\0><\0><\0><\0><\0><4><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>????????<\0>
v??<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0> N<\0><\0>??<18><1><15>'<\0>
<\0>?x!7<\0><\0><\0><\0><\0><\0><\0><\0>(??b<1>0<\b>
<\0>?*<\0><\0><\0><4><\0><\0>_^?b<1>4<\b><\0>?*<\0>
<\0><1><\0><\0><\0>`??b<1>5<\b><\0>?*<\0><\0><1><\0>
<\0><\0>a??b<1><3><16><\0>?*<\0><\0><\0>@<\0><\b><\0>
<\0><\0><\0><\f>+<\0><\0>?<28>?b<1><1><20><\0>?*<\0>
<\0>?C<4>&<\0><\0><\0><\0><\0><\0><\0><\0>???&???b<1>
<2><28><\0>?*<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0>????????<\0>v??i??b<1><4><18><\0>?*<\0>
<\0><15>'<15>'<15>'<15>'<15>'<15>'<15>'???b<1><17><20>
<\0>?*<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0>?<7><\0><\0><31>*?b<1><18>$<\0>?*<\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0>?<7><\0><\0>??<18>
<1>k??b<1> <16><\0>?*<\0><\0><\0><\0><\0><\0><\0><\0>
<17><\0>????`??b<1>#<20><\0>?*<\0><\0><11><\0><\0><\0>
<\0><\0><\0><\0>k<5><5><\0>???????b<1>$<20><\0>?*<\0>
<\0><11><\0><\0><\0><\0><\0><\0><\0>K<7><3><\0>???????b<1>!<20>
<\0>?*<\0><\0>????<\0><\0><\0><\0>?<7><\n><18><\0>
<\0><11>?Q??b<1>&<24><\0>?*<\0><\0><\0><\0><\0><\0><7>
<17><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0>y<3>?b<1>"<20><\0>?*<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>????|69<\0>@F?b<1><9><20><\0><\0><\0><\0><\0>?*<\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0>@??b<1>;(<\0><\0><\0><\0><\0>?*<\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0>?C?b<1><(<\0><\0><\0><\0><\0>?*<\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>
<\0>?n?b<1>9<\b><\0>?*<\0><\0><\0><\0><\0><\0>d?
$GNDTM,W84,,0.0,N,0.0,E,0.0,W84*71<\r><\n>
$GNRMC,,V,,,,,,,,,,N*4D<\r><\n>
$GNVTG,,,,,,,,,N*2E<\r><\n>
$GNGNS,,,,,,NN,00,99.99,,,,*7D<\r><\n>
$GNGGA,,,,,,0,00,99.99,,,,,,*56<\r><\n>
$GNGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*2E<\r><\n>
$GNGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*2E<\r><\n>
$GPGSV,1,1,00*79<\r><\n>$GLGSV,1,1,00*65<\r><\n>
$GNGLL,,,,,,V,N*7A<\r><\n>
$GNGRS,,1,,,,,,,,,,,,*7E<\r><\n>
$GNGRS,,1,,,,,,,,,,,,*7E<\r><\n>
$GNGST,,0.0000,,,,3750000,3750000,3750000*66<\r><\n>
$GNZDA,,,,,00,00*56<\r><\n>
$GNGBS,,,,,,,,*5F<\r><\n>
$GNVLW,,,,,,,,*44<\r><\n>
$PUBX,00,000011.00,0000.00000,N,00000.00000,E,0.000,NF,5303301,3750000,0.000,0.00,0.000,,99.99,99.99,99.99,0,0,0*2A<\r><\n>
$PUBX,03,00*1C<\r><\n>
$PUBX,04,000011.00,181015,11.00,1867,17D,0,0.000,21*6C<\r><\n>?b<2> `<2>?

也许设置错了?虽然我试图添加:

serialParams.DCBlength=sizeof(serialParams);
serialParams.fParity=FALSE;
serialParams.fDtrControl=0;
serialParams.fRtsControl=0;
serialParams.fOutX=TRUE;
serialParams.fInX=TRUE;

serialParams.fBinary=FALSE;
serialParams.fOutxCtsFlow=FALSE;
serialParams.fOutxDsrFlow=FALSE;
serialParams.fDsrSensitivity=FALSE;
serialParams.fErrorChar=FALSE;
serialParams.fNull=FALSE;
serialParams.fAbortOnError=FALSE; 

Serial::Open(),它仍然输出相同的输出。也许缓冲区有问题?我仍然没有真正掌握缓冲区的概念以及它们应该存在多长时间,所以我很可能在那里犯了错误。

编辑2:

希望(和忘记)Serial::Open()

int Serial::Open(const char* port, int baudrate) {

    // if connected: close current connection before opening a new one
    if(m_SerialHandle != INVALID_HANDLE_VALUE) {
        Close();
    }

    TCHAR vibroTacPort[15];
    sprintf(vibroTacPort, "\\\\.\\%s", port);

    // Open serial port
    m_SerialHandle = CreateFile(vibroTacPort, // port // "\\\\.\\COM13"
                                GENERIC_READ | GENERIC_WRITE,
                                0,//FILE_SHARE_READ | FILE_SHARE_WRITE,
                                NULL,
                                OPEN_EXISTING,
                                FILE_FLAG_OVERLAPPED | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING | FILE_ATTRIBUTE_TEMPORARY, // | FILE_ATTRIBUTE_NORMAL,
                                NULL);

    // FILE_FLAG_OVERLAPPED is necessary for event-driven communication, Handle hast to be flagged for overlapped IO, otherwise Serial::Request() blocks if no event occurs (e.g. if the VibroTac device does not respond to the request)
    // FILE_ATTRIBUTE_TEMPORARY, FILE_FLAG_WRITE_THROUGH and FILE_FLAG_NO_BUFFERING increase the system performance
    // Note: FILE_FLAG_WRITE_THROUGH is not be supported by all hard disks
    // (http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx#caching_behavior)


    if(m_SerialHandle == INVALID_HANDLE_VALUE)
    {
        DWORD errorCode = GetLastError();
        //  Handle the error.
        switch(errorCode) {
        case ERROR_FILE_NOT_FOUND:
        case ERROR_ACCESS_DENIED:
            //  121     The semaphore timeout period has expired.
            //  1167    The device is not connected.
            // fall through and do nothing for now
            ;
        }
        return (errorCode);
    }

    // Do some basic settings
    DCB serialParams = { 0 };
    serialParams.DCBlength = sizeof(serialParams);

    if (!GetCommState(m_SerialHandle, &serialParams)) {
        Close();
        return ERROR_OPEN_FAILED;
    };
    serialParams.BaudRate = CBR_9600;//baudrate;
    serialParams.ByteSize = 8;
    serialParams.StopBits = ONESTOPBIT;
    serialParams.Parity = NOPARITY;

    /*serialParams.DCBlength=sizeof(serialParams);
    serialParams.fParity=FALSE;
    serialParams.fDtrControl=0;
    serialParams.fRtsControl=0;

    serialParams.fOutX=TRUE;
    serialParams.fInX=TRUE;

    serialParams.fBinary=FALSE;
    serialParams.fOutxCtsFlow=FALSE;
    serialParams.fOutxDsrFlow=FALSE;
    serialParams.fDsrSensitivity=FALSE;
    serialParams.fErrorChar=FALSE;
    serialParams.fNull=FALSE;
    serialParams.fAbortOnError=FALSE;*/
    if (!SetCommState(m_SerialHandle, &serialParams)) {
        Close();
        return ERROR_OPEN_FAILED;
    }

    // Set timeouts

    COMMTIMEOUTS timeout = { 1 };
    timeout.ReadIntervalTimeout = 100;  //100   // 0 = "not used", the maximum time allowed to elapse before the arrival of the next byte on the communications line, in milliseconds.
    timeout.ReadTotalTimeoutConstant = 0;   // A constant used to calculate the total time-out period for read operations, in milliseconds. For each read operation, this value is added to the product of the ReadTotalTimeoutMultiplier member and the requested number of bytes.
    timeout.ReadTotalTimeoutMultiplier = 80;//20    // The multiplier used to calculate the total time-out period for read operations, in milliseconds. For each read operation, this value is multiplied by the requested number of bytes to be read.
    timeout.WriteTotalTimeoutConstant = 1;
    timeout.WriteTotalTimeoutMultiplier = 1;

    if (!SetCommTimeouts(m_SerialHandle, &timeout)) {
        Close();
        return ERROR_OPEN_FAILED;
    }

    // Set event mask
    // Events:
    // EV_RXCHAR    0x0001  A character was received and placed in the input buffer.
    // EV_ERR       0x0080  A line-status error occurred. Line-status errors are CE_FRAME, CE_OVERRUN, and CE_RXPARITY.
    DWORD dwEvtMask = EV_RXCHAR | EV_ERR;
    if(!SetCommMask(m_SerialHandle, dwEvtMask)) {
        Close();
        return ERROR_OPEN_FAILED;
    };

    // initialize m_Overlapped with 0
    memset(&m_Overlapped, 0, sizeof(m_Overlapped));

    // Create an event object for use by WaitCommEvent.
    m_Overlapped.hEvent = CreateEvent(
        NULL,   // default security attributes
        TRUE,   // manual-reset event
        FALSE,  // not signaled
        NULL    // no name
        );


    m_Overlapped.Internal = 0;
    m_Overlapped.InternalHigh = 0;
    m_Overlapped.Offset = 0;
    m_Overlapped.OffsetHigh = 0;

    return 0;
}

编辑3:

我想也许最好一次只读一个字节,直到我到达$字符,然后是\n字符,以确定哪些部分对我有用。有人可以解释我如何使用Serial::Open()中创建的处理程序读取单个字节?如果我使用前一种方式并限制length又名"NumberOfBytesToRead",我如何测试我是否到达相关部分?

1 个答案:

答案 0 :(得分:0)

好吧,经过大量的试验和错误,以及几个小时的吸烟,我找到了一个至少在我的情况下有效的答案:

我这样改变了main.cpp

#include <iostream>
#include "Serial.h"
#include "GPSInfo.h"
#include "NMEAParser.h"

int main()
{
    Serial serial;
    unsigned char buffer[256];
    std::string port = "COM19";
    const char *portaddress=port.data();
    serial.Open(portaddress,9600);

    std::string read;
    read=serial.Read(buffer);
    while(1)
    {
         read=serial.Read(buffer);
         std::cout<<read;
    }

    return 0;
}

Serial::Read()是这样的:

std::string Serial::Read(unsigned char* buffer) {
    WaitForSingleObject(m_Mutex, INFINITE);
    DWORD bytesRead = 0;
    DWORD nNumberOfBytesToRead=1; // new
    char a=0;
    char *ptr=&a;
    char last=0;
    std::string output="";
    ReadFile(m_SerialHandle, ptr, nNumberOfBytesToRead, NULL, &m_Overlapped);
    GetOverlappedResult(m_SerialHandle, &m_Overlapped, &bytesRead, 1);
    if(a=='$')
    {
        last=a;
        ReadFile(m_SerialHandle, ptr, nNumberOfBytesToRead, NULL, &m_Overlapped);
        if(a=='G'||a=='P'||a=='S')
        {

            output+=last;
            output+=a;
            while (a!='\n')
            {

                ReadFile(m_SerialHandle, ptr, nNumberOfBytesToRead, NULL, &m_Overlapped);
                output+=a;

            }
        }
    }
    ReleaseMutex(m_Mutex);
    return output;
}

现在我有以下输出:

$GNDTM,W84,,0.0,N,0.0,E,0.0,W84*71
$GNRMC,095639.00,A,4804.88405,N,01116.55021,E,0.415,,181016,,,A*6C
$GNVTG,,T,,M,0.415,N,0.769,K,A*35
$GPGSV,4,1,14,01,12,263,,07,00,284,,08,57,301,18,10,66,091,24*7B
$GPGSV,4,2,14,11,23,280,16,14,00,152,,15,04,026,,16,26,194,*7E
$GPGSV,4,3,14,18,37,056,13,21,11,079,,26,03,179,18,27,78,145,18*78
$GPGSV,4,4,14,30,03,310,,32,16,131,*7B
$GLGSV,3,1,09,70,43,047,15,71,57,137,33,72,17,181,17,76,09,244,*6F
$GLGSV,3,2,09,77,22,293,,78,12,347,,85,29,101,25,86,71,030,*63
$GLGSV,3,3,09,87,29,306,13*5F
$GNGLL,4804.88405,N,01116.55021,E,095639.00,A,A*7A
$GNGRS,095639.00,1,-2.7,7.0,,,,,,,,,,*7F
$GNTXT,01,01,00,txbuf alloc*61
$GNTXT,01,01,02,u-blox AG - www.u-blox.com*4E
$GNTXT,01,01,02,HW UBX-M8030 00080000*60
$GNTXT,01,01,02,EXT CORE 3.01 (b8bc67)*66
$GNTXT,01,01,02,ROM BASE 2.01 (75331)*19
$GNTXT,01,01,02,FWVER=HPG 1.11*5E
$GNTXT,01,01,02,PROTVER=20.01*1B

这正是我想要的。 (有时候仍然有垃圾,但我认为这不会影响我的解析。)

感谢您的所有评论和答案,它帮助了很多。