LoginSignup
0
0

More than 3 years have passed since last update.

ATmega328PBを使う (3) PWMでLEDを点ける

Posted at

初めに

LED調光にPWMを使いますので、テストプログラムで動作確認してみます。

PWMモード

ATMega328PBタイマーの動作モードには、標準(Normal)、位相補正PWM(PWM,PhaseCorrect)、CTC、高速PWM(Fast PWM)モードがあります。
TC0であれば、動作モードやTOP値などの組み合わせで下表のようなモードを選べます。
V04.png
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として使います。

v01.png

V05.png

コンポーネントの設定

V02.png
V03.png

TC3/TC4をPWM出力として使う場合は注意が必要です。
TC3/TC4はOutput Compare Modulatorに接続されています。
そのためTC3/TC4を別々のPWM出力として使えません。またModulatorの設定にPD2を使います。
TC3をPWM出力とするにはPD2を出力とし、’1’を設定します。
V06.png

コード

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) {
        ;
    }
}

内容に不備等ありましたら連絡お願いします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0