Serial 통신
직렬(Serial) 통신은 대게 하나의 신호선을 이용하여 데이터를 주고받는 통신을 일컬어 지칭합니다. 하나의 신호선을 이용하기 대문에 데이터 전송은 일정한 시간 간격으로 전송하게 됩니다. 즉 한 시간 간격 동안에 하나의 논리적인 데이터인 0과 1(High 혹은 Low)을 보내며, 일정한 길이의 데이터를 모두 전송하기 위해서는 다소 시간이 소요됩니다.
그렇지만 시리얼 통신은 적은 수의 신호선을 사용하기 때문에 저렴하게 통신을 할 수 있습니다. 이런 장점 때문에 최근에 대부분의 통신은 직렬 통신으로 데이터를 전송합니다. 시리얼 통신의 적용 예는 USB, PC COM Port 등이 있습니다.
Serial통신하기
아두이노로 읽은 데이터를 자바에서 읽기 위해서 아두이노측에서 무언가 할 필요는 없다.
아두이노는 기본적으로 Serial통신을 지원해주기 때문이다. 중요한 건 자바에서 Serial통신을 해야된다는 건데
자바에서 아두이노와 무언가 연결하는 건 아니다.
자바에서 단순히 USB(Port)를 통해 들어오는 값을 읽을 수 있냐 없냐이다. USB를 통해 들어오는 값은
당연히 아두이노에서 전달된 값이다.
자바에서 'USB(Port)의 값을 읽기 위해서'를 앞으로 'Serial통신하기 위해서'라고 하겠습니다.
자바에서 Serial통신을 위해서는 RxTx라이브러리가 필요합니다.
http://rxtx.qbang.org/wiki/index.php/Download 에서 다운 받을 수 있습니다.
rxtx-2.2pre2-bins.zip을 다운받아 줍니다.
혹시 모르니 파일을 첨부하겠습니다.
압축을 풀면 다음과 같이 구성되어있습니다.
.jar파일을 라이브러리에 추가하면 됩니다. 또 운영체제에 맞는 폴더에 있는 파일들을 한곳에 넣어줍시다.
(저는 linux64bit이고 webContent밑의 abcd폴더에 넣었습니다.)
보통은 lib만 추가하면 되지만 시리얼통신은 그렇지 않은데 그 이유는 native한 소스가 필요하기 때문이다.
즉 순수 자바가아니라 실행 파일이 섞인 자바가 필요하다는것이다. 이를 위해 추가 설정이 필요하다.
프로젝트 우클릭 properties-Java Build Path에 들어가서
해당 라이브러리의 Native libry location을 클릭 후 edit을 눌러줍니다.
그 다음 폴더를 선택하면되는데 만약 워크스페이스내에있다면 Workspace를,
아니라면 External Folder를 선택한다.
그리고 아까 운영체제에 맞는 파일들을 넣었던 abcd 폴더를 선택해줍니다.
이렇게 하면 준비는 끝났다.
저는 Dynamic Web project로 만들어서 했지만 어떤 java프로젝트든 lib추가하고
Java Build Path의 RXTX라이브러리를 선택해 Natvie library location 위치설정을 해주면 된다.
(근데 spring에서 dependecy 추가해서 해봤는데 Native library location 위치 설정해도 적용이 안되더라
-> 그래서 spring에서도 dependecy말고 그냥 lib 따로 등록해줌. 잘 됨)
이제 Java소스코드를 작성하면 된다.
SerialReader
import java.io.IOException;
import java.io.InputStream;
public class SerialReader implements Runnable {
InputStream in;
public SerialReader(InputStream in) {
this.in = in;
}
public void run() {
byte[] buffer = new byte[1024];
int len = -1;
try {
while ((len = this.in.read(buffer)) > -1) {
System.out.print(new String(buffer, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
SerialWriter
import java.io.IOException;
import java.io.OutputStream;
public class SerialWriter implements Runnable {
OutputStream out;
public SerialWriter(OutputStream out) {
this.out = out;
}
public void run() {
try {
int c = 0;
while ((c = System.in.read()) > -1) {
this.out.write(c);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Serial
import java.io.InputStream;
import java.io.OutputStream;
import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
public class Serial {
public Serial() {
super();
}
void connect(String portName) throws Exception {
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
if (portIdentifier.isCurrentlyOwned()) {
System.out.println("Error: Port is currently in use");
} else {
CommPort commPort = portIdentifier.open(this.getClass().getName(), 2000);
if (commPort instanceof SerialPort) {
SerialPort serialPort = (SerialPort) commPort;
serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
InputStream in = serialPort.getInputStream();
OutputStream out = serialPort.getOutputStream();
(new Thread(new SerialReader(in))).start(); //실제로 읽기 시작하는 거.
(new Thread(new SerialWriter(out))).start(); //콘솔에 입력한 값을 Serial로 보내는 거
} else {
System.out.println("Error: Only serial ports are handled by this example.");
}
}
}
}
Main
public class Main {
public static void main(String[] args) {
try {
(new Serial()).connect("/dev/ttyUSB0");
//포트번호는 아두이노에 툴에서 확인하면된다.
} catch (Exception e) {
e.printStackTrace();
}
}
}
아두이노
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.write("hello"); //콘솔에 hello라는 메세지를 보냄
delay(500); //0.5초마다 보내자
}
업로드 후 자바의 메인메소드를 실행시키면 hello가 0.5초마다 추가 되는걸 볼 수 있다.