그래픽 & 멀티미디어
이번 시간에는 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()같은 멤버함수를 사용할 수 있어 편리합니다.
프로그램 코딩 시작
역시 작업 순서대로 글을 올리겠습니다.
- 프로제트 파일 생성, "C++ Project"를 선택합니다.
- 적당한 프로젝트 이름을 입력합니다.
여기서는 프로젝트 이름을 rs232.pro로 하겠습니다.
- 프로젝트 파일을 저장합니다.
- 폼 이름을 지정합니다. 이 이름이 클래스 이름이 되므로 적당한 이름을 지정해 줍니다. 여기서는 frmMain으로 입력하겠습니다.
- 필요한 위젯을 배치합니다.
- 슬롯을 등록합니다.
onBtnSendClick()은 자료 전송 버튼을 위한 슬롯입니다.
onReceiveFromRs232()는 자료 수신 처리를 위한 슬롯입니다.
init()는 폼이 생성된 후에 발생되는 함수입니다.
- 전체 소스에 따라 슬롯함수를 작성합니다.
- 소스코드를 작성한 후에 아래와 같이 버튼의 클릭 시그널에 대해서 슬롯 함수에 연결합니다.
프로그램 완성
main()함수를 위해 main.cpp를 생성하고 컴파일하면 모든 작업이 끝납니다.
프로젝트를 빌드하기 위해서 main.cpp를 생성합니다. File >> New메뉴를 선택합니다. main.cpp를 선택합니다.
frmMain을 선택하고 프로젝트를 빌드합니다.
]# qmake ]# make ]# ./rs232 // 위의 작업 순서 중 2번을 보시면 프로젝트 파일 이름이 rs232.pro입니다.
프로그램 실행
프로그램을 실행합니다. 반대 쪽에서는 jwRsMonitor 또는 기타 시리얼 통신 테스터 프로그램으로 숫자를 전송하십시오. 또한 예제 프로그램에서 전송한 문자열을 수신하여 확인해 보십시오.
.
리눅스를 공부하는 학생입니다...
테스터 프로그램중에 확장자가 exe말고 리눅스에서 바로 실행할 수 있는 프로그램이 있는지 알고 싶습니다...
제 리눅스에서는 exe파일이 실행되지 않네요...ㅠㅠ