Чтение из последовательного порта после записи на него

Я работаю над проектом, в котором мой компьютер взаимодействует с платой Arduino, которая считывает выходные данные датчика и помещает их в последовательный порт, только если был получен «t». Код Arduino, как показано ниже, работает.

const int inputPin = 0;
void setup(){
  Serial.begin(9600);
  pinMode(13, OUTPUT);}

void loop(){
 if (Serial.available() > 0){
    char c=Serial.read();
   if(c=='t'){
      int value = analogRead(inputPin);
      float celsius = (5.0 * value * 100.0)/1024.0; 
      Serial.println(celsius);
    }
  }
}

Моя проблема в коде C, когда я пытаюсь прочитать, что Arduino помещает в последовательный порт. Мой код C:

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

int main(){     
    int STATE_OK=0;
    int STATE_WARNING=1;
    int STATE_CRITICAL=2; 
    char tempbuf[10];
    int fd=open("/dev/ttyACM0",O_RDWR | O_NOCTTY | O_NONBLOCK);
    if(fd == -1){
            printf("Unable to open /dev/ttyACM0\n");
            return STATE_WARNING;
    } else {
        fcntl(fd, F_SETFL, FNDELAY);
        int w=write(fd, "t", 1);
        printf("The number of bytes written to the serial port is %d \n",w);
        fprintf(stderr, "fd = %d.\n", fd);
        sleep(10);
        int n=read(fd,tempbuf,5);
        printf("%d,%s \n",n,strerror(errno));
        if(n>0){
            float temp=atof(tempbuf);
            printf("Temperature is: %f Celsius\n", temp);
            if (temp>27){
                return STATE_CRITICAL;
            }else{
                printf("The temperature is %f Celsius and checked 10 seconds ago\n",temp);
                return STATE_OK;
            }
        }
    }
    close(fd);
    return 0;
}

n всегда = 0, и я не могу понять, в чем проблема. Заранее спасибо.


person Youmna Habchy    schedule 16.07.2013    source источник
comment
Достаточно ли продолжительный сон для ответа?   -  person suspectus    schedule 16.07.2013
comment
Я уже пытался изменить его на сон (1000), но n по-прежнему = 0, и я думаю, что этого достаточно, потому что у arduino быстрый отклик.   -  person Youmna Habchy    schedule 16.07.2013
comment
По крайней мере, используйте программу типа Putty, чтобы убедиться, что ваш компьютер может получать данные через последовательный порт. Ошибки проводки, конечно, являются объяснением, другое — не заботиться о рукопожатии. Использование O_NONBLOCK, число 5 и отсутствие настройки параметров порта, таких как скорость передачи, также являются хорошим способом навлечь на себя неприятности.   -  person Hans Passant    schedule 16.07.2013
comment
Я не уверен, понял ли я, что вы имеете в виду, но когда я читал из последовательного порта, не записывая, а затем читая, он работал, поэтому мой компьютер мог получать данные из последовательного порта. Запись без чтения тоже работала, проблема в том, что я использую их вместе. Спасибо за помощь мне.   -  person Youmna Habchy    schedule 16.07.2013
comment
Идея отладки: вернуться туда, где работало чтение (без записи). Затем измените open(), чтобы разрешить запись, но не выполнять запись. Идея состоит в том, чтобы определить, является ли проблема вызовом open() или вызовом write().   -  person chux - Reinstate Monica    schedule 16.07.2013
comment
Есть ли у вас возможность подключить петлевой разъем к последовательному порту? (Например, на 9-контактном D-sub, короткие контакты 2 и 3.)   -  person chux - Reinstate Monica    schedule 16.07.2013
comment
Я попробовал то, что вы предложили, и после разрешения записи в open() без записи read() продолжает нормально работать   -  person Youmna Habchy    schedule 16.07.2013
comment
Вы имеете в виду, что я должен подключить контакт RX к TX платы arduino??   -  person Youmna Habchy    schedule 16.07.2013


Ответы (5)


не могу понять в чем проблема

Одна большая проблема заключается в том, что программа C, работающая на «компьютере», неполна.

Программа Arduino настраивает последовательный порт, по крайней мере, на скорость передачи данных (и все остальное, что может выполняться по умолчанию).
Но «компьютерная» программа на C никогда не настраивает должным образом последовательный порт. Последовательный порт будет использовать любые ранее настроенные атрибуты (скорость передачи, длина данных, настройка четности, канонический или необработанный режим), что приведет к непредсказуемым операциям чтения и записи. (Петлевой тест, вероятно, даст ложноположительный результат.)

Используйте руководство по последовательному порту POSIX или этот ответ для примера кода.

Для канонического режима вам, вероятно, потребуется добавить такой код (при условии, что 8N1):

    rc = tcgetattr(fd, &tty);
    if (rc < 0) {
        /* handle error */
    }
    savetty = tty;    /* preserve original settings for restoration */

    spd = B9600;
    cfsetospeed(&tty, (speed_t)spd);
    cfsetispeed(&tty, (speed_t)spd);

    tty.c_cflag &= ~PARENB
    tty.c_cflag &= ~CSTOPB
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;

    tty.c_cflag &= ~CRTSCTS;    /* no HW flow control? */
    tty.c_cflag |= CLOCAL | CREAD;

    tty.c_iflag |= IGNPAR | IGNCR;
    tty.c_iflag &= ~(IXON | IXOFF | IXANY);
    tty.c_lflag |= ICANON;
    tty.c_oflag &= ~OPOST;

    rc = tcsetattr(fd, TCSANOW, &tty);
    if (rc < 0) {
        /* handle error */
    }

Вы, вероятно, должны удалить строку

