串口可以处于脏状态吗?

时间:2016-01-25 19:56:23

标签: linux serial-port posix

我正在编写一个程序,通过串口与现有设备进行通信,我注意到一个奇怪的模式。正在使用真正的串行端口和USB转串口适配器进行测试。我得到了相同的结果。

启动计算机或插入适配器后,串口通信正常工作。我可以将二进制数据发送到设备,然后获得响应。只要需要,程序就可以继续与设备通信。

但是,一旦程序结束(干净地关闭端口),再次运行程序会导致无法通信。它可以很好地访问串口,但它回来的只是垃圾。

(奇怪的是,垃圾似乎是与调制解调器命令混合的二进制数据,如ATE0Q0S0 = 0,这没有任何意义。再次,我不需要重置设备与它通信,只是端口,所以我不喜欢我不知道它来自哪里。)

重启或拔出设备电源无效。只有当我重新启动计算机或重置USB设备(通过拔出或驱动程序重置)时,我才能再次运行该程序并使其成功通信。

这会导致什么?从结果来看,我只能假设串口在使用后没有处于干净状态,但除了重新应用ioctl属性和关闭文件描述符之外,我找不到有关正确清理串口状态的文档。使用,我已经做过了。

也许串口端口引脚或其他东西?我不知道我将如何测试,或者为什么它会发生。

我目前的“解决方案”是坚持使用USB适配器,让我的程序在尝试使用串口之前执行USB驱动程序重置,但我希望有更好的解决方案。

修改

根据要求,这是我用来测试串口读/写的C程序。

包括

#include <fcntl.h>
#include <inttypes.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>

// Saved termios that we can re-apply when we exit
struct termios savedPortAttributes;

// Set the serial port attributes so we can use it
void setPortAttributes( int fd )
{
    struct termios tty;
    memset( &tty, 0, sizeof(tty) );
    if ( tcgetattr( fd, &tty ) != 0 ) {
        printf( "tcgetaddr error: $i\n", errno );
        return;
    }
    cfsetispeed( &tty, B9600 );
    cfsetospeed( &tty, B9600 );
    cfmakeraw( &tty );
    tty.c_lflag = 0;
    tty.c_oflag = 0;
    tty.c_iflag &= ~(IXON | IXOFF | IXANY);
    tty.c_cflag |= (CLOCAL | CREAD);
    tty.c_cflag &= ~(PARENB | PARODD);
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CRTSCTS;
    tty.c_cc[VMIN] = 0;
    tty.c_cc[VTIME] = 5;
    if ( tcsetattr( fd, TCSANOW, &tty ) != 0 ) {
        printf( "tcsetaddr error: $i\n", errno );
        return;
    }
    if ( tcflush( fd, TCIOFLUSH ) != 0 ) {
        printf( "tcflush error: $i\n", errno );
        return;
    }
}

void test( int fd )
{
    // Send a sample MODBUS command
    printf( "Writing command\n" );
    char sendBuffer[] = { 0x01, 0x03, 0x00, 0x0B, 0x00, 0x02, 0xB5, 0xC9 };
    int bytesWritten = write( fd, sendBuffer, sizeof(sendBuffer) );
    if ( bytesWritten < 0 ) {
        printf( "Error writing command.\n" );
        return;
    }

    // We don't want to wait more than 1000ms for a response
    struct timespec spec;
    clock_gettime( CLOCK_MONOTONIC, &spec );
    int64_t startMs = spec.tv_sec * 1000 + round( spec.tv_nsec / 1.0e6 );

    // Read data back from the port
    printf( "Reading from port...\n" );
    unsigned char buffer[1024];
    int bufferOffset = 0;
    int count = 0;
    while ( 1 ) {
        count = read( fd, &buffer[bufferOffset], sizeof(buffer) - bufferOffset );
        if ( count < 0 ) {
            printf( "Error reading command.\n" );
            return;
        }
        if ( count > 0 ) {
            printf( "Bytes read: " );
            for ( int i = bufferOffset; i < bufferOffset + count; i++ ) {
                printf( "%02x ", buffer[i] );
            }
            printf( "\n" );
        }
        bufferOffset += count;

        // Test code. If we receive part of a valid MODBUS response, grab the
        // field length byte so we know if we're done reading
        if ( bufferOffset >= 3 && buffer[0] == 1 && buffer[1] == 3 ) {
            int messageLength = buffer[2];
            if ( bufferOffset >= messageLength + 5 ) {
                break;
            }
        }

        // If it's been 1000ms, stop reading
        clock_gettime( CLOCK_MONOTONIC, &spec );
        int64_t timeMs = spec.tv_sec * 1000 + round( spec.tv_nsec / 1.0e6 );
        //printf( "%" PRId64 " , %" PRId64 "\n", startMs, timeMs );
        if ( timeMs - startMs > 1000 ) {
            break;
        }
    }
}

void main()
{
    printf( "Opening port\n" );
    int fd = open( "/dev/ttyUSB0", O_RDWR|O_NOCTTY );
    if ( fd == -1 ) {
        printf( "Unable to open port.\n" );
        return;
    }

    tcgetattr( fd, &savedPortAttributes );
    setPortAttributes( fd );

    test( fd );
    test( fd );

    tcsetattr( fd, TCSANOW, &savedPortAttributes );
    close( fd );
}

0 个答案:

没有答案