ATmega328PB 사용 (3) PWM으로 LED를 켜기

처음에



LED 조광에 PWM을 사용하므로 테스트 프로그램으로 동작 확인해 봅니다.

PWM 모드



ATMega328PB 타이머의 동작 모드에는 표준(Normal), 위상 보정 PWM(PWM,PhaseCorrect), CTC, 고속 PWM(Fast PWM) 모드가 있습니다.
TC0이면 동작 모드나 TOP값 등의 조합으로 아래 표와 같은 모드를 선택할 수 있습니다.

LED 조광을 위해 고속 PWM에서 TOP 값 0xFF의 Mode 3을 설정합니다.
16bit 타이머의 TC1등에서는 9bit, 10bit도 선택할 수 있습니다만. 모두 8bit로 하고 있습니다.
클록은 8MHz의 256분주로 했다. PWM의주기는 약 8.2ms입니다.

PWM 배치



PWM0~3을 추가합니다. 다만 다른 용도로 사용하는 포트와 부딪치므로 모두 사용할 수 없습니다.
이번 PWM3에 할당한 TC3의 OCA는 다른 포트(UART)와 배팅하므로 OCB만 PWM으로 사용합니다.





구성 요소 설정






TC3/TC4를 PWM 출력으로 사용하는 경우에는 주의가 필요합니다.
TC3/TC4는 Output Compare Modulator에 연결되어 있습니다.
따라서 TC3/TC4를 별도의 PWM 출력으로 사용할 수 없습니다. 또한 Modulator 설정에 PD2를 사용합니다.
TC3을 PWM 출력으로 하려면 PD2를 출력으로 하고 '1'을 설정합니다.


코드



7개의 PWM을 동시에 변화시키는 코드입니다.
PWM의 초기 설정 후, 타이머로 밝기를 변화시키고 있습니다.
#define NUMBER_OF_PWM   (7)

uint16_t PwmTbl[] ={
     0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100,
    90, 80, 70, 60, 50, 40, 30, 20, 10
};

int PwmTblSize;
static uint8_t PwmStage[NUMBER_OF_PWM];
static uint16_t PwmTopVal;

void PWM_0AB_init(void)
{
    // Enable pin output
    PWM_0_enable_output_ch0();
    PWM_0_enable_output_ch1();

    // Set channel 0 duty cycle value register value to specified value
    PWM_0_load_duty_cycle_ch0(0x3f);
    PWM_0_load_duty_cycle_ch1(0x3f);

    // Set counter register value
    PWM_0_load_counter(0);
}

void PWM_1AB_init(void)
{
    // Enable pin output
    PWM_1_enable_output_ch0();
    PWM_1_enable_output_ch1();

    // Set channel 0 duty cycle value register value to specified value
    PWM_1_load_duty_cycle_ch0(0x3f);
    PWM_1_load_duty_cycle_ch1(0x3f);

    // Set counter register value
    PWM_1_load_counter(0);
}

void PWM_2AB_init(void)
{
    // Enable pin output
    PWM_2_enable_output_ch0();
    PWM_2_enable_output_ch1();

    // Set channel 0 duty cycle value register value to specified value
    PWM_2_load_duty_cycle_ch0(0x3f);
    PWM_2_load_duty_cycle_ch1(0x3f);

    // Set counter register value
    PWM_2_load_counter(0);
}

void PWM_3AB_init(void)
{
    PWM_3_enable();
    // Enable pin output
    PWM_3_enable_output_ch1();

    // Set channel 0 duty cycle value register value to specified value
    PWM_3_load_duty_cycle_ch1(0x3f);

    // Set counter register value
    PWM_3_load_counter(0);
}


void timerIntr(void)
{
    static unsigned int count = 0;
    uint16_t width[NUMBER_OF_PWM];

    count++;
    if (count >= 400) {
        count = 0;
        for (int i = 0;i < NUMBER_OF_PWM; i++) {
            PwmStage[i]++;
            if (PwmStage[i] >= PwmTblSize) {
                PwmStage[i] = 0;
            }
            width[i] = ((uint16_t)PwmTopVal*(uint16_t)PwmTbl[PwmStage[i]]);
            width[i] /= 100;
        }
        PWM_0_load_duty_cycle_ch0((PWM_0_register_t)width[0]);
        PWM_0_load_duty_cycle_ch1((PWM_0_register_t)width[1]);
        PWM_1_load_duty_cycle_ch0((PWM_1_register_t)width[2]);
        PWM_1_load_duty_cycle_ch1((PWM_1_register_t)width[3]);
        PWM_2_load_duty_cycle_ch0((PWM_2_register_t)width[4]);
        PWM_2_load_duty_cycle_ch1((PWM_2_register_t)width[5]);
        PWM_3_load_duty_cycle_ch1((PWM_3_register_t)width[6]);
    }
}
int main(void)
{
    /* Initializes MCU, drivers and middleware */
    atmel_start_init();
    PwmTblSize = sizeof(PwmTbl)/sizeof(uint16_t);

    PwmTopVal = 0xff;

    PwmStage[0] = 0;
    PwmStage[1] = 0;
    PwmStage[2] = 0;
    PwmStage[3] = 0;
    PwmStage[4] = 0;
    PwmStage[5] = 0;
    PwmStage[6] = 0;

    PWM_0AB_init();
    PWM_1AB_init();
    PWM_2AB_init();
    PWM_3AB_init();

    /* Replace with your application code */
    while (1) {
        ;
    }
}

내용에 미비 등이 있으면 연락 부탁드립니다.

좋은 웹페이지 즐겨찾기