본문 바로가기
MCU/AVR

[AVR128DB48] UART 사용 방법 및 예제 코드

by linuxgo 2025. 8. 19.
반응형

1. AVR128DB48 UART 모듈 개요

Microchip의 AVR128DB48 마이크로컨트롤러는 여러 개의 USART(Universal Synchronous/Asynchronous Receiver/Transmitter) 모듈을 제공하여 직렬 통신을 지원합니다. UART는 센서 데이터 전송, 디버깅, 외부 장치와의 통신 등 다양한 애플리케이션에 적합합니다. 이 문서에서는 AVR128DB48의 UART 설정 방법, Bitfield 구조를 활용한 레지스터 설정, 그리고 실용적인 예제 코드를 제공하여 초보자와 숙련된 개발자 모두 쉽게 활용할 수 있도록 돕습니다.

주요 사양

  • USART 모듈: 최대 4개 (USART0, USART1, USART2, USART3)
  • 지원 기능:
    •    비동기/동기 UART 통신
    •    보드레이트: 300bps ~ 2Mbps (24MHz 클럭 기준)
    •    데이터 비트: 5~9비트
    •    패리티: None, Even, Odd
    •    정지 비트: 1 또는 2비트
  • 주요 레지스터:
    •    USARTn.CTRLA: 제어 레지스터 A (인터럽트 설정)
    •    USARTn.CTRLB: 제어 레지스터 B (송신/수신 활성화)
    •    USARTn.CTRLC: 제어 레지스터 C (프레임 형식)
    •    USARTn.BAUD: 보드레이트 설정
    •    USARTn.TXDATAL: 송신 데이터
    •    USARTn.RXDATAL: 수신 데이터
    •    USARTn.STATUS: 상태 플래그
  • 인터럽트: 수신 완료(RXC), 송신 완료(TXC), 데이터 레지스터 비움(DRE)
  • 전력 관리: 저전력 모드 지원
  • 전압 레벨: 1.8V~5.5V 동작 지원

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 설정 절차

  1. 시스템 초기화:
    •    set_system_clock()로 시스템 클럭 설정 (24MHz, XOSC32K 오토튜닝)
    •    인터럽트 비활성화 (cli())
  2. 포트 설정:
    •    TXD 핀 출력, RXD 핀 입력 설정 (예: PORTA.PIN0: TXD, PORTA.PIN1: RXD for USART0)
  3. 보드레이트 설정:
    •    USARTn.BAUD 레지스터에 계산된 값 설정
  4. 프레임 형식 설정:
    •    USARTn.CTRLC로 데이터 비트, 패리티, 정지 비트 설정
  5. 송신/수신 활성화:
    •    USARTn.CTRLB로 TXEN, RXEN 설정
  6. 인터럽트 설정 (필요 시):
    •    USARTn.CTRLA로 RXCIE, TXCIE, DREIE 설정
  7. 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

#include <avr/io.h>        // AVR 입출력 관련 헤더 파일
#include <util/delay.h>    // 지연 함수 관련 헤더 파일

#define F_CPU 24000000UL  // 시스템 클록 주파수를 24 MHz로 정의
#define BAUD_RATE 9600    // 보드레이트 9600bps
#define BAUD_VALUE ((64 * F_CPU) / (16 * BAUD_RATE)) // BAUD 레지스터 값 계산

void set_system_clock(void) {
    _PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm);
    while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm));
    _PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_24M_gc | CLKCTRL_AUTOTUNE_bm);
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0x00);
}

void uart_init(void) {
    // PA0(TXD), PA1(RXD) 설정 (USART0)
    PORTA.DIRSET = PIN0_bm; // PA0(TXD)을 출력으로 설정
    PORTA.DIRCLR = PIN1_bm; // PA1(RXD)을 입력으로 설정

    // USART0 설정
    USART0.BAUD = BAUD_VALUE; // 보드레이트 설정 (9600bps)
    USART0.CTRLC = USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | USART_SBMODE_1BIT_gc | USART_CHSIZE_8BIT_gc; // 8N1
    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

#include <avr/io.h>        // AVR 입출력 관련 헤더 파일

#define F_CPU 24000000UL  // 시스템 클록 주파수를 24 MHz로 정의
#define BAUD_RATE 9600    // 보드레이트 9600bps
#define BAUD_VALUE ((64 * F_CPU) / (16 * BAUD_RATE)) // BAUD 레지스터 값 계산

void set_system_clock(void) {
    _PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm);
    while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm));
    _PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_24M_gc | CLKCTRL_AUTOTUNE_bm);
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0x00);
}

void uart_init(void) {
    // PA0(TXD), PA1(RXD) 설정 (USART0)
    PORTA.DIRSET = PIN0_bm; // PA0(TXD)을 출력으로 설정
    PORTA.DIRCLR = PIN1_bm; // PA1(RXD)을 입력으로 설정

    // USART0 설정
    USART0.BAUD = BAUD_VALUE; // 보드레이트 설정 (9600bps)
    USART0.CTRLC = USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | USART_SBMODE_1BIT_gc | USART_CHSIZE_8BIT_gc; // 8N1
    USART0.CTRLB = USART_TXEN_bm | USART_RXEN_bm; // 송신기 및 수신기 활성화
}

uint8_t uart_receive(void) {
    while (!(USART0.STATUS & USART_RXCIF_bm)); // 수신 완료 플래그 대기
    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(); // 데이터 수신
        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

#include <avr/io.h>        // AVR 입출력 관련 헤더 파일
#include <avr/interrupt.h> // 인터럽트 관련 헤더 파일

#define F_CPU 24000000UL  // 시스템 클록 주파수를 24 MHz로 정의
#define BAUD_RATE 9600    // 보드레이트 9600bps
#define BAUD_VALUE ((64 * F_CPU) / (16 * BAUD_RATE)) // BAUD 레지스터 값 계산

volatile uint8_t rx_data; // 수신 데이터를 저장하는 전역 변수

void set_system_clock(void) {
    _PROTECTED_WRITE(CLKCTRL.XOSC32KCTRLA, CLKCTRL_ENABLE_bm | CLKCTRL_RUNSTDBY_bm);
    while (!(CLKCTRL.MCLKSTATUS & CLKCTRL_XOSC32KS_bm));
    _PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_24M_gc | CLKCTRL_AUTOTUNE_bm);
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);
    _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0x00);
}

void uart_init(void) {
    // PA0(TXD), PA1(RXD) 설정 (USART0)
    PORTA.DIRSET = PIN0_bm; // PA0(TXD)을 출력으로 설정
    PORTA.DIRCLR = PIN1_bm; // PA1(RXD)을 입력으로 설정

    // USART0 설정
    USART0.BAUD = BAUD_VALUE; // 보드레이트 설정 (9600bps)
    USART0.CTRLC = USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | USART_SBMODE_1BIT_gc | USART_CHSIZE_8BIT_gc; // 8N1
    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) {
    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

반응형