简体   繁体   English

C串行读取找不到回车符“ \\ r”

[英]C serial read does not find carriage return “\r”

I am battling now for a few days to Initialize a ELM237 OBD2 Adapter via Serial. 我现在正在努力通过串行初始化ELM237 OBD2适配器。 The device i am connecting to sends a response that always ends with a carriage return. 我连接的设备发送的响应始终以回车结尾。 I can Send commands without problems. 我可以毫无问题地发送命令。 The response is also send by the device as expected. 响应也由设备按预期发送。 I am trying to read from the serial port until i read the carriage return. 我试图从串行端口读取,直到读取回车。 I can See in my Serial Monitor that the command is sent properly and i get a full Message including carriage return back . 我可以在串行监视器中看到该命令已正确发送,并且收到完整的消息,包括回车。 But my code does not recognize the carriage return. 但是我的代码无法识别回车符。

Here is what i receive on my Serial Monitor : 这是我在串行监视器上收到的信息:

[19/07/2018 21:08:43] 
Written data 

41 54 5a 0d                                                             

ATZ. 

[19/07/2018 21:08:43] Read data

41 54 5a 0d

ATZ.             

[19/07/2018 21:08:44] Read data  

0d 0d 45 4c 4d 33 32 37 20 76 31 2e 35 0d 0d 3e   

..ELM327 v1.5..> 

This is the Output of my programm : 这是我的程序的输出:

Serial Port Open Succesfully

Request ATZ Reset ELM Adapter

current buffer ATZ

current buffer ATZ

current buffer ATZ

current buffer ATZ

ELM327 v1.5

current buffer ATZ

ELM327 v1.5

Code: 码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h> 
#include <errno.h>
#include <termios.h>
#include <sys/ioctl.h>

int SerialConnection();
int serial_fd;



int main(int argc, char* argv[])
{
    char buffer[255];       /* Input buffer */
    char *bufptr;           /* Current char in buffer */
    int  nbytes;            /* Number of bytes read */

    if(argc != 2)
    {
        printf( "Usage: %s <Serial Port>\n",argv[0]);
        exit(1);
    }

    serial_fd = SerialConnection(argv[1]);//Open serial port
    if(serial_fd < 1)
    {
        printf( "Serial Port Open Failure\n");
        exit(1);
    }
    printf( "Serial Port Open Succesfully\n");


    while(1)
    {
        memset(buffer, 0, 255); //clear buffer
        int ELMInit = 1;
        switch(ELMInit)
        {
        case 1:
            printf( "Request ATZ Reset ELM Adapter\n");
            write(serial_fd, "ATZ\r", 4);
            bufptr = buffer;
            while ((nbytes = read(serial_fd, bufptr, buffer + sizeof(buffer) - bufptr - 1)) > 0)
            {
                printf("current buffer %s \n",buffer);
                bufptr += nbytes;
                if (bufptr[-1] == '\r')
                {
                    printf("carriage return found %s \n",buffer);
                    if(strstr(buffer, "ELM327") != NULL)
                    {
                        printf("success %s\n",buffer);
                    }
                    break;
                }
                *bufptr = '\0';
            }
            break;

            default:
            break;


        }

    }

}   

int SerialConnection(char *serial_port)
{
    int fd;
    struct termios options;

    fd = open(serial_port, O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1)
    {
        return -1;
    }
    else
    {
        fcntl(fd, F_SETFL, 0);
        tcgetattr(fd, &options);
        cfsetispeed(&options, B38400);
        cfsetospeed(&options, B38400);
        options.c_cflag &= ~PARENB;                     /* Mask the character size to 8 bits, no parity */
        options.c_cflag &= ~CSTOPB;                     /*1 Stop bit */
        options.c_cflag &= ~CSIZE;
        options.c_cflag |= CS8;                         /* Select 8 data bits */
        options.c_cflag &= ~CRTSCTS;                    /* Disable hardware flow control */ 
        //options.c_lflag |= ICANON;                        /* Canonical mode*/
        //options.c_lflag |= ~(ICANON | ECHO | ECHOE);  /* Enable data to be processed as Canonical input */
        options.c_cflag |= (CLOCAL | CREAD);            /* Enable the receiver and set local mode */
        tcsetattr(fd, TCSANOW, &options);               /* Set the new options for the port */
    }
    return (fd);
}

I can See in my Serial Monitor that the command is sent properly and i get a full Message including carriage return back . 我可以在串行监视器中看到该命令已正确发送,并且收到完整的消息,包括回车。 But my code does not recognize the carriage return. 但是我的代码无法识别回车符。

