PWM

김준혁·2026년 4월 2일

8bit FastPWM mode 예시 코드

#ifndef F_CPU
#define F_CPU 16000000UL 
#endif

#include <avr/io.h>
#include <util/delay.h>
#include "UART0.h" // 제공해주신 헤더 포함

void Timer0_FastPWM_Init(void) {
    DDRD |= (1 << DDD6); //6번핀 출력 설정
    TCCR0A = (1 << COM0A1) | (1 << WGM01) | (1 << WGM00); // 비반전 모드, Fast PWM 모드
    TCCR0B = (1 << CS02); // 분주비 256으로 설정
    OCR0A = 0; // 처음 LED밝기=0
}

int main(void) {
    Timer0_FastPWM_Init();
    UART0_init();
    
    int16_t brightness = 0;
    int8_t fadeAmount = 1;

    while (1) {
        OCR0A = (uint8_t)brightness; // PWM 듀티비 업데이트

        // 🔥 10단계마다 한 번씩만 시리얼 출력 (나머지 연산 % 활용)
        if (brightness % 10 == 0) {
            UART0_print_string("Brightness: ");
            UART0_print_1_byte_number((uint8_t)brightness);
            UART0_print_string("\r\n");
        }

        brightness += fadeAmount;
        if (brightness <= 0 || brightness >= 255) { // 0이나 255까지 가면 반대로
            fadeAmount = -fadeAmount;
            
            // 방향 전환 시에는 확실히 표시
            UART0_print_string(fadeAmount > 0 ? ">> UP\r\n" : "<< DOWN\r\n");
        }

        _delay_ms(10); 
    }
}

uart는 기존 코드들을 사용했고, serial monitor에 너무 빠르게 찍혀 자꾸 먹통이 됐다.
따라서 10단위로 출력되도록 해줬다.
9,10번 핀은 timer1번에 해당된다. timer0은 6번(PD6)핀을 사용해야 한다.

timer1번 실습 코드

#ifndef F_CPU
#define F_CPU 16000000UL // 시스템 클럭 정의 (16MHz)
#endif

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

// 1. Timer1 PWM 초기화 함수
void Timer1_PWM_Breathing_Init(void) {
    // 1-1. 출력 핀 설정: PB1 (OC1A)
    DDRB |= (1 << PB1); 

    // 1-2. TCCR1A 레지스터 설정
    // - COM1A1 = 1: 비교 일치 시 OC1A 핀을 LOW로, BOTTOM 도달 시 HIGH로 (비반전 모드)
    // - WGM11 = 1, WGM10 = 1: 위상 교정 PWM 모드 (10비트 해상도, TOP = 0x03FF)
    TCCR1A = (1 << COM1A1) | (1 << WGM11) | (1 << WGM10);

    // 1-3. TCCR1B 레지스터 설정
    // - WGM13 = 0, WGM12 = 0: 위상 교정 PWM 모드 (10비트) 유지
    // - CS11 = 1, CS10 = 1: 프리스케일러 64 설정 (122Hz flicker-free 주파수)
    TCCR1B = (1 << CS11) | (1 << CS10);

    // 1-4. 초기 듀티비 설정: 0% (OCR1A = 0)
    OCR1A = 0;
}

// 2. 메인 함수
int main(void) {
    Timer1_PWM_Breathing_Init(); // PWM 및 핀 초기화

    uint16_t brightness = 0;     // 현재 밝기 값 (OCR1A 대입용, 0~1023)
    int8_t fadeAmount = 1;       // 밝기 변화량 및 방향 (양수: 밝아짐, 음수: 어두워짐)

    while (1) {
        // 2-1. OCR1A 레지스터 업데이트 (듀티비 제어)
        OCR1A = brightness;

        // 2-2. 다음 루프를 위한 밝기 값 계산
        brightness += fadeAmount;

        // 2-3. 밝기 경계값 처리 및 방향 반전
        // 10비트 해상도이므로 TOP 값은 1023 (0x03FF)
        if (brightness <= 0 || brightness >= 1023) {
            fadeAmount = -fadeAmount; // 방향 전환
            
            // 극단적인 값에서의 오버플로/언더플로 방지 및 부드러운 전환을 위한 보정
            if(brightness > 1023) brightness = 1023;
            if(brightness < 0)    brightness = 0;
        }

        // 2-4. 숨쉬기 속도 조절을 위한 미세 지연 (블로킹 방식)
        // 이 지연 값에 따라 숨쉬기 주기가 결정됨 (너무 크면 끊겨 보임)
        _delay_ms(3);
    }
    return 0; // 이 줄에 도달하지 않음
}
profile
임베디드

0개의 댓글