Arduino

아두이노 소프트웨어 시리얼(SoftwareSerial) 통신

기하 2021. 12. 4. 09:41

아두이노를 어느정도 사용할 줄 아는 사람이면

무엇인가를 만들고 싶은 욕구가 당연히 생길 것이다.

그럴 때 많이 사용하는 아두이노 보드들은

아두이노 우노, 아두이노 미니와 같은 크기가 작은 보드들이다.

하지만 기본적으로 블루투스 통신만 사용하더라도

위에서 언급한 보드들에서는 사용하기가 어렵다.

 

그 이유로는 위에서 언급한 아두이노 보드들에는

단 하나의 시리얼 포트만이 존재하기 때문이다.

 

우리가 아두이노 보드를 보면

디지털 0번, 1번 핀에 RX TX라고 적혀있는 것을 본 적이 있을 것이다.

 

이곳이 바로 시리얼 포트다.

하지만 우리가 알기에는 Serial 통신은 11통신으로 하나의 통신만이 가능하다.

 

그럼 이 점을 유념하여 보면

디지털 0번과 1번은 아두이노와 컴퓨터를 연결해주는 통신 통로로 이미 사용되고 있다.

그것은 이미 컴퓨터와 연결이 되어 11 통신을 하고 있다는 뜻이다.

또한 우리가 다른 곳에 사용하지 못한다는 것을 뜻하기도 한다.

물론 코드를 업로드 한 뒤에 연결하여 사용한다면 문제가 없다.

 

여기서 사용하지 못 한다는 것은 디지털 0번, 1번을 다른 용도로 사용하고 있을시에는

아두이노 스케치에서 업로드를 하지 못 하는 경우가 있기 때문이다.

그렇기 때문에 대부분 아두이노를 사용할 때 0번 1번은 잘 사용하지 않는다.

 

이것은 거의 모든 아두이노 보드에서 마찬가지일 것이다.

그럼 다른 기기와의 Serial 통신은 포기해야 하는 것인가.

그렇지 않다.

아두이노에서는 이렇게 Serial 포트가 모자랄 때를 대비하여

기본 라이브러리를 하나 마련해 두고 있다.

그 라이브러리가 바로 'SoftwareSerial'이다.

SoftwareSerial

일반 입출력 데이터 핀을 RX, TX핀으로 동작할 수 있게 해주는 라이브러리로 이를 통해

RX, TX로 작동하게 된 핀을 소프트웨어 시리얼이라고 부른다.

그와 반대로 일반적으로 지정되어 있는 예를 들어 앞에서 설명한 

아두이노 우노의 데이터 핀 0, 1번과 같은 본래 RX, TX 핀을

하드웨어 시리얼이라고 부른다.

그럼 모든 입출력 데이터 핀을 소프트웨어 시리얼로 동작 시킬 수 있느냐 하면 그것은 또 아니다.

소프트웨어 시리얼은 두 개의 핀을 RX와 TX 역할로 지정하여 사용하는데

이때 RX 핀은 보드의 종류에 따라 사용 할 수 있는 핀이 정해져 있다.

 

ATmega328을 사용하는 아두이노 우노의 경우에는 모든 핀이 가능하고

ATmega2560을 사용하는 아두이노 메가의 경우 10~15, 50~53, 62~69 핀을

ATmega32u4를 사용하는 아두이노 레오나르도에서는 8~11, 14~16 핀만을

소프트웨어 시리얼의 'RX'로 사용할 수 있다.

 

이처럼 모두 사용가능한 핀이 다르므로 이 이외의 칩을 사용한다면 꼭 확인하고 사용하자.

이는 SoftwareSerial이 데이터 수신 감지를 위해 인터럽트를 사용하지만

모든 입출력 핀이 인터럽트를 지원하지 않기 때문에 생기는 현상이다.

이렇게 SoftwareSerial을 통해 여러 개의 UART 통신을 사용할 수 있게 되었지만

임의로 늘리는 것이니만큼 한 번에 하나의 UART 시리얼 통신만을 사용할 수 있다는 것을 유의하자.

SoftwareSerial 클래스 또한 많은 맴버 함수들이 정의되어 있다.

하지만 대부분이 Serial 클래스의 맴버 함수와 이름과 기능이 유사하니 앞서

아두이노 기초 포스트(또는 아두이노 I.키트 시리얼 통신 포스트)의 Serial통신을 참고하면 이해하기 쉬울 것이다.

http://blog.naver.com/darknisia/220789153470 )

 
 

 

​먼저 우리가 살펴 볼 함수는 SoftwareSerial name 함수다.

 

SoftwareSerial name(RX, TX, Inverse_logic)

 

SoftwareSerial 클래스의 생성자로 RX, TX 핀을 지정한다.

Inverse_logic은 0V를 논리 1, 5V를 논리 0으로 반전시켜 주는 것으로

반전 로직을 사용하는 주변 장치와의 통신을 위해 사용할 수 있는 것이다.

기본 값은 false.

 

또한 SoftwareSerial을 여러 개를 사용할 때를 위해

SoftwareSerial의 이름을 정할 수도 있다.

name의 위치에 사용하고 싶은 이름을 사용하면 그 이름의 객체가 생성되며

앞으로 그 이름으로 함수들을 사용할 수 있다.

 

name.begin(speed) 

시리얼 통신을 초기화하고 전송속도를 설정하는 함수다.

속도는 Serial.begin 함수와 마찬가지지만

데이터 비트수, 페러티 비트, 정지 비트 등을 지정 할 수 없다.

