gpt4 book ai didi

c - Linux termios在串行端口read()之后修改第一个字符

转载 作者:IT王子 更新时间:2023-10-29 00:58:03 25 4
gpt4 key购买 nike

我的termios设置是使用read()修改从串行端口读取的第一个字符。我有一个与Linux盒子通讯的微 Controller 。微 Controller 响应从linux机器发送的命令。设置如下:

  • 微 Controller (PIC24F)RS485端口<-> RS485转USB转换器<-> Ubuntu PC。

  • 当我运行类似Cutecom的终端程序时,一切都会按计划进行。我向PIC发送了一个命令字符,但是得到了响应,但是当我使用命令行程序时,第一个字符已被修改。这是我的代码:
    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <termios.h>

    #define DEVICE "/dev/ttyUSB0"
    #define SPEED B38400

    int main()
    {
    struct termios tio; //to hold serial port settings
    struct termios stdio; //so we can accept user input
    struct termios old_stdio; //save the current port settings
    int tty_fd; //file descriptor for serial port
    int res, n, res2, read1, wri;
    char buf[255];
    char buf2[255];

    //save the current port settings
    tcgetattr(STDOUT_FILENO,&old_stdio);

    //setup serial port settings
    bzero(&tio, sizeof(tio));
    tio.c_iflag = 0;
    tio.c_iflag = IGNPAR | IGNBRK | IXOFF;
    tio.c_oflag = 0;
    tio.c_cflag = CS8 | CREAD | CLOCAL; //8n1 see termios.h
    tio.c_lflag = ICANON;

    //open the serial port
    tty_fd=open(DEVICE, O_RDWR | O_NOCTTY);

    //set the serial port speed to SPEED
    cfsetospeed(&tio,SPEED);

    //apply to the serial port the settings made above
    tcsetattr(tty_fd,TCSANOW,&tio);

    for(n = 5; n > 0; n--)
    {
    printf("Please enter a command: ");
    (void)fgets(buf2, 255, stdin);
    (void)write(tty_fd, buf2, strlen(buf2));
    printf("Ok. Waiting for reply.");
    res = read(tty_fd, buf, 255);
    printf("Read:%d START%d %d %d %d %dFINISH\n",res,buf[0],buf[1],buf[2],buf[3],
    buf[4]);
    }

    //close the serial port
    close(tty_fd);

    //restore the original port settings
    tcsetattr(STDOUT_FILENO,TCSANOW,&old_stdio);

    return EXIT_SUCCESS;
    }

    这是我得到的结果的一个例子。
  • 当PIC发送“00000\n”时,输出为:读取:6 START-16 48 48 48 48 FINISH
  • 当PIC发送“23456\n”时,输出为:读取:6 START-14 51 52 53 54FINISH
  • 当PIC发送“34567\n”时,输出为:读取:6 START-14 52 53 54 55FINISH
  • 当PIC发送“45678\n”时,输出为:读取:6 START-12 53 54 55 56FINISH
  • 当PIC发送“56789\n”时,输出为:读取:6 START-12 54 55 56 57FINISH

  • 由于某些原因,第一个字符被某些termios设置弄乱了。它必须是termios设置,因为当我运行Cutecom时,将完全返回上述相同的测试输入。我已经一遍又一遍地阅读了手册页,尝试对输入控件进行所有不同的设置,但是无论我做什么都不能动摇这个问题。

    为了轻松解决问题,我只能将数据跨1个字符移动,但要避免这样做。

    有没有人遇到过这样的问题,或者不知道该怎么办?

    非常感谢。

    13年3月28日
    奥斯丁的好建议。对于那些感兴趣的人,这里有两个输出:
  • 首先是我程序中的termios设置

    速度38400波特;第0行;第0列;行= 0;
    intr =;退出=;擦除=;杀死=; eof =;
    eol =; eol2 =; swtch =;开始=;停止=;
    susp =; rprnt =; werase =;下一个=;
    冲洗=;最小值= 0;时间= 0;
    -parenb -parodd cs8 -hupcl -cstopb读取clocal -crtscts
    ignbrk -brkint ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon ixoff
    -iuclc -ixany -imaxbel -iutf8
    -opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
    -isig icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt
    -echoctl -echoke
  • 和cutecom使用的设置

    速度38400波特;第0行;第0列;行= 0;
    intr = ^ C;退出= ^\;擦除= ^ ?;杀= ^ U; eof = ^ D; eol =;
    eol2 =; swtch =;开始= ^ Q;停止= ^ S; susp = ^ Z; rprnt = ^ R;
    werase = ^ W; lnext = ^ V;冲洗= ^ O;最小值= 60;时间= 1;
    -parenb -parodd cs8 hupcl -cstopb读取clocal -crtscts
    ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff
    -iuclc -ixany -imaxbel -iutf8
    -opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
    -isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt
    -echoctl -echoke

  • 我仍在进行所有操作,并且在取得进展时会更新该帖子。

    29/3/13
    仍然有同样的问题。我什至找到了Cutecom的源代码,并遵循了它们使用的termios设置。问题仍然存在。该第一个字符已损坏!!!
  • 这是我程序中的Termios设置。由于某些原因,无法设置刷新。

    速度38400波特;第0行;第0列;行= 0;
    intr = ^ ?;退出= ^\;擦除= ^ H;杀= ^ U; eof = ^ D; eol =;
    eol2 =; swtch =;开始= ^ Q;停止= ^ S; susp = ^ Z; rprnt = ^ R;
    werase = ^ W; lnext = ^ V;冲洗=;最小值= 60;时间= 1;
    -parenb -parodd cs8 hupcl -cstopb读取clocal -crtscts
    ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff
    -iuclc -ixany -imaxbel -iutf8
    -opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
    -isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt
    -echoctl -echoke
  • 和我的新代码:
    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <termios.h>
    #include <sys/ioctl.h>

    #define DEVICE "/dev/ttyUSB0"
    #define SPEED B38400

    int main()
    {
    struct termios tio; //to hold serial port settings
    struct termios stdio; //so we can accept user input
    struct termios old_stdio; //save the current port settings
    int tty_fd; //file descriptor for serial port
    int retval, res, n, res2, read1, wri;
    char buf[255];
    char buf2[255];


    tty_fd = open(DEVICE, O_RDWR | O_NDELAY);
    if(tty_fd < 0)
    {
    perror(DEVICE);
    exit(-1);
    }
    printf("Init 1 complete.\n");

    tcflush(tty_fd, TCIOFLUSH);

    int f = fcntl(tty_fd, F_GETFL, 0);
    fcntl(tty_fd, F_SETFL, f & ~O_NDELAY);

    retval = tcgetattr(tty_fd, &old_stdio);
    if(retval != 0)
    {
    perror(DEVICE);
    exit(-1);
    }
    printf("Init 2 complete.\n");

    struct termios newtio;
    retval = tcgetattr(tty_fd, &newtio);
    if(retval != 0)
    {
    perror(DEVICE);
    exit(-1);
    }
    printf("Init 3 complete.\n");

    cfsetospeed(&newtio, SPEED);
    cfsetispeed(&newtio, SPEED);

    newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS8;
    newtio.c_cflag |= CLOCAL | CREAD;
    newtio.c_cflag &= ~(PARENB | PARODD);
    newtio.c_cflag &= ~CRTSCTS;
    newtio.c_cflag &= ~CSTOPB;

    newtio.c_iflag = IGNBRK;
    newtio.c_iflag &= ~(IXON | IXOFF | IXANY);

    newtio.c_lflag = 0;

    newtio.c_oflag = 0;

    newtio.c_cc[VTIME] = 1;
    newtio.c_cc[VMIN] = 60;
    newtio.c_cc[VINTR] = 127;
    newtio.c_cc[VQUIT] = 28;
    newtio.c_cc[VERASE] = 8;
    newtio.c_cc[VKILL] = 21;
    newtio.c_cc[VEOF] = 4;
    newtio.c_cc[VSTOP] = 19;
    newtio.c_cc[VSTART] = 17;
    newtio.c_cc[VSUSP] = 26;
    newtio.c_cc[VREPRINT] = 18;
    newtio.c_cc[VFLSH] = 15;
    newtio.c_cc[VWERASE] = 23;
    newtio.c_cc[VLNEXT] = 22;


    retval = tcsetattr(tty_fd, TCSANOW, &newtio);
    if(retval != 0)
    {
    perror(DEVICE);
    exit(-1);
    }
    printf("Init 4 complete.\n");

    int mcs = 0;
    ioctl(tty_fd, TIOCMGET, &mcs);
    mcs |= TIOCM_RTS;
    ioctl(tty_fd, TIOCMSET, &mcs);

    retval = tcgetattr(tty_fd, &newtio);
    if(retval != 0)
    {
    perror(DEVICE);
    exit(-1);
    }
    printf("Init 5 complete.\n");

    newtio.c_cflag &= ~CRTSCTS;

    retval = tcsetattr(tty_fd, TCSANOW, &newtio);
    if(retval != 0)
    {
    perror(DEVICE);
    exit(-1);
    }
    printf("Init 6 complete.\n");


    for(n = 5; n > 0; n--)
    {
    printf("Please enter a command: ");
    (void)fgets(buf2, 255, stdin);
    (void)write(tty_fd, buf2, strlen(buf2));
    printf("Ok. Waiting for reply\n");
    res = read(tty_fd, buf, 255);
    printf("Read:%d START%d %d %d %d %dFINISH\n",res,buf[0],buf[1],buf[2], buf[3],
    buf[4]);
    }

    //restore the original port settings
    tcsetattr(tty_fd, TCSANOW, &old_stdio);

    close(tty_fd);

    return EXIT_SUCCESS; //return all good
    }

  • 我完全不知道该怎么办,或者我应该从这里拿走它。

    最佳答案

    快速浏览您的代码,我看不出任何明显错误的地方。如果您希望使用8位值,则可能要考虑移至unsigned char buf[]

    由于您在Cutecom中有一个可运行的程序,因此您可以使用它们的termios设置作为调试您自己的程序的引用。

    当Cutecom在/dev/ttyUSB0上运行时,在另一个终端上运行以下命令以转储tty设置:

    stty -a -F /dev/ttyUSB0

    运行程序时执行相同的操作,并查找两种配置之间的差异。尝试在程序中设置终端设置,使其与为Cutecom报告的设置完全匹配。

    更新:

    由于修复termios设置仍无法解决问题,因此,请尝试以下其他操作。我可能会猜测某个地方存在计时问题。在Cutecom控制台上打字时,您一次要向设备发送一个字符,每个字符之间的间隔为毫秒。使用程序时,输入命令后将发送完整的字符缓冲区,并且字符将以驱动程序允许的最快速度背对背发送。也许您的PIC程序无法处理数据流的时序,或者期望例如两个停止位而不是一个停止位,从而导致一些奇怪的返回码。

    最好的起点可能是从源头开始。掌握示波器或逻辑分析仪,并验证PIC发送的数据实际上是正确的。您将必须了解位电平的波形,并考虑起始位和停止位。比较Cutecom和您的程序的波形。如果使用逻辑分析仪,请确保使用的时钟是波特率的高倍数。例如32乘法器。

    调试的另一种方法是使用 strace来验证驱动程序返回的字符实际上是不正确的,并且这不是程序的问题。使用 strace,您将能够看到程序的原始读/写以及内核返回的内容。在程序运行时,使用 strace -o ~/tmp/strace_output.txt -ttt -xx your_program转储所有系统调用。有时,仅在编制程序的过程中,它的运行速度会降低,足以显示时序错误。您可以将读取/写入的时间与Cutecom的 strace进行比较。仅出于测试目的,您可以添加自己的 write()函数,该函数发送一个字符串,但在每个字符之间延迟一小段时间。

    关于c - Linux termios在串行端口read()之后修改第一个字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15672751/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com