尝试将AT命令写入使用FT232R读取ECU数据的USB至OBDii电缆(ISO 9141-2)
我正在尝试使用ISO 9141-2协议从ECU读取数据。我使用的电缆是OBD2到USB,使用FT232R芯片。 我正在运行的程序是C语言的 当我将命令写入串行端口(ttyUSB0)时,它会很好地写入,但当它读回接收到的数据时,它只返回相同的数据。不是从ECU返回数据,我不知道它为什么这样做 任何帮助都很好,谢谢 示例代码-尝试设置波特率等,但也没有运气尝试将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&
#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));