그렇기 때문에 이 값들은 Serial.begin의 기본 값이 적용된다.

 

name.end() 

시리얼 통신을 종료하는 함수다.

 

name.listen() 

소프트웨어 시리얼 통신의 RX 핀으로 데이터 수신이 올 때까지 대기한다.

여러 소프트웨어 시리얼을 사용하는 경우 앞서 말했듯이

한 번에 하나의 통신만이 가능하므로 반드시 원하는 포트를 수신 대기 생태로 지정해 주어야 한다.

그리고 데이터 수신이 오게 되면 이 함수는 true를 반환하고 대기상태라면 false를 반환한다.

 

name.isListening() 

소프트웨어 시리얼이 수신 대기상태인지 아닌지를 반환하는 함수다.

 

name.overflow() 

소프트웨어 시리얼의 데이터 수신 버퍼에 오버플로가 발생하는지를 확인하는 함수로

만약 발생하면 true를 아니면 false를 반환한다.

이 함수가 호출되면 오버플로는 false로 설정되며

이후 새롭게 오버플로가 발생하기 전까지는 오버플로가 발생하지 않은 상태로 설정된다.

 

name.peek() 

데이터 수신 버퍼의 첫 번째 바이트 데이터를 반환한다.

해당 소프트웨어 시리얼 포트가 수신 대기 상태에 있지 않거나 버퍼가 비어 있는 경우 1을 반환한다.

그렇다고 수신 버퍼에서 데이터를 제거하지는 않는다.

 

name.read() 

데이터 수신 버퍼의 첫 번째 문자를 반환하는 함수로 앞의 peek 함수랑 같은 기능을 가진다.

하지만 name.read() 함수는 수신 버퍼에서 반환한 데이터를 제거한다.

 

name.readBytes(buffer, length) 

이 함수는 지정한 개수만큼 읽어와 버퍼에 저장하는 함수다.

길이가 길거나 정해진 데이터를 수신할 때 유용하다.

만약 지정한 개수만큼 데이터가 수신되지 않을 경우

수신된 개수만큼만 저장하고 그 개수를 반환한다.

Serial.readBytes와 같은 역할을 한다.

 

name.write(character) 

바이트 단위의 데이터를 전송한다.

하지만 Serial 클래스와 달리 바이트 배열을 한 번에 전송하는 기능은 없어

한 번에 하나의 데이터만을 전송할 수 있다.

그렇기 때문에 반환되는 값이 전송한 바이트 수인데 01만이 반환된다.

 

name.available() 

수신 버퍼에 저장되어 있는 데이터의 바이트 수를 반환한다.

만약 소프트웨어 시리얼이 수신 대기 상태에 있지 않거나 버퍼가 비어 있는 경우 0을 반환한다

일반적으로 데이터를 받기를 기다릴 때 if문을 이용하여 많이 사용된다.

 

name.flush() 

수신 데이터 버퍼를 비운다.

 

name.print(value, format)

value를 시리얼 포트로 출력한다.

format은 정수의 경우 출력 형식인 진법을 선택할 수 있게 해주며

실수인 경우에는 소수점 이하 자릿수를 지정할 수 있게 해준다.

만약 format을 지정하지 않고 실수를 사용한다면

소수점 둘째자리까지 출력되게 설정되어 있다.

여기서 value는 여러 형식의 값을 출력할 수 있다.

char, char 배열, Stirng, 정수, 실수 등의 값이 대표적이다.

Serial 클래스의 print 함수와 동일한 기능을 한다.

 

name.println(value, format) 

name.print 함수와 동일하며 다른 점은 문자열 출력 후 한 칸 밑으로 내려간다는 것이다.

쉽게 말하면 글자를 쓰고 엔터키를 누른 것과 같은 기능이고

좀 더 전문적으로 말하면 문자열 출력이후 개행 문자를 추가로 출력했다고 할 수 있다.

Serial 클래스의 println 함수와 동일한 기능을 한다.

 

여기까지가 SofrwareSerial 라이브러리에 포함되어 있는 함수들이고 자주 사용되는 함수들이다.

물론 이중에서도 진짜 자주 사용되는 것은 몇 종류 없다.

 

그럼 이 SoftwareSerial을 가지고 예제 코드를 돌려보자.

참고로 예제코드는 SoftwareSerial을 이용하여 블루투스 통신을 하는 것이다.

이 코드를 참고하여 사용법을 익히자.

 

#include <SoftwareSerial.h>  

// SoftwareSerial(RX, TX) 형식으로 블루투스 모듈과 교차하여 연결
SoftwareSerial BlueToothSerial(A1, A0);

void setup() {
  Serial.begin(9600);          // Serial 통신 초기화
  BlueToothSerial.begin(9600); // 블루투스 통신 초기화(SoftwareSerial 통신 초기화)
}

void loop() {
  // 블루투스 모듈 ➜ 아두이노 ➜ 시리얼 모니터
  if (BlueToothSerial.available()) {           // 데이터 수신 대기
    char receivechar = BlueToothSerial.read(); // 수신 데이터 읽기
    Serial.write(receivechar);                 // 수신 데이터 시리얼모니터로 출력
  }

  // 시리얼 모니터 ➜ 아두이노 ➜ 블루투스 모듈
  if (Serial.available()) {                    // 시리얼 모니터 확인
    char transmitchar = Serial.read();         // 시리얼 모니터 데이터 읽기
    BlueToothSerial.write(transmitchar);       // 블루투스로 데이터 전송
  }
}