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 |