尝试将AT命令写入使用FT232R读取ECU数据的USB至OBDii电缆(ISO 9141-2)

尝试将AT命令写入使用FT232R读取ECU数据的USB至OBDii电缆(ISO 9141-2),c,serial-port,usb,at-command,obd-ii,C,Serial Port,Usb,At Command,Obd Ii,我正在尝试使用ISO 9141-2协议从ECU读取数据。我使用的电缆是OBD2到USB,使用FT232R芯片。 我正在运行的程序是C语言的 当我将命令写入串行端口(ttyUSB0)时,它会很好地写入,但当它读回接收到的数据时,它只返回相同的数据。不是从ECU返回数据,我不知道它为什么这样做 任何帮助都很好,谢谢 示例代码-尝试设置波特率等,但也没有运气 #include <stdio.h> #include <string.h> #include <fcntl.h&

我正在尝试使用ISO 9141-2协议从ECU读取数据。我使用的电缆是OBD2到USB,使用FT232R芯片。 我正在运行的程序是C语言的

当我将命令写入串行端口(ttyUSB0)时,它会很好地写入,但当它读回接收到的数据时,它只返回相同的数据。不是从ECU返回数据,我不知道它为什么这样做

任何帮助都很好,谢谢

示例代码-尝试设置波特率等,但也没有运气

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    char *port = "/dev/ttyUSB0";
    char receivedData[100];

    int n, fd; 

    fd = open(port, O_RDWR | O_NOCTTY);

    if(fd > 0){
        n = write(fd, "AT I\r\n", 10);
        read(fd, receivedData, 10);
        printf("%s\n", receivedData);

        close(fd);
    }
    else{
        printf("failed to open device\n");
    }

    return 0;
}
#包括
#包括
#包括
#包括
int main()
{
char*port=“/dev/ttyUSB0”;
字符接收数据[100];
int n,fd;
fd=打开(端口,O|RDWR | O|NOCTTY);
如果(fd>0){
n=写入(fd,“在I\r\n”,10);
读取(fd,接收数据,10);
printf(“%s\n”,receivedData);
关闭(fd);
}
否则{
printf(“打开设备失败\n”);
}
返回0;
}

尽管这不是问题的直接答案,但这一数量的代码 不适用于评论部分

我使用这些函数初始化串行线:

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


struct baud_map {
    int baud;
    speed_t speed;
};

struct baud_map baudmap[] = {
    { 50        , B50 },
    { 75        , B75 },
    { 110       , B110 },
    { 134       , B134 },
    { 150       , B150 },
    { 200       , B200 },
    { 300       , B300 },
    { 600       , B600 },
    { 1200      , B1200 },
    { 1800      , B1800 },
    { 2400      , B2400 },
    { 4800      , B4800 },
    { 9600      , B9600 },
    { 19200     , B19200 },
    { 38400     , B38400 },
    { 57600     , B57600 },
    { 115200    , B115200 },
    { 230400    , B230400 },
    { 0,      0 }
};

int dbits_map[] = { 0, 0, 0, 0, 0, CS5, CS6, CS7, CS8 };

enum parity_t {
    PARITY_NO_PARITY,
    PARITY_ODD,
    PARITY_EVEN
};

int baud_to_speed(int baud, speed_t *speed)
{
    if(speed == NULL)
        return 0;

    struct baud_map *map = baudmap;
    while(map->baud)
    {
        if(map->baud == baud)
        {
            *speed = map->speed;
            return 1;
        }

        map++;
    }

    return 0;
}

/*
 * tty: "/dev/ttyUSB0"
 * baud: baudrate, for example 9600
 * parity: see enum parity_t
 * stop_bits: 1 or 2
 * data_bits: [5-8]
 *
 * return the fd on success, -1 on failure
 */
int openSerial_long(const char *tty, int baud, enum parity_t parity, int stop_bits, int data_bits)
{
    int fd;

    speed_t speed;

    if(baud_to_speed(baud, &speed) == 0)
    {
        fprintf(stderr, "Invalid baudrate %d\n", baud);
        return 0;
    }

    fd = open(tty, O_RDWR | O_NOCTTY  | O_NONBLOCK);

    if(fd == -1)
    {
        fprintf(stderr, "Could not open %s as a tty: %s\n", tty, strerror(errno));
        return -1;
    }

    struct termios termios;

    if(tcgetattr(fd, &termios) == -1)
    {
        fprintf(stderr, "Could not get tty attributes from %s: %s\n", tty, strerror(errno));
        close(fd);
        return -1;
    }

    // setting common values
    termios.c_iflag &= ~ICRNL;           // do not translate \r into \n
    termios.c_oflag &= ~OPOST;           // do not map \n to \r\n
    termios.c_cflag |= (CREAD | CLOCAL); // enable receiver & ignore model ctrl lines
    termios.c_lflag |= (ISIG | ICANON);  // enable signals and noncanonical mode
    termios.c_lflag &= ~ECHO;             // disable echo


    cfsetispeed(&termios, speed);
    cfsetospeed(&termios, speed);

    switch(parity)
    {
        case PARITY_NO_PARITY:
            termios.c_cflag &= ~PARENB;
            break;
        case PARITY_ODD:
            termios.c_cflag |= PARENB;
            termios.c_cflag |= PARODD;
            break;
        case PARITY_EVEN:
            termios.c_cflag |= PARENB;
            termios.c_cflag &= ~PARODD;
            break;
        default:
            fprintf(stderr, "invalid parity\n");
            break;
    }

    if(stop_bits == 1)
        termios.c_cflag &= ~CSTOPB;
    else if(stop_bits == 2)
        termios.c_cflag |= CSTOPB;
    else
        fprintf(stderr, "Invalid stop bit\n");

    int bits;

    switch(data_bits)
    {
        case 5:
        case 6:
        case 7:
        case 8:
            bits = dbits_map[data_bits];
            break;

        default:
            bits = -1;

    }

    if(bits != -1)
    {
        termios.c_cflag &= ~CSIZE;
        termios.c_cflag |= bits;
    } else
        fprintf(stderr, "Invalid data size\n");


    if(tcsetattr(fd, TCSANOW, &termios) == -1)
    {
        fprintf(stderr, "Could not get tty attributes from %s: %s\n", tty, strerror(errno));
        close(fd);
        return -1;
    }


    return fd;
}

