Возникли проблемы с последовательным портом в Linux, между AVR и Linux

Здравствуйте, я пытаюсь общаться между AVR Atmega32a и Linux дистрибутива. Я использую чип FTD на USB-порт (драйверы VCOM и т. Д.)

Я буду публиковать коды в AVR и Linux, но код в AVR работает нормально, так как я тестировал его на Minicom.

Я предполагаю, что проблема здесь в моем коде на Linux. Основная проблема в том, что иногда это работает, иногда не работает. Я предполагаю, что это как-то связано с открытием и закрытием файлового дескриптора или самого порта.

Почему я это говорю?

Код на AVR делает простую вещь. Ожидает нажатия кнопки, а затем начинает посылать "Hello world" навсегда.

Так что при использовании minicom все работает просто отлично.

Когда я использую свою программу в первый раз и жду, пока кнопка не будет нажата, мне кажется, что я ничего не могу прочитать из порта, даже если я нажимаю кнопку.

Затем я открываю Minicom, и он сразу начинает читать (потому что кнопка была нажата). Затем я закрываю Minicom, я открываю свою программу, и она отлично работает....

Кажется, возникают проблемы с открытием и закрытием файла (порта), но я не уверен. В любом случае, эта вещь недостаточно стабильна.

Любая помощь будет благодарна.

То, что я хочу написать, это читать постоянно с последовательного порта. Я читал о блокировке чтения, но когда я пытаюсь реализовать это, это, кажется, не работает.

Благодарю.

ОБНОВЛЕНИЕ ** Я просто добавил else if (wordsRead<0) printf ("Ошибка чтения \ n"); кажется, что он получает -1 при чтении в первый раз, но я не понимаю, почему это происходит Проблема в том, что когда он правильно читает с порта (после первого использования minicom), я получаю много чтений ошибок между "Привет, мир" печатает....

Вот мой код AVR только основная функция.

int main()
{
    uart_init();
    //Set A0-6 as input, A7 as output
    //Set as hexademical cause compiler does not support 0b
    DDRA = 0x80;;
    //Triggers up
    PORTA = 0xFF;

    while ((PINA & 0x1) == 1);
    //Led on
    PORTA &= 0x7F; 

    while (1){  
        uart_putstring("Hello world ");
    }
}

Вот мой код C на Linux.

#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>

int main()
{
    //Open Port  
    int fdSP= open("/dev/ttyUSB0",O_RDWR | O_NOCTTY | O_NDELAY);
    if (fdSP == -1){
        printf("Error opening serial port\n");
        return 1;
    }

    // create the struct
    struct termios options;

    //Preferences
    int BaudRate = 19200;

    //Set Baud Rate
    cfsetispeed(&options, BaudRate);
    cfsetospeed(&options, BaudRate);

    //Set Parity (No Parity)
    options.c_cflag &= ~PARENB;

    //Set Stop Bits (2 Stop Bits)
    options.c_cflag &= CSTOPB;

    //Set Data Bits (8 Data Bits)
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;


    if (tcsetattr(fdSP, TCSANOW, &options) != 0){
        printf("Error applying settings to serial port\n");
        return 1;
    }



    //Read Port
    pid_t pid = fork();
    if (pid < 0){
        printf("Error creating child\n");
        return 1;
    }
    else if (pid == 0){
        raise(SIGSTOP);
        int wordsRead;
        char readSP;
        while (1){
            wordsRead = read(fdSP, &readSP, 1);
            if (wordsRead > 0)
                printf("%c", readSP);
                    else if (wordsRead < 0)
                            printf("Error reading\n");
           }
    }
    else{
        printf("Created a child to read from serial port\n");
        printf("To kill the child open another terminal and type sudo kill %ld or press enter ok?", (long) pid);
        getchar();
        kill(pid, SIGCONT);
        getchar();
        kill(pid, SIGKILL);

        if (close(fdSP) == -1){
            printf("Error closing port\n");
            return 1;
        };
    }
    return 0;
}

