c代码无法正确轮询/询问通过串行端口连接的仪器

cl25kdpy  于 2023-08-03  发布在  其他
关注(0)|答案(1)|浏览(88)

我正在编写一个c程序来记录通过串行端口从仪器到达的数据。使用以单个回车结尾的各种ascii字符询问仪器。
仪器立即响应,请求的值以结尾<0D><0A>。
我已经使用SerialTools进行了测试(我正在运行MAC OSX M1 Max,使用XCode/C删除代码)。
我以前写的c代码询问其他仪器使用串行端口和记录的数据成功。在这种新情况下,我无法在第一次请求后收到任何数据。
仪器要求:串行:9600波特,N,8,1
我已经从在线论坛上听取了关于如何为规范输入设置串行端口的建议-特别是从sawdust termios代码提供的termios代码,这是非常好的。我认为规范输入是最好的,因为仪器总是用终止数据<0D><0A>。下面的代码显示了操作。它第一次写入端口'd\r',并立即从端口读取,我们得到预期的响应' 2.31<0D><0A>'。每次我随后写入相同的字符'd\r',读取都不会提供新值,而是' .31<0D><0A>',这看起来像是报告了一个移位的值。我怀疑仪器没有正确接收第二个请求,并且移位与缓冲区/串行端口有关。下面是相关代码:

#define TERMINAL    "/dev/cu.usbserial-4013420"
#define DISPLAY_STRING 1

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

#include <sys/stat.h>
#include <sys/types.h>

int set_interface_attribs(int fd, int speed)
{
    struct termios tty;

    if (tcgetattr(fd, &tty) < 0) {
        printf("Error from tcgetattr: %s\n", strerror(errno));
        return -1;
    }

    cfsetospeed(&tty, (speed_t)speed);
    cfsetispeed(&tty, (speed_t)speed);

    tty.c_cflag |= (CLOCAL | CREAD);    /* ignore modem controls */
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;         /* 8-bit characters */
    tty.c_cflag &= ~PARENB;     /* no parity bit */
    tty.c_cflag &= ~CSTOPB;     /* only need 1 stop bit */
    tty.c_cflag &= ~CRTSCTS;    /* no hardware flowcontrol */

    tty.c_lflag |= ICANON | ISIG;  /* canonical input */
    tty.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN);
    tty.c_lflag |= (ICANON | ECHO | ECHOE);

        tty.c_iflag &= ~IGNCR;  /* preserve carriage return */
        tty.c_iflag &= ~INPCK;
        tty.c_iflag &= ~(INLCR | ICRNL | IMAXBEL);
        tty.c_iflag &= ~(IXON | IXOFF | IXANY);   /* no SW flowcontrol */
        tty.c_oflag &= ~OPOST;
 tty.c_cc[VEOF] = 0x0A;
    
    
    if (tcsetattr(fd, TCSANOW, &tty) != 0) {
        printf("Error from tcsetattr: %s\n", strerror(errno));
        return -1;
    }

   
    return 0;
}

int main(int argc, const char * argv[])
{
    char *portname = TERMINAL;
    int fd;
    size_t wlen;            // use size_t for unsigned int
    int tester;
    char *xstr = "d\r";
    size_t xlen = strlen(xstr);
    unsigned char buff[10]={0};
    size_t rdlen2;
    
    fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
    
    if (fd < 0) {
        printf("Error opening %s: %s\n", portname, strerror(errno));
        return -1;
    }
    /*baudrate 9600, 8 bits, no parity, 1 stop bit */
    set_interface_attribs(fd, B9600);

    
    /* simple output  write, then read and repeat...*/
   
    printf("xstr is %s\n", xstr);
    
    wlen = write(fd, xstr, xlen);
    
    rdlen2 = read(fd, buff, sizeof(buff));

    wlen = write(fd, xstr, xlen);

    rdlen2 = read(fd, buff, sizeof(buff));

    wlen = write(fd, xstr, xlen);

    rdlen2 = read(fd, buff, sizeof(buff));

    wlen = write(fd, xstr, xlen);

    rdlen2 = read(fd, buff, sizeof(buff));

    wlen = write(fd, xstr, xlen);

    rdlen2 = read(fd, buff, sizeof(buff));
   

    close(fd);
}

字符串
我已经尝试了各种刷新缓冲区的方法,并使用tcdrain来确保写入完成。似乎没有什么能解决这个问题。谢谢你的建议。

lxkprmvk

lxkprmvk1#

我刚刚发现了我的错误!
我关闭了echo(正确地),然后在下面的一行中打开了它-请参阅这里的片段:

tty.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN); 

tty.c_lflag |= (ICANON | ECHO | ECHOE);

字符串
我们需要删除以下行:

tty.c_lflag |= (ICANON | ECHO | ECHOE);

  • --我犯了一个简单的错误,但也许这会对其他人有帮助,就像泰德·林格莫建议的那样。

令人尴尬的是,我使用了一些完美的工作代码(见上面的链接),并打破了它。我的故障,是由于没有完全了解串口的设置条件造成的。
轮询和日志记录现在可以按预期工作。

相关问题