The output from your program does confirm what @JonathanLeffler commented on. 程序的输出确实确认了@JonathanLeffler的评论。 The received carriage returns are being translated to newlines, which are terminating the canonical read() requests. 收到的回车符将转换为换行符,从而终止规范的read()请求。 You're seeing somewhat reasonable results inspite of an incomplete termios configuration by your program. 尽管程序的termios配置不完整,但您看到的结果还是比较合理的。

Your program does configure the termios attributes using the preferred method. 您的程序确实使用首选方法配置termios属性。
But if you require canonical mode (ie read lines), then your program should explicitly configure that mode, rather than leave it to chance (as it does now). 但是,如果您需要规范模式(即读取行),则程序应显式配置该模式,而不是让它偶然(如现在那样)。

options.c_lflag |= ICANON;                        /* Canonical mode*/
options.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN);

You probably should disable echoing, so that you do not receive back what you sent. 您可能应该禁用回显,以使您不会收到返回的信息。

Since you expect the line to terminate with \\r rather than the conventional \\n , you must also specify that. 由于您希望该行以\\r而不是传统的\\n结尾,因此您还必须指定该行。

options.c_cc[VEOL] = '\r';
options.c_iflag &= ~(INLCR | IGNCR | ICRNL);

Disable both carriage return and newline translations, and definitely do not ignore carriage returns. 禁用回车和换行翻译,并且绝对不要忽略回车。


Note that your code does disable hardware flow-control, but leaves software flow-control (Xon/Xoff) to chance. 请注意,您的代码确实禁用了硬件流控制,但是使软件流控制(Xon / Xoff)成为偶然。

options.c_iflag &= ~(IXON | IXOFF | IXANY);   /* no SW flowcontrol */
options.c_iflag &= ~(INPCK| IUCLC | IMAXBEL);
options.c_oflag &= ~OPOST;

Signal generation is also not configured either way. 信号生成也未配置。


ADDENDUM 附录

I only have one weird issue left . 我只剩下一个奇怪的问题。 My Message is 20 bytes Long when i do a printf on nbytes it tells me that i have received all 20 bytes . 我的消息是20字节长,当我在nbytes上执行printf时,它告诉我我已收到所有20字节。 but when i do a printf on buffer it cuts off the first characters instead of printing ATZ...ELM327 v1.5 it only prints M327 v1.5 但是当我在缓冲区上执行printf时,它会切断第一个字符,而不是打印ATZ ... ELM327 v1.5,它只会打印M327 v1.5

(1) Echo has been turned off, so the read() will not pick up the "ATZ\\r" that was sent unless the connected device echoes the command back. (1)回声已关闭,因此除非连接的设备回显命令, 否则 read()不会接收已发送的“ ATZ \\ r”。 That's unlikely because such devices are typically configured to not echo when controlled by a computer program instead of a human. 这不太可能,因为此类设备通常配置为在受计算机程序而非人为控制时不回声。

(2) The printf() is displaying the entire contents of the buffer , which includes the EOL character such as the carriage return. (2) printf()正在显示buffer的全部内容,其中包括EOL字符,例如回车符。 Outputting this received \\r combined with the extraneous whitespace (between the string specifier and newline) is what clobbers the earlier printf() output. 输出此接收到的\\r并与无关的空格(在字符串说明符和换行符之间)结合起来,是对早期的printf()输出的一种掩盖。

printf("current buffer %s \n",buffer);
                         ^

A carriage return by itself (ie without a line feed) is rarely used (in Linux) unless you intend to overwrite the existing line. 除非打算覆盖现有的行,否则很少使用回车符本身(即没有换行符)(在Linux中)。 You need to be aware of the consequences when displaying solitary carriage returns. 在显示单独回车时,您需要意识到后果。

One simple solution would be to switch to Linux line termination, and translate carriage returns to newlines (ie enable ICRNL instead of disabling it). 一种简单的解决方案是切换到Linux行终止,并将回车符转换为换行符(即启用ICRNL而不是禁用它)。 And change your search for \\r to \\n . 并将\\r的搜索更改为\\n

Actually the concatenated reads into the buffer and search for carriage return are all superfluous when (blocking) canonical input is properly configured. 实际上,当正确配置(阻塞)规范输入时,级联读取缓冲区和搜索回车符都是多余的。 There is no need for a read loop because a single canonical read() request is assured of returning with a line of input. 不需要读取循环,因为可以确保单个规范的read()请求返回一行输入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM