임베디드

Arduino UNO 와 Raspberry Pi 통신

Zino. 2025. 8. 27. 16:49

Arduino UNO 와 Raspberry Pi를 USB A to B 케이블로 연결(Arduino : B, Raspberry : A)한 후 시리얼 통신을 구현해보자.

 

라즈베리파이의 USB-Serial 로 아두이노와 텍스트 명령을 주고받으려 한다.

라즈베리파이에서 "ON" 명령을 받으면 아두이노 보드의 내장 LED를 켜고 "OFF" 명령을 받으면 LED를 끄는 프로그램을 작성했다.

 

<라즈베리파이 측 코드>

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <errno.h>
#include <stdlib.h>

static int serial_open(const char* dev) {
    int fd = open(dev, O_RDWR | O_NOCTTY | O_SYNC);
    if (fd < 0) {
        perror("open");
        return -1;
    }

    struct termios tio;
    if (tcgetattr(fd, &tio) != 0) {
        perror("tcgetattr");
        close(fd);
        return -1;
    }

    cfmakeraw(&tio);
    cfsetispeed(&tio, B9600);
    cfsetospeed(&tio, B9600);

    tio.c_cflag = (tio.c_cflag & ~CSIZE) | CS8;  // 8-bit
    tio.c_cflag |= (CLOCAL | CREAD);             // 수신 활성
    tio.c_cflag &= ~(PARENB | PARODD);           // no parity
    tio.c_cflag &= ~CSTOPB;                      // 1 stop
    tio.c_cflag &= ~CRTSCTS;                     // no HW flow

    tio.c_cc[VMIN]  = 0;   // non-blocking read
    tio.c_cc[VTIME] = 10;  // read timeout 1.0s (단위 0.1s)

    if (tcsetattr(fd, TCSANOW, &tio) != 0) {
        perror("tcsetattr");
        close(fd);
        return -1;
    }

    // 아두이노 자동 리셋 고려(포트 오픈 직후 대기)
    sleep(2);
    return fd;
}

static int write_line(int fd, const char* s) {
    size_t len = strlen(s);
    ssize_t n = write(fd, s, len);
    if (n < 0) return -1;
    // 줄바꿈 보장
    if (s[len-1] != '\n') {
        if (write(fd, "\n", 1) < 0) return -1;
    }
    tcdrain(fd);
    return 0;
}

static int read_line(int fd, char* buf, size_t maxlen, int timeout_ms) {
    size_t idx = 0;
    int elapsed = 0;
    const int step_ms = 20;

    while (elapsed < timeout_ms && idx < maxlen - 1) {
        char c;
        int n = read(fd, &c, 1);
        if (n == 1) {
            if (c == '\r') continue;
            if (c == '\n') break;
            buf[idx++] = c;
        } else {
            usleep(step_ms * 1000);
            elapsed += step_ms;
        }
    }
    buf[idx] = '\0';
    return (idx > 0);
}

int main(int argc, char** argv) {
    const char* dev = (argc > 1) ? argv[1] : "/dev/ttyACM0";

    int fd = serial_open(dev);
    if (fd < 0) {
        fprintf(stderr, "Failed to open %s\n", dev);
        return 1;
    }

    char line[64];

    // 테스트: ON → 응답 → 2초 후 OFF → 응답
    printf("Send: ON\n");
    if (write_line(fd, "ON") < 0) { perror("write"); return 1; }
    if (read_line(fd, line, sizeof(line), 2000)) {
        printf("Recv: %s\n", line);
    } else {
        printf("Recv timeout\n");
    }

    sleep(2);

    printf("Send: OFF\n");
    if (write_line(fd, "OFF") < 0) { perror("write"); return 1; }
    if (read_line(fd, line, sizeof(line), 2000)) {
        printf("Recv: %s\n", line);
    } else {
        printf("Recv timeout\n");
    }

    close(fd);
    return 0;
}

 

 

<아두이노 측 코드>

#define F_CPU 16000000UL

#include <avr/io.h>
#include <util/delay.h>
#include <string.h>

// --- UART 설정 (9600 8N1) ---
static void uart_init(uint16_t ubrr) {
    // Baud = F_CPU / (16 * (UBRR + 1)) => UBRR = F_CPU/(16*Baud) - 1
    UBRR0H = (unsigned char)(ubrr >> 8);
    UBRR0L = (unsigned char)(ubrr & 0xFF);
    UCSR0B = (1 << RXEN0) | (1 << TXEN0);                 // RX/TX enable
    UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);               // 8N1
}

static void uart_putc(char c) {
    while (!(UCSR0A & (1 << UDRE0))) ;                    // TX buffer empty 대기
    UDR0 = c;
}

static void uart_print(const char* s) {
    while (*s) uart_putc(*s++);
}

static char uart_getc_blocking(void) {
    while (!(UCSR0A & (1 << RXC0))) ;                     // 수신 대기
    return UDR0;
}

// --- 간단한 라인 입력 (\n까지) ---
static int uart_readline(char* buf, int maxlen) {
    int i = 0;
    while (i < maxlen - 1) {
        char c = uart_getc_blocking();
        if (c == '\r') continue;                          // CR 무시
        buf[i++] = c;
        if (c == '\n') break;                             // LF로 라인 종료
    }
    buf[i] = '\0';
    return i;
}

int main(void) {
    // LED 핀 설정 (PB5: Arduino D13)
    DDRB |= (1 << PB5);

    // UART 9600 설정
    // UBRR = 16000000/(16*9600) - 1 = 103
    uart_init(103);

    // 부팅/자동리셋 직후 준비 메세지
    uart_print("READY\n");

    char line[16];
    for (;;) {
        int n = uart_readline(line, sizeof(line));
        if (n <= 0) continue;

        // 'ON\n' / 'OFF\n' 비교 (대소문자 엄격)
        if (strncmp(line, "ON\n", 3) == 0) {
            PORTB |= (1 << PB5);      // LED ON
            uart_print("OK\n");
        } else if (strncmp(line, "OFF\n", 4) == 0) {
            PORTB &= ~(1 << PB5);     // LED OFF
            uart_print("OK\n");
        } else {
            uart_print("ERR\n");
        }
    }
}

 

'임베디드' 카테고리의 다른 글

RTOS  (0) 2026.04.30
엔코더 모터 (Encoder Motor) 제어  (0) 2025.09.17
[AVR Programming] 아두이노 서보모터 제어  (1) 2025.08.18
I2C 통신 / 센서 주소 찾기  (3) 2025.08.16
아두이노 블루투스 통신 HC-05  (2) 2025.08.14