2 ответа

Хорошо, я нашел проблему...

Кажется, проблема была в том порядке, в котором я выполнял все действия по настройке атрибутов и т. Д.

Я изменил заказ на

  1. Определите нужные атрибуты -> параметры (новые).
  2. Откройте серийный порт.
  3. Получить существующие атрибуты -> oldoptions.
  4. Установите новые атрибуты -> параметры (новые).
  5. Читать из порта.
  6. Восстановите старые атрибуты -> oldoptions.
  7. Закройте порт.

Порядок до (не работал) был (2->3->1->4->5->6->7)

Спасибо @Bart Friederichs за ценные советы и помощь

Мой окончательный код ниже

основной (подлежит исполнению)

#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
#include "sp-proc.h"

#define MY_BAUDRATE B19200


int main()
{
    // create the struct
    struct termios options, oldoptions;


    memset(&options,0,sizeof(options));
    options.c_iflag = 0;
    options.c_oflag = 0;
    options.c_cflag = CS8|CREAD|CLOCAL;
    options.c_lflag = 0;
    options.c_cc[VMIN] = 1;
    options.c_cc[VTIME] = 0;

    //Setting Baud Rate
    cfsetispeed(&options, MY_BAUDRATE);
    cfsetospeed(&options, MY_BAUDRATE);

    //Open Serial Port  
    int fdSP = openSP();

    //Save old options to oldoptions
    getOldAttr(fdSP, &oldoptions);

    //Set new options
    setNewAttr(fdSP, &options, &oldoptions);

    //Create child to read from port
    pid_t pid = fork();
    if (pid < 0){
        printf("Error creating child\n");
        exit(1);
    }
    else if (pid == 0){

        raise(SIGSTOP);
        //Read Port
        int wordsRead;
        char readSP;
        while (1){
            wordsRead = read(fdSP, &readSP, 1);
            if (wordsRead > 0)
                printf("%c", readSP);
        }
        exit(0);
    }
    else{
        printf("Created child with pid = %ld to read from Serial Port\n", (long) pid);
        printf("To stop reading from serial port open another terminal ");
        printf("and type sudo kill %ld or press <enter> ok?", (long) pid);
        getchar();
        kill(pid, SIGCONT);
        getchar();
        kill(pid, SIGSTOP); 
        printf("\n");

        //Restoring old options
        resetOldAttr(fdSP, &oldoptions);
        //Closing SerialPort
        closeSP(fdSP);
        exit(0);
    }
}

зр-proc.h

int openSP(void);
void closeSP(int fd);
void getOldAttr(int fd, struct termios* old);
void resetOldAttr(int fd, struct termios* old);
void setNewAttr(int fd, struct termios* new, struct termios* old);

зр-proc.c

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

int openSP(){
    int fd= open("/dev/ttyUSB0",O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1){
        printf("Error opening serial port\n");
        exit(1);
    }
    return fd;
}

void closeSP(int fd){
    if (close(fd) == -1){
            printf("Error closing port\n");
            exit(1);
    }
}

void getOldAttr(int fd, struct termios* old){
    if (tcgetattr(fd, old) != 0){
        printf("Error getting old options from serial port\n");
        closeSP(fd);
        exit(1);
    }
}

void resetOldAttr(int fd, struct termios* old){
    if (tcsetattr(fd, TCSANOW, old) != 0){
        printf("Error restoring old options\n");
        closeSP(fd);
        exit(1);
    }
}

void setNewAttr(int fd, struct termios* new, struct termios* old){
    if (tcsetattr(fd, TCSANOW, new) != 0){
        printf("Error applying settings to serial port\n");
        resetOldAttr(fd, old);
        closeSP(fd);
        exit(1);
    }
}

Это:

// create the struct
struct termios options;

создает неинициализированный struct termios, Сначала вы должны выполнить инициализацию с текущими настройками порта, а затем изменить настройки:

// create the struct
struct termios options;
tcgetattr(fdSP, &options);
Другие вопросы по тегам