QT/Examples

QT로 Serial 통신 구현하기 - 1

모래반지빵냐빵냐 2015. 4. 15. 12:00

출처 : http://god10276.tistory.com/entry/QT%EB%A1%9C-Serial-%ED%86%B5%EC%8B%A0-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-1


QT로 Serial 통신을 구현하려고 한다.

앞서 기본적으로 QT Creator 를 이용하여 Form을 생성하는 방법과 Button Event 등 Event 함수 등을 설정하는 방법 등에 대해서 기술하였다. 이번에는 실제 Serial 통신은 어떤 식으로 구현하는지 알아보자.

먼저 Window와 다르게 Linux는 /dev/ttyS0 -> COM1 , /dev/ttyS1 -> COM2 .... 이런 식으로 구성되고, USB to Serial 같은 경우에는 /dev/ttyUSB0 이런식으로 구분되기 때문에 따로따로 기술해 주어야 한다. 그래서 다음과 같이 정의했다.



#define DEVICE01 "/dev/ttyS0"
#define DEVICE02 "/dev/ttyS1"
#define DEVICE03 "/dev/ttyS2"
#define DEVICE04 "/dev/ttyUSB0"
#define DEVICE05 "/dev/ttyUSB1"



이런 식으로 정의하여서 사용자가 선택한 Device 장비로 Setting 될 수 있도록 하였다.

또한, BAUDRATE 같은 경우에는 <asm/termbits.h>에 정의되어 있는데 이것은 <termios.h>에 include 된다. 그러므로, <termios.h> Header File 만 Include 해 주면 된다. 

역시 편리하게 하기 위해 다음과 같은 방법으로 정의해 두었다.

#define BAUDRATE1200     B1200
#define BAUDRATE2400     B2400
#define BAUDRATE4800     B4800
#define BAUDRATE9600     B9600
#define BAUDRATE14400    B14400
#define BAUDRATE19200    B19200
#define BAUDRATE38400    B38400
#define BAUDRATE56000    B56000
#define BAUDRATE57600    B57600
#define BAUDRATE115200   B115200

기본적으로 Serial 통신을 위해 추가해 준 Header File은 다음과 같다.

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>



이제 본격적인 UI 구성으로 들어가 보자.





그냥 단순하게, Terminal 창 만을 나타낼 수 있도록 구성하였다. 앞부분에서 COM Port를 설정하고 뒷 부분에서 BAUDRATE를 설정한 후에 Connect를 하면 정상적으로 Board와 통신할 수 있게 된다. 해당 UI를 포함한 클래스의 Private member로 다음과 같은 항목들을 추가해 주었다.

    QSocketNotifier *notRsRead;
    int fd;
    char buf[BUFF_SIZE];


QSocketNotifier는 <QSocketNotifier>라는 Header를 추가해 주어야 한다. 이것에 대한 자세한 설명은 추후에 기술하도록 하겠다.

또한, QSocketNotifier에 의해 동작될 Event 함수도 public slots에 정의해 주었다. 

public slots:
    void setEvent();

// pushButton 사용자 정의 함수
private slots:
       void on_connectButton_clicked();