/**
 * tty: "/dev/ttyUSB0"
 * baud: baudrate, for example 9600
 * mode: a string like 8N1 where 
 *       the first character is the number of data bits (range from 5-8)
 *       the second character is N (no parity), O (odd), E (even)
 *       the third character is the number of stop bits (1 or 2)
 */
int openSerial(const char *tty, int baud, const char *mode)
{
    if(tty == NULL || mode == NULL)
        return -1;

    if(strlen(mode) != 3)
    {
        fprintf(stderr, "invalid mode\n");
        return -1;
    }

    int stop_bits = mode[2];
    if(stop_bits != '1' && stop_bits != '2')
    {
        fprintf(stderr, "Invalid stop bits\n");
        return -1;
    }

    stop_bits -= '0';

    enum parity_t parity;
    switch(mode[1])
    {
        case 'n':
        case 'N':
            parity = PARITY_NO_PARITY;
            break;
        case 'o':
        case 'O':
            parity = PARITY_ODD;
            break;
        case 'e':
        case 'E':
            parity = PARITY_EVEN;
            break;
        default:
            fprintf(stderr, "Invalid parity\n");
            return -1;
    }

    int data_bits = mode[0] - '0';

    if(data_bits < 5 || data_bits > 8)
    {
        fprintf(stderr, "invalid data bits\n");
        return -1;
    }

    return openSerial_long(tty, baud, parity, stop_bits, data_bits);
}
我不知道您必须使用哪些串行设置,请查阅手册

也要注意像这样的东西

n = write(fd, "AT I\r\n", 10);
是错误的,它是未定义的Behvaior,因为
write
正在读取边界上的内容 字符串文本的。最好是:

const char *cmd = "AT I\r\n";
n = write(fd, cmd, strlen(cmd));
然后您将写入正确数量的数据

正如我在评论中所说,我在谷歌搜索了ISO 9141-2,我可以 找不到有关是否使用AT命令的任何可靠信息。所以请 检查您试图阅读的OBDII芯片手册

ISO 9141-2。此协议的异步串行数据速率为10.4 kbit/s。它有点类似于RS-232;然而,信号电平是不同的,通信发生在一条双向线路上,没有额外的握手信号。ISO 9141-2主要用于克莱斯勒、欧洲和亚洲车辆

在我看来,这个协议只是类似于RS232,也许你需要 支持此波特率的另一个转换器(除)。 第页还指出波特率为10400位/秒,这不是 默认情况下支持。我发现这也表明你 应使用两个转换器,一个用于OBD2和转换器之间的通信 速度为10.4 kbit/s,转换器和PC之间的速度为标准波特率 大约19.2 kbits/s

或者,您可以尝试设置自定义波特率,如所述和 . 我从来没有使用过自定义波特率,所以我不知道这个
工作。

好的,首先:我不知道C。但是,你做了n=(无论发送AT命令是什么),对于你收到的读取数据,然后打印。为什么不将读取的结果附加到变量中并打印出来呢?或者,您可以使用基于bash的命令与“minicom”之类的串行端口通信,我知道还有其他类似的

还有一些其他的注意事项,因为我最近一直在使用OBD2:AT命令发送给读卡器,而不是ECU。您可以使用minicom查看当您重置适配器(ATZ)时ECU什么也不做。但是,发送03(或ECU代码重置的任何模式),它将清除您的代码。 有关多个ECU的标题和类似内容的更多信息,请参阅


最后一点注意:别忘了你有两个不同的波特率-一个用于连接FT232R芯片的USB串行端口,另一个用于连接所述芯片到ECU。对于ELM327,后者通过AT命令来更改proto。无论如何,使用来自计算机的FT232R波特率,必要时在minicom中进行测试。希望这有帮助

OBD2适配器向您发回与您发送的命令完全相同的命令是完全正常的。这称为回声模式,可以通过发送
ATE0\r
作为第一个命令来关闭。如果您阅读了更多的答案,您应该会看到您的命令的结果出现在响应的请求之后


还请注意,OBD2在不向任何ECU发送数据的情况下处理AT命令,只有PID(由数字组成的命令)将通过总线发送。

可能是因为您使用相同的缓冲区进行读写,而读取失败,这就是为什么它看起来是相同的。请分享代码,否则我们只能猜测。在原始问题中添加了代码。当我试图从ECU读取数据时,我不确定是否还需要身份验证?
write(fd,“AT I\r\n”,10)
是未定义的行为,您溢出了字符串文本,并且可能向设备发送垃圾
write(fd,“AT I\r\n”,strlen(“AT I\r\n”))
在更改后正确,即I刚刚接收到相同的数据。因此,我发送“AT I\r\n”并接收“AT I”,而不是来自ECU的实际数据。我正在努力弄清楚为什么它只返回相同的内容。我不熟悉ISO 9141-2协议,请查看手册,也许您需要在AT I之前发送另一个AT命令,以便启用对它的访问。
const char *cmd = "AT I\r\n";
n = write(fd, cmd, strlen(cmd));