이번 시간에는 QT를 이용하여 시리얼 통신 프로그램을 작성해 보겠습니다. 역시 QSocketNotifier를 이용할 것입니다. 혹 QSocketNotifier를 처음 접하시는 분은 QT - QSocketNotifier 글을 먼저 읽어 주시기 바랍니다. 또한 시리얼 통신을 처음 접하시는 분은 시리얼 관련 글을 먼저 읽어 주십시오. ^^

우선 예제 중 소스입니다. 디자인 부분은 나중에 QT Designer에서 처리할 것입니다. 예제는 btnSend(QPushButton)버튼을 클릭하면 edtInput(QLineEdit)에 입력된 문자열을 상대방으로 전송하며,

상대 쪽에서 숫자 정보를 전송하면, 그 숫자에 맞추어 slider의 thumb 위치를 옮기겠습니다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <termios.h>                   // B115200, CS8 등 상수 정의
#include <fcntl.h>                     // O_RDWR , O_NOCTTY 등의 상수 정의
#include <qapplication.h>
#include <qsocketnotifier.h>
#include <qmessagebox.h>

#define  BUFF_SIZE   1024

QSocketNotifier   *notRsRead;

int   fd;
char  buff[BUFF_SIZE+5];

void frmMain::onBtnSendClick()
{
   QString  userInput( edtInput->text());

   if ( 0 > write( fd,  userInput, userInput.length()) )
      QMessageBox::information( this, "rs232", "Sending Error!!");
}

void frmMain::onReceiveFromRs232()
{
   int   szRead;
   int   nThumb;

   szRead = read( fd, buff, BUFF_SIZE);
   buff[szRead] = '\0';
   labReceived->setText( buff);
   nThumb = atoi( buff);
   slider->setValue( nThumb);
}