void MainWindow::on_connectButton_clicked()
{
    /*
        #define DEVICE01 "/dev/ttyS0"
        #define DEVICE02 "/dev/ttyS1"
        #define DEVICE03 "/dev/ttyS2"
        #define DEVICE04 "/dev/ttyUSB0"
        #define DEVICE05 "/dev/ttyUSB1"

        #define BAUDRATE1200     B1200
        #define BAUDRATE2400     B2400
        #define BAUDRATE3800     B4800
        #define BAUDRATE9600     B9600
        #define BAUDRATE14400    B14400
        #define BAUDRATE19200    B19200
        #define BAUDRATE38400    B38400
        #define BAUDRATE56000    B56000
        #define BAUDRATE57600    B57600
        #define BAUDRATE115200   B115200
    */

    struct termios newtio;
    int res;

    QString temp_port, port;
    QString temp_baudrate, baudrate;

    temp_port = ui->portBox->currentText();

    if(temp_port == "ttyS0")
    {
        fd = open(DEVICE01, O_RDWR | O_NOCTTY | O_NONBLOCK);
    }
    else if(temp_port == "ttyS1")
    {
        fd = open(DEVICE02, O_RDWR | O_NOCTTY | O_NONBLOCK);
    }
    else if(temp_port == "ttyS2")
    {
        fd = open(DEVICE03, O_RDWR | O_NOCTTY | O_NONBLOCK);
    }
    else if(temp_port == "ttyUSB0")
    {
        fd = open(DEVICE04, O_RDWR | O_NOCTTY | O_NONBLOCK);
    }
    else
    {
        fd = open(DEVICE05, O_RDWR | O_NOCTTY | O_NONBLOCK);
    }

    memset(&newtio, 0, sizeof(newtio));

    temp_baudrate = ui->baudrateBox->currentText();

    if(temp_baudrate == "1200")
        newtio.c_cflag = BAUDRATE1200;
    else if(temp_baudrate == "2400")
        newtio.c_cflag = BAUDRATE2400;
    else if(temp_baudrate == "4800")
        newtio.c_cflag = BAUDRATE4800;
    else if(temp_baudrate == "9600")
        newtio.c_cflag = BAUDRATE9600;
    else if(temp_baudrate == "19200")
        newtio.c_cflag = BAUDRATE19200;
    else if(temp_baudrate == "38400")
        newtio.c_cflag = BAUDRATE38400;
    else if(temp_baudrate == "57600")
        newtio.c_cflag = BAUDRATE57600;
    else if(temp_baudrate == "115200")
        newtio.c_cflag = BAUDRATE115200;

    newtio.c_cflag |= CS8;
    newtio.c_cflag |= CLOCAL | CREAD;
    newtio.c_iflag = IGNPAR;
    newtio.c_oflag = 0;
    newtio.c_lflag = 0;

    newtio.c_cc[VINTR]    = 0;     /* Ctrl-c */
    newtio.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
    newtio.c_cc[VERASE]   = 0;     /* del */
    newtio.c_cc[VKILL]    = 0;     /* @ */
    newtio.c_cc[VEOF]     = 4;     /* Ctrl-d */
    newtio.c_cc[VTIME]    = 0;     /* inter-character timer unused */
    newtio.c_cc[VMIN]     = 1;     /* blocking read until 1 character arrives */
    newtio.c_cc[VSWTC]    = 0;     /* '\0' */
    newtio.c_cc[VSTART]   = 0;     /* Ctrl-q */
    newtio.c_cc[VSTOP]    = 0;     /* Ctrl-s */
    newtio.c_cc[VSUSP]    = 0;     /* Ctrl-z */
    newtio.c_cc[VEOL]     = 0;     /* '\0' */
    newtio.c_cc[VREPRINT] = 0;     /* Ctrl-r */
    newtio.c_cc[VDISCARD] = 0;     /* Ctrl-u */
    newtio.c_cc[VWERASE]  = 0;     /* Ctrl-w */
    newtio.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
    newtio.c_cc[VEOL2]    = 0;     /* '\0' */


    tcflush(fd, TCIFLUSH);
    tcsetattr(fd, TCSANOW, &newtio);

    notRsRead = new QSocketNotifier(fd, QSocketNotifier::Read, this);
    connect(notRsRead, SIGNAL(activated(int)), this, SLOT(setEvent()));

}

void MainWindow::setEvent()
{
    int szRead;
    szRead = read(fd, buf, BUFF_SIZE);
    buf[szRead] = '\0';
    ui->textEdit->insertPlainText(buf);
    ui->textEdit->moveCursor(QTextCursor::End);
}


이게 실제 구현부이다. open을 통해 Com port를 열어 주고, BAUDRATE 설정을 통해 통신 속도를 설정해 준다. 그리고 QSocketNotifier로 Message가 오면 setEvent 함수가 동작할 수 있도록 구현하였다. 자세한 내용은 Source를 조금 읽어보면 쉽게 확인할 수 있을것이다.

여기서 중요한 부분은 

struct termios newtio;

이부분인데, 따로 정의하지 않아도 Header File안에 정의되어 있으므로 사용할 수 있다. 이 부분을 설정해주고 사용하여야 정상적인 통신이 가능하다.