라즈베리파이와 아두이노 사이에는 SPI, I2C, UART 등 다양한 통신 방법들을 적용할 수 있다. 하지만 아두이노의 입출력 핀 전압이 5V인 반면에 라즈베리파이의 GPIO 입출력 핀 전압은 3.3V이기 때문에 직접적으로 결선할 경우 문제가 발생하게 된다. 따라서 여기서는 가장 간편하게 사용할 수 있는 Serial(UART) 통신을 활용해보자. 


시리얼통신은 라즈베리파이와 아두이노를 USB케이블로 연결하는 것으로 간단하게 구현할 수 있으며 전압에 따른 문제 또한 발생하지 않는다.



1. 아두이노 Idle 설치하기


  $ sudo apt-get install arduino


패키지 설치를 위해 라즈베리파이에 update 명령어를 통해 업데이트 시켜주고 위 명령어를 입력하여 아두이노 패키지를 설치한다. 이때 설치된 패키지는 권한을 아직 가지고 있지 않은 상태이므로 바로 실행시키지 말고 아래 명령어를 입력하여 아두이노 패키지가 시리얼 포트에 엑세스 할 수 있는 권한을 얻도록 한다.


  $ sudo usermod -a -G tty pi

  $ sudo usermod -a -G dialout pi


위 과정을 완료하였다면 아두이노 패키지가 성공적으로 라즈베리파이에 설치되었다. 이제 아두이노를 실행시키고 라즈베리파이에 아두이노를 연결한 후에 포트를 설정하고 ("/dev/ttyACM0" 일 것이다.) blink 예제를 업로드하여 제대로 동작하는지 확인해본다.




2. 시리얼 통신하기


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/*
 Pi_Serial_test.cpp - SerialProtocol library - demo
 Copyright (c) 2014 NicoHood.  All right reserved.
 Program to test serial communication
 
 Compile with:
 sudo gcc -o Pi_Serial_Test.o Pi_Serial_Test.cpp -lwiringPi -DRaspberryPi -pedantic -Wall
 sudo ./Pi_Serial_Test.o
 */
 
// just that the Arduino IDE doesnt compile these files.
#ifdef RaspberryPi 
 
//include system librarys
#include <stdio.h> //for printf
#include <stdint.h> //uint8_t definitions
#include <stdlib.h> //for exit(int);
#include <string.h> //for errno
#include <errno.h> //error output
 
//wiring Pi
#include <wiringPi.h>
#include <wiringSerial.h>
 
// Find Serial device on Raspberry with ~ls /dev/tty*
// ARDUINO_UNO "/dev/ttyACM0"
// FTDI_PROGRAMMER "/dev/ttyUSB0"
// HARDWARE_UART "/dev/ttyAMA0"
char device[]= "/dev/ttyACM0";
// filedescriptor
int fd;
unsigned long baud = 9600;
unsigned long time=0;
 
//prototypes
int main(void);
void loop(void);
void setup(void);
 
void setup(){
 
  printf("%s \n""Raspberry Startup!");
  fflush(stdout);
 
  //get filedescriptor
  if ((fd = serialOpen (device, baud)) < 0){
    fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
    exit(1); //error
  }
 
  //setup GPIO in wiringPi mode
  if (wiringPiSetup () == -1){
    fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;
    exit(1); //error
  }
 
}
 
void loop(){
  // Pong every 3 seconds
  if(millis()-time>=3000){
    serialPuts (fd, "Pong!\n");
    // you can also write data from 0-255
    // 65 is in ASCII 'A'
    serialPutchar (fd, 65);
    time=millis();
  }
 
  // read signal
  if(serialDataAvail (fd)){
    char newChar = serialGetchar (fd);
    printf("%c", newChar);
    fflush(stdout);
  }
 
}
 
// main function for normal c++ programs on Raspberry
int main(){
  setup();
  while(1) loop();
  return 0;
}
 
#endif //#ifdef RaspberryPi
cs

위 코드는 wiringPi 라이브러리를 활용하여 아두이노와 통신할 수 있는 예제 코드이다. 여기서 "/dev/ttyACM0" 부분은 아두이노가 연결된 장치의 포트명을 말하는 것으로 가끔씩 에러가 발생할 경우 ACM1, ACM2 이렇게 순차적으로 증가할 수 있으니 유의하도록 한다. 라즈베리파이의 USB포트 구성 목록을 확인하려면 다음 과 같은 명령어를 입력하면 된다.

  $ dmesg|tail



그럼 이제 위 소스코드를 컴파일한다. 필자는 소스코드의 파일명을 test.c로 하였으며 hello라는 이름으로 컴파일했다. 컴파일할 때는 파일이 저장된 디렉토리로 들어간 후에 하도록 한다.


  $ sudo gcc test.c -o hello -l wiringPi -DRaspberryPi

  $ sudo ./hello


아래는 간단하게 구현한 아두이노 소스코드이며 1초마다 라즈베리파이로 Hello World 문자를 송신할 것이다.


1
2
3
4
5
6
7
8
void setup(){  
  Serial.begin(9600);
 
void loop(){
  Serial.println("Hello World");
  delay(1000);
}
cs


3. 결과 확인


위와 같은 결과가 나오면 성공이다. 여기서 실행된 프로그램을 종료하려면 Ctrl + C를 눌러주면 된다. 만약 종료를 하지 않을경우 터미널을 종료해도 계속해서 프로그램이 동작하며 아두이노를 다시 연결시 ttyACM0 포트는 사용하지 못하기 때문에 테스트 종료시에 유의하도록 한다.