1. AVR128DB48 UART 모듈 개요
Microchip의 AVR128DB48 마이크로컨트롤러는 여러 개의 USART(Universal Synchronous/Asynchronous Receiver/Transmitter) 모듈을 제공하여 직렬 통신을 지원합니다. UART는 센서 데이터 전송, 디버깅, 외부 장치와의 통신 등 다양한 애플리케이션에 적합합니다. 이 문서에서는 AVR128DB48의 UART 설정 방법, Bitfield 구조를 활용한 레지스터 설정, 그리고 실용적인 예제 코드를 제공하여 초보자와 숙련된 개발자 모두 쉽게 활용할 수 있도록 돕습니다.
주요 사양 (AVR128DB48)
- USART 모듈: 5개 (USART0, USART1, USART2, USART3, USART4)
- AVR128DB48 전용: USART0~4 지원. 데이터시트 Table 1-1 확인.
- 지원 기능:
- 비동기/동기 UART 통신
- 보드레이트: 300bps ~ 6Mbps (24MHz 클럭 기준, 비동기 모드)
- 데이터시트(Section 35.3.2)에서 비동기 모드 최대 보드레이트는 f_CLK/4 (24MHz/4 = 6Mbps).
- 데이터 비트: 5~9비트
- 패리티: None, Even, Odd
- 정지 비트: 1 또는 2비트
- 주요 레지스터:
- USARTn.CTRLA: 제어 레지스터 A (인터럽트 설정)
- USARTn.CTRLB: 제어 레지스터 B (송신/수신 활성화)
- USARTn.CTRLC: 제어 레지스터 C (프레임 형식)
- USARTn.BAUD: 보드레이트 설정
- USARTn.TXDATAL: 송신 데이터
- USARTn.RXDATAL: 수신 데이터
- USARTn.STATUS: 상태 플래그
- USARTn.CTRLD: 제어 레지스터 D (스타트 프레임 감지, 멀티프로세서 모드 등)
- 데이터시트(Section 35.6.4)에서 CTRLD는 스타트 프레임 감지 및 특정 기능 설정에 사용.
- 인터럽트:
- 수신 완료(RXC)
- 송신 완료(TXC)
- 데이터 레지스터 비움(DRE)
- 스타트 프레임 감지(SSF), 수신 시작(ISF)
- 데이터시트(Section 35.4)에서 SSF와 ISF 인터럽트 지원.
- 전력 관리: 대기 모드(Standby) 및 전원 절약 모드(Power-Down)에서 동작 가능, CLKCTRL.RUNSTDBY_bm 설정 필요
- 데이터시트(Section 35.3.8)에서 저전력 모드 동작 명확화.
- 전압 레벨: 1.8V~5.5V 동작 지원
- 데이터시트(Section 42.3)에서 VDD 범위 1.8V~5.5V로 정확.
- 포트 정보 (AVR128DB48, VQFN48/TQFP48 패키지):
- 데이터시트 Table 2-2 기반, USART 관련 핀만 추출. 기본 및 대체 핀 모두 포함. (대체 핀은 PORTMUX.USARTn 설정 필요)
- USART0:
- 기본: PA0 (TxD, Pin 44), PA1 (RxD, Pin 45), PA2 (XCK, Pin 46), PA3 (XDIR, Pin 47)
- 대체: PA4 (TxD, Pin 48), PA5 (RxD, Pin 1), PA6 (XCK, Pin 2), PA7 (XDIR, Pin 3)
- USART1:
- 기본: PC0 (TxD, Pin 10), PC1 (RxD, Pin 11), PC2 (XCK, Pin 12), PC3 (XDIR, Pin 13)
- 대체: PC4 (TxD, Pin 16), PC5 (RxD, Pin 17), PC6 (XCK, Pin 18), PC7 (XDIR, Pin 19)
- USART2:
- 기본: PF0 (TxD, Pin 34), PF1 (RxD, Pin 35), PF2 (XCK, Pin 36), PF3 (XDIR, Pin 37)
- 대체: PF4 (TxD, Pin 38), PF5 (RxD, Pin 39)
- USART3:
- 기본: PB0 (TxD, Pin 4), PB1 (RxD, Pin 5), PB2 (XCK, Pin 6), PB3 (XDIR, Pin 7)
- 대체: PB4 (TxD, Pin 8), PB5 (RxD, Pin 9), PB6 (XCK, Pin 2), PB7 (XDIR, Pin 3)
- USART4:
- 기본: PE0 (TxD, Pin 30), PE1 (RxD, Pin 31), PE2 (XCK, Pin 32), PE3 (XDIR, Pin 33)
- 참고: 대체 핀은 PORTMUX.USARTn = PORTMUX_USARTn_ALT1_gc 등으로 설정. Curiosity Nano 보드에서 USART3(PB0/PB1)이 EDBG USB-UART에 연결됨.
2. UART Bitfield 설정
AVR128DB48의 UART 레지스터는 Bitfield 구조로 정의되어 있으며, <avr/io.h> 헤더 파일을 통해 접근합니다. 주요 레지스터는 다음과 같습니다:
2.1 USARTn.CTRLA (제어 레지스터 A)
- bit.RXCIE: 수신 완료 인터럽트 활성화 (1: 활성화)
- bit.TXCIE: 송신 완료 인터럽트 활성화 (1: 활성화)
- bit.DREIE: 데이터 레지스터 비움 인터럽트 활성화 (1: 활성화)
2.2 USARTn.CTRLB (제어 레지스터 B)
- bit.TXEN: 송신기 활성화 (1: 활성화)
- bit.RXEN: 수신기 활성화 (1: 활성화)
- bit.RXMODE: 수신 모드 (0: 일반, 1: CLK2x, 2: GENAUTO, 3: LIN)
2.3 USARTn.CTRLC (제어 레지스터 C)
- bit.CMODE: 통신 모드 (0: 비동기, 1: 동기)
- bit.PMODE: 패리티 모드 (0: 없음, 2: Even, 3: Odd)
- bit.SBMODE: 정지 비트 (0: 1비트, 1: 2비트)
- bit.CHSIZE: 문자 크기 (0: 8비트, 1: 7비트, 2: 6비트, 3: 5비트, 7: 9비트)
2.4 USARTn.BAUD (보드레이트 레지스터)
- 16비트 레지스터로 보드레이트 설정
- 공식: BAUD = (64 * F_PER) / (S * Baudrate)
- F_PER: 시스템 클럭 주파수 (예: 24MHz)
- S: 샘플링 수 (비동기 일반: 16, CLK2x: 8)
2.5 USARTn.STATUS (상태 레지스터)
- bit.RXCIF: 수신 완료 플래그
- bit.TXCIF: 송신 완료 플래그
- bit.DREIF: 데이터 레지스터 비움 플래그
3. UART 설정 절차
- 시스템 초기화:
- set_system_clock()로 시스템 클럭 설정 (24MHz, XOSC32K 오토튜닝)
- 인터럽트 비활성화 (cli())
- 포트 설정:
- TXD 핀 출력, RXD 핀 입력 설정 (예: PORTA.PIN0: TXD, PORTA.PIN1: RXD for USART0)
- 보드레이트 설정:
- USARTn.BAUD 레지스터에 계산된 값 설정
- 프레임 형식 설정:
- USARTn.CTRLC로 데이터 비트, 패리티, 정지 비트 설정
- 송신/수신 활성화:
- USARTn.CTRLB로 TXEN, RXEN 설정
- 인터럽트 설정 (필요 시):
- USARTn.CTRLA로 RXCIE, TXCIE, DREIE 설정
- UART 실행:
- 설정 후 즉시 동작
4. UART 설정 고려사항
- 클럭 설정: 시스템 클럭(24MHz) 및 XOSC32K 안정화 확인
- 보드레이트: 정확한 BAUD 값 계산 (오차율 2% 이내 권장)
- 인터럽트: 다중 인터럽트 사용 시 우선순위 주의
- 저전력: 불필요한 송신/수신 비활성화로 전력 소모 감소
- 핀 멀티플렉싱: UART 핀과 다른 주변 장치 충돌 주의 (예: SPI, TWI)
5. 실용적인 UART 예제 코드 (Bitfield 구조)
아래는 AVR128DB48 UART를 Bitfield 구조로 설정한 3개의 예제 코드입니다. 각 예제는 Atmel Studio 또는 MPLAB X IDE와 AVR-GCC 환경에서 실행 가능합니다.
5.1 예제 1: 기본 UART 송신 (문자열 전송)
// File: uart_basic_tx.c
// Description: AVR128DB48 UART 기본 송신 예제 (문자열 전송)
// Compiler: AVR-GCC
// Target: AVR128DB48
#ifndef F_CPU
#define F_CPU 24000000UL // 시스템 클록 주파수 (24 MHz, delay.h용)
#endif
#define BAUD_RATE 9600 // 보드레이트 9600bps
#define BAUD_VALUE (((F_CPU * 64UL) / (16UL * BAUD_RATE)) - 1) // BAUD 레지스터 값 (9999, 오류 0%)
#include <avr/io.h> // AVR 입출력 관련 헤더 파일
#include <util/delay.h> // 지연 함수 관련 헤더 파일
void set_system_clock(void) {
// 32.768 kHz 외부 크리스털 오실레이터(XOSC32K) 활성화
_PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm);
// XOSC32K 안정화 대기 (타임아웃 약 1초)
uint32_t timeout = 24000000UL;
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm) && timeout--) {
;
}
if (timeout == 0) {
return; // 타임아웃 시 기본 클록으로 폴백
}
// 내부 OSCHF를 24 MHz로 설정, XOSC32K 오토튜닝 활성화
_PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_24M_gc | CLKCTRL_AUTOTUNE_bm);
// 시스템 클록 소스를 OSCHF로 설정
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
// 클록 프리스케일러 비활성화 (24 MHz 그대로 사용)
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0x00);
// 시스템 클록 안정화 대기 (타임아웃 약 1초)
timeout = 24000000UL;
while ((CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm) && timeout--) {
;
}
}
void uart_init(void) {
// PA0(TXD0)를 출력으로, PA1(RXD0)를 입력으로 설정
PORTA.DIRSET = PIN0_bm; // PA0(TXD0) 출력
PORTA.DIRCLR = PIN1_bm; // PA1(RXD0) 입력
PORTA.OUTCLR = PIN0_bm; // TXD0 초기 Low (안정성)
// USART0 설정: 9600bps, 8비트 데이터, 패리티 없음, 1 스톱 비트
USART0.BAUD = BAUD_VALUE; // 보드레이트 설정 (9999)
USART0.CTRLC = USART_CMODE_ASYNCHRONOUS_gc | // 비동기 모드
USART_PMODE_DISABLED_gc | // 패리티 없음
USART_SBMODE_1BIT_gc | // 1 스톱 비트
USART_CHSIZE_8BIT_gc; // 8비트 데이터
USART0.CTRLB = USART_TXEN_bm; // 송신기 활성화
}
void uart_transmit(uint8_t data) {
// 데이터 레지스터 비어질 때까지 대기
while (!(USART0.STATUS & USART_DREIF_bm));
USART0.TXDATAL = data; // 데이터 전송
}
void uart_print(const char* str) {
// 문자열을 한 문자씩 전송
while (*str) {
uart_transmit(*str++);
}
}
int main(void) {
set_system_clock(); // 시스템 클록 설정
uart_init(); // UART 초기화
while (1) {
uart_print("Hello, AVR128DB48!\r\n"); // 테스트 메시지 전송
_delay_ms(1000); // 1초 대기
}
return 0; // 도달하지 않음
}
설명:
- 기능: USART0를 통해 "Hello, AVR128DB48!" 문자열을 9600bps로 전송
- 설정: PA0(TXD) 출력, 8비트 데이터, 패리티 없음, 1 정지 비트 (8N1)
- 출력: 시리얼 터미널에서 문자열 출력 확인
5.2 예제 2: UART 수신 (에코)
// File: uart_echo.c
// Description: AVR128DB48 UART 수신 예제 (수신 데이터를 에코)
// Compiler: AVR-GCC
// Target: AVR128DB48
#ifndef F_CPU
#define F_CPU 24000000UL // 시스템 클록 주파수 (24 MHz)
#endif
#define BAUD_RATE 9600 // 보드레이트 9600bps
#define BAUD_VALUE (((F_CPU * 64UL) / (16UL * BAUD_RATE)) - 1) // BAUD 레지스터 값 (9999, 오류 0%)
#include <avr/io.h> // AVR 입출력 관련 헤더 파일
void set_system_clock(void) {
// 32.768 kHz 외부 크리스털 오실레이터(XOSC32K) 활성화
_PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm);
// XOSC32K 안정화 대기 (타임아웃 약 1초)
uint32_t timeout = 24000000UL;
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm) && timeout--) {
;
}
if (timeout == 0) {
return; // 타임아웃 시 기본 클록으로 폴백
}
// 내부 OSCHF를 24 MHz로 설정, XOSC32K 오토튜닝 활성화
_PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_24M_gc | CLKCTRL_AUTOTUNE_bm);
// 시스템 클록 소스를 OSCHF로 설정
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
// 클록 프리스케일러 비활성화 (24 MHz 그대로 사용)
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0x00);
// 시스템 클록 안정화 대기 (타임아웃 약 1초)
timeout = 24000000UL;
while ((CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm) && timeout--) {
;
}
}
void uart_init(void) {
// PA0(TXD0)를 출력으로, PA1(RXD0)를 입력으로 설정
PORTA.DIRSET = PIN0_bm; // PA0(TXD0) 출력
PORTA.DIRCLR = PIN1_bm; // PA1(RXD0) 입력
PORTA.OUTCLR = PIN0_bm; // TXD0 초기 Low (안정성)
// USART0 설정: 9600bps, 8비트 데이터, 패리티 없음, 1 스톱 비트
USART0.BAUD = BAUD_VALUE; // 보드레이트 설정 (9999)
USART0.CTRLC = USART_CMODE_ASYNCHRONOUS_gc | // 비동기 모드
USART_PMODE_DISABLED_gc | // 패리티 없음
USART_SBMODE_1BIT_gc | // 1 스톱 비트
USART_CHSIZE_8BIT_gc; // 8비트 데이터
USART0.CTRLB = USART_TXEN_bm | USART_RXEN_bm; // 송신기 및 수신기 활성화
}
uint8_t uart_receive(void) {
// 수신 완료 플래그 대기
while (!(USART0.STATUS & USART_RXCIF_bm));
// 프레임 오류 확인
if (USART0.STATUS & USART_FERR_bm) {
(void)USART0.RXDATAL; // 오류 데이터 무시
USART0.STATUS = USART_FERR_bm; // 플래그 클리어
return 0; // 유효하지 않은 데이터
}
return USART0.RXDATAL; // 수신 데이터 반환
}
void uart_transmit(uint8_t data) {
// 데이터 레지스터 비어질 때까지 대기
while (!(USART0.STATUS & USART_DREIF_bm));
USART0.TXDATAL = data; // 데이터 전송
}
int main(void) {
set_system_clock(); // 시스템 클록 설정
uart_init(); // UART 초기화
while (1) {
uint8_t data = uart_receive(); // 데이터 수신
if (data) { // 유효한 데이터만 전송
uart_transmit(data); // 수신된 데이터 에코
}
}
return 0; // 도달하지 않음
}
설명:
- 기능: USART0를 통해 수신된 데이터를 다시 송신 (에코)
- 설정: PA0(TXD) 출력, PA1(RXD) 입력, 9600bps, 8N1
- 출력: 시리얼 터미널에서 입력한 문자 에코
5.3 예제 3: UART 인터럽트 기반 수신
// File: uart_interrupt_rx.c
// Description: AVR128DB48 UART 인터럽트 수신 예제 (수신 데이터를 에코)
// Compiler: AVR-GCC
// Target: AVR128DB48
#ifndef F_CPU
#define F_CPU 24000000UL // 시스템 클록 주파수 (24 MHz)
#endif
#define BAUD_RATE 9600 // 보드레이트 9600bps
#define BAUD_VALUE (((F_CPU * 64UL) / (16UL * BAUD_RATE)) - 1) // BAUD 레지스터 값 (9999, 오류 0%)
#include <avr/io.h> // AVR 입출력 관련 헤더 파일
#include <avr/interrupt.h> // 인터럽트 관련 헤더 파일
volatile uint8_t rx_data; // 수신 데이터를 저장하는 전역 변수
void set_system_clock(void) {
// 32.768 kHz 외부 크리스털 오실레이터(XOSC32K) 활성화
_PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm);
// XOSC32K 안정화 대기 (타임아웃 약 1초)
uint32_t timeout = 24000000UL;
while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm) && timeout--) {
;
}
if (timeout == 0) {
return; // 타임아웃 시 기본 클록으로 폴백
}
// 내부 OSCHF를 24 MHz로 설정, XOSC32K 오토튜닝 활성화
_PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_24M_gc | CLKCTRL_AUTOTUNE_bm);
// 시스템 클록 소스를 OSCHF로 설정
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
// 클록 프리스케일러 비활성화 (24 MHz 그대로 사용)
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0x00);
// 시스템 클록 안정화 대기 (타임아웃 약 1초)
timeout = 24000000UL;
while ((CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm) && timeout--) {
;
}
}
void uart_init(void) {
// PA0(TXD0)를 출력으로, PA1(RXD0)를 입력으로 설정
PORTA.DIRSET = PIN0_bm; // PA0(TXD0) 출력
PORTA.DIRCLR = PIN1_bm; // PA1(RXD0) 입력
PORTA.OUTCLR = PIN0_bm; // TXD0 초기 Low (안정성)
// USART0 설정: 9600bps, 8비트 데이터, 패리티 없음, 1 스톱 비트
USART0.BAUD = BAUD_VALUE; // 보드레이트 설정 (9999)
USART0.CTRLC = USART_CMODE_ASYNCHRONOUS_gc | // 비동기 모드
USART_PMODE_DISABLED_gc | // 패리티 없음
USART_SBMODE_1BIT_gc | // 1 스톱 비트
USART_CHSIZE_8BIT_gc; // 8비트 데이터
USART0.CTRLB = USART_TXEN_bm | USART_RXEN_bm; // 송신기 및 수신기 활성화
USART0.CTRLA = USART_RXCIE_bm; // 수신 완료 인터럽트 활성화
}
void uart_transmit(uint8_t data) {
// 데이터 레지스터 비어질 때까지 대기
while (!(USART0.STATUS & USART_DREIF_bm));
USART0.TXDATAL = data; // 데이터 전송
}
ISR(USART0_RXC_vect) {
// 프레임 오류 확인
if (USART0.STATUS & USART_FERR_bm) {
(void)USART0.RXDATAL; // 오류 데이터 무시
USART0.STATUS = USART_FERR_bm; // 플래그 클리어
return;
}
rx_data = USART0.RXDATAL; // 수신 데이터 저장
uart_transmit(rx_data); // 수신 데이터 에코
}
int main(void) {
set_system_clock(); // 시스템 클록 설정
uart_init(); // UART 초기화
sei(); // 글로벌 인터럽트 활성화
while (1) {
// 인터럽트로 처리
}
return 0; // 도달하지 않음
}
설명:
- 기능: USART0를 통해 인터럽트 기반으로 데이터 수신 및 에코
- 설정: PA0(TXD) 출력, PA1(RXD) 입력, 9600bps, 8N1, 수신 인터럽트 활성화
- 출력: 시리얼 터미널에서 입력한 문자 에코
6. 사용 방법
6.1 환경 설정
- AVR-GCC 설치: Atmel Studio 또는 MPLAB X IDE에 AVR-GCC 툴체인 설치
- 헤더 파일: <avr/io.h>, <avr/interrupt.h>, <util/delay.h> 포함
- 프로젝트 설정: AVR128DB48 타겟으로 프로젝트 생성
- 클럭 정의: #define F_CPU 24000000UL로 시스템 클럭 설정
6.2 코드 실행
- 각 예제를 별도의 .c 파일로 저장하거나, main.c에 복사
- 다른 예제 코드 주석 처리
- Atmel Studio/MPLAB X IDE에서 빌드 및 플래싱
6.3 하드웨어 준비
- UART 연결: PA0(TXD) 및 PA1(RXD)에 시리얼 어댑터(예: USB-to-Serial) 연결
- 전원: 1.8V~5.5V 전원 공급
- 시리얼 터미널: PuTTY, Tera Term 등으로 9600bps, 8N1 설정
6.4 디버깅
- Atmel Studio/MPLAB X IDE의 디버거 사용
- USARTn.STATUS 레지스터 확인 (RXCIF, TXCIF, DREIF)
- 시리얼 터미널로 송수신 데이터 점검
7. 추가 팁
- 보드레이트 오차: BAUD_VALUE 계산 시 오차율 2% 이내 유지
- 노이즈 감소: RXD 핀에 풀업 저항 사용 권장
- Microchip 리소스: AVR128DB48 데이터시트, Application Notes, AVR-GCC 예제
- 문제 해결:
- 데이터 전송 없음: TXD 핀과 USARTn.CTRLB.TXEN 확인
- 수신 오류: RXD 핀과 보드레이트 설정 확인
- 인터럽트 실패: USARTn.CTRLA와 인터럽트 플래그 확인
- 커뮤니티: Microchip Community, AVR Freaks 포럼 참고
8. 결론
이 문서는 AVR128DB48 UART 모듈의 설정 방법과 Bitfield 구조를 활용한 예제 코드를 제공하여 직렬 통신 애플리케이션에 적용 가능하도록 구성했습니다. 초보자는 기본 송신 예제부터 시작하고, 숙련자는 인터럽트 기반 수신 예제를 활용하여 복잡한 통신 시스템을 구현할 수 있습니다.
키워드: AVR128DB48, UART, USART, 마이크로컨트롤러, Atmel Studio, MPLAB X IDE, 직렬 통신, 보드레이트, 인터럽트, 8N1
'MCU > AVR' 카테고리의 다른 글
AVR128DB48 Event System 사용 방법 및 예제 코드(수정) (0) | 2025.08.20 |
---|---|
AVR128DB48 Watchdog 사용 방법 및 예제 코드 (0) | 2025.08.19 |
AVR128DB48 SPI 사용 방법 및 예제 코드 (0) | 2025.08.19 |
AVR128DB48 I2C 사용 방법 및 예제 코드(수정) (0) | 2025.08.19 |
AVR128DB48 GPIO 사용 방법 및 예제 코드 (0) | 2025.08.18 |
AVR128DB48 Microchip Studio 프로젝트 생성 절차 및 기본 프로그램 작성(수정) (1) | 2025.08.18 |
AVR128DA48 Modbus ASCII 슬레이브 구현 (1) | 2025.08.16 |
AVR128DA48 I2C Bit-bang을 STM32 HAL API 스타일로 코드 구현 (1) | 2025.08.05 |