我正在尝试使用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;
}
即使这不是问题的直接答案,但这段代码不适合评论部分。
我使用这些函数来初始化串行线:
#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);
}
最常见的模式是"8N1"
(8位数据,无奇偶校验,1个停止位),我打开串行线路
int fd = open("/dev/ttyUSB0", 9600, "8N1");
if(fd == -1)
{
fprintf(stderr, "Error, could not initialize serial line\n");
exit(EXIT_FAILURE);
}
我不知道您必须使用哪些串行设置,请在手册中查找。
还要注意像这样的东西
n = write(fd, "AT I\r\n", 10);
这是错误的,它是未定义的行为,因为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,也许你需要另一个支持这种波特率的转换器(FT232R除外)。 This页面还指出波特率为10400位/秒,默认情况下不支持。我发现这个post也建议你应该使用两个转换器,一个用于OBD2和转换器之间的通信,速率为10.4 kbit / s,另一个转换器和PC之间的标准波特率,如19.2 kbits / s。
好吧首先关闭:我不知道C.但是,你做了n =(无论发送AT命令)和你收到的读数据,然后打印。为什么不将读取的结果附加到变量并打印出来?或者,您可以使用基于bash的命令与串口进行通信,如“minicom”,我知道还有其他类似的。
还有其他一些注释,因为我最近一直在使用OBD2:AT命令发送给读者,而不是ECU。您可以使用minicom查看何时重置适配器(ATZ),ECU什么都不做。但是,发送03(或任何模式是ECU代码重置)它将清除您的代码。有关标题的更多信息以及多个ECU的更多信息,请参阅https://mechanics.stackexchange.com/questions/22982/received-frames-from-vehicles-with-multiple-ecu-chips
最后一点:不要忘记你有2种不同的波特率 - 一种用于USB串口到FT232R芯片,另一种用于从芯片到ECU。使用ELM327,后者通过AT命令完成,以更改原型。无论如何,请使用来自计算机的FT232R波特率,必要时在minicom中进行测试。希望这有帮助!
OBD2适配器将您发送的命令发送回去是完全正常的。这称为回声模式,可以通过发送ATE0\r
作为第一个命令来关闭。如果您阅读了更多答案,您应该会在回显的请求之后看到命令的结果。
另请注意,OBD2处理AT命令而不向任何ECU发送数据,只有PID(由数字组成的命令)将通过总线发送。