C程序不断在串口上发送相同的数据

时间:2015-03-20 15:02:24

标签: c serial-port arm embedded-linux

我正在开发一个运行Linux嵌入式ARM的SOM板,我正在开发一个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”在到达时返回读取的数据(使用下面的“serial_read”)。我发送的字符正确到达,无论我重复“w”和“r”循环的时间,答案都会在控制台上正确显示。

二级菜单中的选项应该以相同的方式运行:它们只是调用一个例程(下面的“sendSimpleCmd”),该例程调用带有costant char作为参数的“serial_write”(每个选项都不同),然后调用“ serial_read”。

问题是这只适用于所选的第一个选项:在此之后,无论我选择哪个选项,程序都会继续发送链接到所选第一个选项的数据。它一直这样做,直到我回到主菜单,然后再次选择“m”:此时发送的数据是我期望的,但随后的选择将被忽略,直到我返回主菜单(或关闭)该软件,如果重要的话)。

最奇怪的是,我在同一串口上收到了预期的数据,我正在使用与“板”通信,而在“正确”的串口上,我一直收到第一条消息。这是我选择“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: *

混合由软件输出(“发送数据1M”)和选择选项“a”(1K)后应发送的数据组成。因为在“正确”的端口上我反复收到相同的消息,而在“错误”的端口上我收到正确的消息,似乎软件会以某种方式自动更改端口。

问题是: 这种行为可能是由我的编码引起的,还是与其他东西绑定在一起,比如某些内核配置?如果需要更多信息,请询问。

提前谢谢


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");
    }
}

1 个答案:

答案 0 :(得分:1)

在使用strcat之前,你应该初始化 toBeSent 的内容。

您的编译器可能通过使用0而不是垃圾来初始化数组来保存您,但如果不是,则可能导致缓冲区溢出。没有代码可以防止这种情况发生,所以这可能是程序意外行为的原因。如果没有看到其余的代码并了解其他一些细节,就很难知道究竟是什么问题。如果这是其余代码的示例,那么解决方案可能会修改代码以解决这些问题。

考虑使用安全字符串函数来帮助防止缓冲区溢出。