fcntl(fd, F_SETFL, FNDELAY);  

а также параметр O_NONBLOCK в вызове open().

person sawdust    schedule 17.07.2013
comment
Спасибо за ваш ответ, но, честно говоря, я не понял код, нет ли другого способа решить проблему без последовательного программирования? Заранее спасибо. - person Youmna Habchy; 17.07.2013
comment
Есть команда stty, но она не на 100% надежна, как кодирование конфигурации в программе. Вам необходимо прочитать руководство по последовательному порту POSIX и/или этот ответ для образец кода. - person sawdust; 17.07.2013
comment
После прочтения руководства по последовательному порту POSIX я редактирую свой код (как вы предложили), и у меня все еще есть n=0 и c=� , я опубликую свой новый код в ответе. - person Youmna Habchy; 17.07.2013
comment
(1) Вы должны опубликовать измененный код как редактирование вашего вопроса, а не как ответ. (2) В вашем исправленном коде tcsetattr() находится не в том месте, чтобы быть эффективным, поэтому, конечно, никаких улучшений. (3) Коды возврата от tc[gs]etattr() необходимо проверить. (4) Вы не удалили fcntl() и добавили O_NODELAY, что, вероятно, неверно. (5) Вы внесли больше правок, чем необходимо, и изменили программу с чтения всей строки на чтение только одного символа за раз. Вам нужно выбрать канонический режим или необработанный режим и сделать атрибуты совместимыми с логикой read(). - person sawdust; 17.07.2013

попробуй это

int n=read(fd,&tempbuf,sizeof(tempbuf));

вместо

int n=read(fd,tempbuf,5);
person Aditya Ponkshe    schedule 16.07.2013
comment
удалите O_NONBLOCK и посмотрите, что произойдет. - person Aditya Ponkshe; 16.07.2013
comment
У меня все еще тот же результат. - person Youmna Habchy; 16.07.2013
comment
поэтому в printf(%d,%s\n,n,strerror(errno)); значение n всегда равно нулю? - person Aditya Ponkshe; 16.07.2013
comment
Да, результат: 0, успех - person Youmna Habchy; 16.07.2013
comment
попробуйте это fcntl(fd, F_SETFL, 0); - person Aditya Ponkshe; 16.07.2013
comment
тогда у меня нет предложений, извините. - person Aditya Ponkshe; 16.07.2013

Разве вы не должны завершать данные, отправленные с помощью «\ 0»? Серж

person Serge Bollaerts    schedule 16.07.2013

Чтение описания read() (показанного ниже) говорит нам, что n = 0, когда вы достигаете конца файла. Поскольку серийный номер не отправляет \0, чтение будет продолжаться до тех пор, пока не будет достигнут конец файла. Поэтому я думаю, что n==0 - это результат, который вы хотите.

Итак, может быть, ваш if (n>0)

тест должен быть если (n==0)

Можно ли увидеть ожидаемые символы в буфере с помощью отладчика?

read() #include int read(int handle, void *buffer, int nbyte);

Функция read() пытается прочитать n байтов из файла, связанного с дескриптором, и помещает прочитанные символы в буфер. Если файл открывается с помощью O_TEXT, он удаляет возврат каретки и определяет конец файла.

Функция возвращает количество прочитанных байтов. В конце файла возвращается 0, в случае ошибки возвращается -1, устанавливая errno для указания типа возникшей ошибки.

person Jeff    schedule 16.07.2013
comment
Спасибо, но у меня всегда один и тот же результат. - person Youmna Habchy; 17.07.2013

Спасибо за ваши ответы. Это мой окончательный код:

#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<fcntl.h>
#include<termios.h>

int main() {    

    int STATE_OK=0;
    int STATE_WARNING=1;
    int STATE_CRITICAL=2; 
    char tempbuf[10];
    struct termios tty;

    int fd=open("/dev/ttyACM1",O_RDWR | O_NOCTTY);
    if(fd == -1){
            printf("Unable to open /dev/ttyACM1\n");
            return STATE_WARNING;
    }else {
        if(tcgetattr(fd, &tty)!=0){
            perror("tcgetatt() error");
        }else{
                cfsetospeed(&tty, B9600);
                cfsetispeed(&tty, B9600);

                tty.c_cflag &= ~PARENB;
                tty.c_cflag &= ~CSTOPB;
                tty.c_cflag &= ~CSIZE;
                tty.c_cflag |= CS8;
                tty.c_cflag &= ~CRTSCTS; 
                tty.c_cflag |= CLOCAL | CREAD;

                tty.c_iflag |= IGNPAR | IGNCR;
                tty.c_iflag &= ~(IXON | IXOFF | IXANY);
                tty.c_lflag |= ICANON;
                tty.c_oflag &= ~OPOST;
                tcsetattr(fd, TCSANOW, &tty);

                int w=write(fd, "t", 1);/*printf("%d\n",w);
                fprintf(stderr, "fd = %d.\n", fd);*/
                usleep(1000);
                int n=read(fd,tempbuf,8);/*printf("%d \n",n);*/
                tempbuf[9]=0;
                float temp=atof(tempbuf);

                if (temp>27){
                    printf("CRITICAL: %f celsius\n",temp);
                    return STATE_CRITICAL;
                }else{
                    printf("Everything is OK and the temperature is %f Celsius\n",temp);
                    return STATE_OK;
                }
        }
    }
    close(fd);
    return 0;
}
person Youmna Habchy    schedule 18.07.2013
comment
Надлежащая благодарность будет заключаться в том, чтобы принять ответ, который объясняет, как вы пришли к этому окончательному коду. - person sawdust; 18.07.2013