void frmMain::init()
{
   struct termios newtio;

   fd = open( "/dev/ttyS0", O_RDWR ¦ O_NOCTTY ¦ O_NONBLOCK);   // (2) com1을 open

   memset( &newtio, 0, sizeof(newtio) );
   newtio.c_cflag = B115200;           // (3) 통신 속도 115200
   newtio.c_cflag ¦= CS8;               // (4) 데이터 비트가 8bit
   newtio.c_cflag ¦= CLOCAL ¦ CREAD; // (5) 쓰기는 기본, 읽기도 가능하게
   newtio.c_iflag = IGNPAR;                // (6) 패리티 오류 무시
   newtio.c_oflag = 0;
   newtio.c_lflag = 0;
   newtio.c_cc[VTIME] = 0;
   newtio.c_cc[VMIN] = 1;

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

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

그럼 소스를 부분 별로 차근히 보겠습니다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <termios.h>                   // B115200, CS8 등 상수 정의
#include <fcntl.h>                     // O_RDWR , O_NOCTTY 등의 상수 정의
#include <qapplication.h>
#include <qsocketnotifier.h>
#include <qmessagebox.h>

프로그램에 필요한 헤더 파일들입니다.

#define  BUFF_SIZE   1024

char  buff[BUFF_SIZE+5];

상대 쪽으로부터 전송되어 오는 자료를 수신하기 위한 버퍼입니다.

int   fd;

시리얼 포트를 사용하기 위한 파일 디스크립터입니다.

QSocketNotifier   *notRsRead;

상대쪽에서 전송한 자료가 있는지 항상 확인해야 겠습니다. 이를 위해 select나 poll을 이용해야겠지만 QT에서는 QSocketNotifier를 사용하는 것이 편리합니다. 그래서 QSocketNotifier 객체를 선언했습니다.

void frmMain::init()
{
   struct termios newtio;

   fd = open( "/dev/ttyS0", O_RDWR ¦ O_NOCTTY ¦ O_NONBLOCK);   // (2) com1을 open

   memset( &newtio, 0, sizeof(newtio) );
   newtio.c_cflag = B115200;           // (3) 통신 속도 115200
   newtio.c_cflag ¦= CS8;              // (4) 데이터 비트가 8bit
   newtio.c_cflag ¦= CLOCAL ¦ CREAD;   // (5) 쓰기는 기본, 읽기도 가능하게
   newtio.c_iflag = IGNPAR;            // (6) 패리티 오류 무시
   newtio.c_oflag = 0;
   newtio.c_lflag = 0;
   newtio.c_cc[VTIME] = 0;
   newtio.c_cc[VMIN] = 1;

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

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

폼이 생성되면 자동으로 호출되는 ::init() 함수입니다. 파란 글씨로 출력된 부분은 시리얼 포트를 준비하기 위한 부분이며, 시리얼 통신에서 자주 본 내용입니다.

나머지 붉은 색의 notRsRead 행은 시리얼 포트의 파일 디스크립터엔 fd를 가지고 QSocketNotifier 객체를 생성하고 있으며, 읽기에 대해 onReceiveFromRs232() 슬롯과 연결하고 있습니다.

이제 onReceiveFromRs232() 슬롯을 생성해야 겠습니다.

void frmMain::onReceiveFromRs232()
{
   int   szRead;
   int   nThumb;

   szRead = read( fd, buff, BUFF_SIZE);
   buff[szRead] = '\0';          // 수신 자료 뒤에 NULL을 추가합니다.
   labReceived->setText( buff);  // 수신 자료를 QLabel에 출력하고
   nThumb = atoi( buff);         // 숫자로 변환하여
   slider->setValue( nThumb);    // 슬라이드의 thumb 위치를 변경합니다.
}

상대방의 문자열을 숫자로 변경하고 slider( QSlider )의 썸브 위치를 변경하고 있습니다.

void frmMain::onBtnSendClick()
{
   QString  userInput( edtInput->text());

   if ( 0 > write( fd,  userInput, userInput.length()) )
      QMessageBox::information( this, "rs232", "Sending Error!!");
}

자료 전송은 수신보다 간단합니다. btnSend(QPushButton)을 클릭하면 edtInput(QLineEdit) 에 입력된 내용을 전송합니다. QString 객체를 이용하면 length()같은 멤버함수를 사용할 수 있어 편리합니다.

프로그램 코딩 시작

역시 작업 순서대로 글을 올리겠습니다.

  1. 프로제트 파일 생성, "C++ Project"를 선택합니다.


  2. 적당한 프로젝트 이름을 입력합니다.
    여기서는 프로젝트 이름을 rs232.pro로 하겠습니다.


  3. 프로젝트 파일을 저장합니다.


  4. 폼 이름을 지정합니다. 이 이름이 클래스 이름이 되므로 적당한 이름을 지정해 줍니다. 여기서는 frmMain으로 입력하겠습니다.


  5. 필요한 위젯을 배치합니다.


  6. 슬롯을 등록합니다.
    onBtnSendClick()은 자료 전송 버튼을 위한 슬롯입니다.
    onReceiveFromRs232()는 자료 수신 처리를 위한 슬롯입니다.
    init()는 폼이 생성된 후에 발생되는 함수입니다.


  7. 전체 소스에 따라 슬롯함수를 작성합니다.

  8. 소스코드를 작성한 후에 아래와 같이 버튼의 클릭 시그널에 대해서 슬롯 함수에 연결합니다.

프로그램 완성

main()함수를 위해 main.cpp를 생성하고 컴파일하면 모든 작업이 끝납니다.

프로젝트를 빌드하기 위해서 main.cpp를 생성합니다. File >> New메뉴를 선택합니다. main.cpp를 선택합니다.

frmMain을 선택하고 프로젝트를 빌드합니다.

]# qmake
]# make
]# ./rs232       // 위의 작업 순서 중 2번을 보시면 프로젝트 파일 이름이 rs232.pro입니다.

프로그램 실행

프로그램을 실행합니다. 반대 쪽에서는 jwRsMonitor 또는 기타 시리얼 통신 테스터 프로그램으로 숫자를 전송하십시오. 또한 예제 프로그램에서 전송한 문자열을 수신하여 확인해 보십시오.

.