C程序不断在串口上发送相同的数据
C program keeps sending same data on serial port
我正在开发用于 ARM 的嵌入式 SOM 板 运行 Linux,我正在开发一个 C 程序以通过串行 (RS232) 端口与外部设备通信。不过,我遇到了一种奇怪的行为。我也在使用板子的另一个串口与板子上的linux运行通信。
该软件结构简单:是一个纯文本的类似控制台的程序,以此作为主菜单:
Possible commands:
1 - 4: Select serial device (pump should be on 1)
m - pump op. mode configuration
r - reads from the serial device
w - writes to the serial device
>>>>>>>>>>>>>>Current device is /dev/ttymxc1
>>>>>>>>>>>>>>Enter input (q quits):
和一个二级菜单(由上面的 "m" 选项打开)
SPEED:
r - rpm (sends 1M<CR>) //<CR> stands for carriage return
f - flow rate (sends 1N<CR>)
QUANTITY:
v - volume (sends 1H<CR>)
t - time (sends 1O<CR>)
DIRECTION:
c - clockwise (sends 1T<CR>)
a - c-clockwise (sends 1K<CR>)
>>>>>>>>>>>>>>Enter input (q quits):
使用主菜单选项 "r" 和 "w" 的通信工作正常(因此消除了我对波特率等串行设置的任何疑问):"w" 调用例程("serial_write" 发送用户输入的单个字符,而 "r" returns 数据一到达就读取(使用 "serial_read" 下面)。我发送的字符正确到达,控制台上正确显示答案,无论我重复 "w" 和 "r" 循环的次数如何。
二级菜单中的选项应该以相同的方式运行:它们只是调用一个例程(下面的"sendSimpleCmd"),该例程调用"serial_write",并以一个常量字符作为参数(每个选项不同) ,然后调用 "serial_read"。
问题是这只适用于第一个选择的选项:之后,程序会继续发送链接到第一个选择的选项的数据,无论我选择哪个选项。一直这样直到我回到主菜单,然后再选择"m":此时发送的数据是我期望的,但是后面的选择将被忽略,直到我回到主菜单(或关闭软件,如果重要的话)。
最奇怪的是,我在用于与开发板通信的同一串口上收到预期数据,而在 "right" 串口上我不断收到第一条消息。这是当我选择 "a" 作为第二个选项时从控制台粘贴的文本,在选择 "f" 作为第一个选项(我添加的评论)之后:
SPEED:
r - rpm (sends 1M<CR>)
f - flow rate (sends 1N<CR>)
QUANTITY:
v - volume (sends 1H<CR>)
t - time (sends 1O<CR>)
DIRECTION:
c - clockwise (sends 1T<CR>)
a - c-clockwise (sends 1K<CR>)
>>>>>>>>>>>>>>Enter input (q quits):
a //second option
1Knding 1M //mixup of data
wrote 4 characters on fs 4
serial_read: *
混合是由软件输出("Sending data 1M")和选择选项"a"(1K)后应发送的数据组成的。由于在 "right" 端口上我一遍又一遍地收到相同的消息,而在 "wrong" 端口上我收到正确的消息,似乎软件以某种方式自动更改端口。
问题是:
这种行为可能是由我的编码引起的,还是绑定到其他东西,比如某些内核配置?如果需要更多信息,请询问。
提前致谢
Serial_write
void serial_write(char text[], int length){
if (selectedDevice == 0){
printf("Select device first!\r\n");
return;
}
int n;
length = length +1 + 2;
char toBeSent[length];
strcat(toBeSent, PUMP_CMD_MSG_START); //header, "1"
strcat(toBeSent, text);
strcat(toBeSent, PUMP_CMD_MSG_END); //footer, "<CR>"
printf("Sending %s\r\n", toBeSent);
n = write (fd, toBeSent, length);
if (n<0){
printf("writing failed on /dev/ttymxc%i\r\n", selectedDevice);
} else {
printf("wrote %i characters on fs %i\r\n", n, fd);
}
}
Serial_read
int serial_read(char *buffer, int size){
int bytes = 0;
int n;
int i = 0;
char tmp_buffer[size];
while(1){
ioctl(fd, FIONREAD, &bytes);
if (bytes > 0){
break;
}
i++;
if(i> 1000){
printf("FIONREAD tries exceeded 1000, aborting read\r\n");
return;
}
usleep(1000);
}
n=read(fd, tmp_buffer, sizeof(tmp_buffer));
for(i=0;i<n;i++) {
buffer[i]=tmp_buffer[i];
}
printf("serial_read: %s\r\n", buffer);
return 0;
}
sendSimpleCmd
void sendSimpleCmd(char text[]){
int bufSize= 20;
char answer[bufSize];
serial_write(text,1);
if (serial_read(answer, bufSize) == 0) {
printf("Ricevuto da pompa \"%s\":", answer);
//handling of possible answers, doesn't do anything relevant since it always receives "*" as answer
if (strcmp(answer, PUMP_ANS_OK) == 0){ //PUMP_ANS_OK is "*"
printf("ok!\r\n");
} else if (strcmp(answer, PUMP_ANS_NOK) == 0){
printf("errore!\r\n");
} else {
printf("sconosciuto!\r\n");
}
} else {
// printf("read failed\r\n");
}
}
您应该在使用 strcat 之前初始化 toBeSent 的内容。
您的编译器可能通过使用 0 而不是垃圾初始化数组来节省您的时间,但如果不是这样,它可能会导致缓冲区溢出。没有代码可以防止这种情况,因此这可能是意外程序行为的原因。如果不查看代码的其余部分并且不了解其他一些详细信息,将很难知道到底是什么问题。如果这作为其余代码的示例,则解决方案很可能会修改代码以解决这些问题。
考虑使用安全字符串函数来帮助防止缓冲区溢出。
我正在开发用于 ARM 的嵌入式 SOM 板 运行 Linux,我正在开发一个 C 程序以通过串行 (RS232) 端口与外部设备通信。不过,我遇到了一种奇怪的行为。我也在使用板子的另一个串口与板子上的linux运行通信。
该软件结构简单:是一个纯文本的类似控制台的程序,以此作为主菜单:
Possible commands:
1 - 4: Select serial device (pump should be on 1)
m - pump op. mode configuration
r - reads from the serial device
w - writes to the serial device
>>>>>>>>>>>>>>Current device is /dev/ttymxc1
>>>>>>>>>>>>>>Enter input (q quits):
和一个二级菜单(由上面的 "m" 选项打开)
SPEED:
r - rpm (sends 1M<CR>) //<CR> stands for carriage return
f - flow rate (sends 1N<CR>)
QUANTITY:
v - volume (sends 1H<CR>)
t - time (sends 1O<CR>)
DIRECTION:
c - clockwise (sends 1T<CR>)
a - c-clockwise (sends 1K<CR>)
>>>>>>>>>>>>>>Enter input (q quits):
使用主菜单选项 "r" 和 "w" 的通信工作正常(因此消除了我对波特率等串行设置的任何疑问):"w" 调用例程("serial_write" 发送用户输入的单个字符,而 "r" returns 数据一到达就读取(使用 "serial_read" 下面)。我发送的字符正确到达,控制台上正确显示答案,无论我重复 "w" 和 "r" 循环的次数如何。
二级菜单中的选项应该以相同的方式运行:它们只是调用一个例程(下面的"sendSimpleCmd"),该例程调用"serial_write",并以一个常量字符作为参数(每个选项不同) ,然后调用 "serial_read"。
问题是这只适用于第一个选择的选项:之后,程序会继续发送链接到第一个选择的选项的数据,无论我选择哪个选项。一直这样直到我回到主菜单,然后再选择"m":此时发送的数据是我期望的,但是后面的选择将被忽略,直到我回到主菜单(或关闭软件,如果重要的话)。
最奇怪的是,我在用于与开发板通信的同一串口上收到预期数据,而在 "right" 串口上我不断收到第一条消息。这是当我选择 "a" 作为第二个选项时从控制台粘贴的文本,在选择 "f" 作为第一个选项(我添加的评论)之后:
SPEED:
r - rpm (sends 1M<CR>)
f - flow rate (sends 1N<CR>)
QUANTITY:
v - volume (sends 1H<CR>)
t - time (sends 1O<CR>)
DIRECTION:
c - clockwise (sends 1T<CR>)
a - c-clockwise (sends 1K<CR>)
>>>>>>>>>>>>>>Enter input (q quits):
a //second option
1Knding 1M //mixup of data
wrote 4 characters on fs 4
serial_read: *
混合是由软件输出("Sending data 1M")和选择选项"a"(1K)后应发送的数据组成的。由于在 "right" 端口上我一遍又一遍地收到相同的消息,而在 "wrong" 端口上我收到正确的消息,似乎软件以某种方式自动更改端口。
问题是: 这种行为可能是由我的编码引起的,还是绑定到其他东西,比如某些内核配置?如果需要更多信息,请询问。
提前致谢
Serial_write
void serial_write(char text[], int length){
if (selectedDevice == 0){
printf("Select device first!\r\n");
return;
}
int n;
length = length +1 + 2;
char toBeSent[length];
strcat(toBeSent, PUMP_CMD_MSG_START); //header, "1"
strcat(toBeSent, text);
strcat(toBeSent, PUMP_CMD_MSG_END); //footer, "<CR>"
printf("Sending %s\r\n", toBeSent);
n = write (fd, toBeSent, length);
if (n<0){
printf("writing failed on /dev/ttymxc%i\r\n", selectedDevice);
} else {
printf("wrote %i characters on fs %i\r\n", n, fd);
}
}
Serial_read
int serial_read(char *buffer, int size){
int bytes = 0;
int n;
int i = 0;
char tmp_buffer[size];
while(1){
ioctl(fd, FIONREAD, &bytes);
if (bytes > 0){
break;
}
i++;
if(i> 1000){
printf("FIONREAD tries exceeded 1000, aborting read\r\n");
return;
}
usleep(1000);
}
n=read(fd, tmp_buffer, sizeof(tmp_buffer));
for(i=0;i<n;i++) {
buffer[i]=tmp_buffer[i];
}
printf("serial_read: %s\r\n", buffer);
return 0;
}
sendSimpleCmd
void sendSimpleCmd(char text[]){
int bufSize= 20;
char answer[bufSize];
serial_write(text,1);
if (serial_read(answer, bufSize) == 0) {
printf("Ricevuto da pompa \"%s\":", answer);
//handling of possible answers, doesn't do anything relevant since it always receives "*" as answer
if (strcmp(answer, PUMP_ANS_OK) == 0){ //PUMP_ANS_OK is "*"
printf("ok!\r\n");
} else if (strcmp(answer, PUMP_ANS_NOK) == 0){
printf("errore!\r\n");
} else {
printf("sconosciuto!\r\n");
}
} else {
// printf("read failed\r\n");
}
}
您应该在使用 strcat 之前初始化 toBeSent 的内容。
您的编译器可能通过使用 0 而不是垃圾初始化数组来节省您的时间,但如果不是这样,它可能会导致缓冲区溢出。没有代码可以防止这种情况,因此这可能是意外程序行为的原因。如果不查看代码的其余部分并且不了解其他一些详细信息,将很难知道到底是什么问题。如果这作为其余代码的示例,则解决方案很可能会修改代码以解决这些问题。
考虑使用安全字符串函数来帮助防止缓冲区溢出。