ATmega328 - PWM制御
ナビゲーションに移動
検索に移動
概要
PWM (Pulse Width Modulation) 制御は、電力を制御するための手法の1つである。
PWMは、一定の周期でパルスの幅を変化させることにより、平均電力を制御する。
ATmegaマイコンには、ハードウェアタイマ / カウンタを使用して、PWM信号を生成する機能が搭載されている。
PWM制御の主な特徴を、以下に示す。
- デューティサイクル
- PWM信号のデューティサイクルは、パルスの幅と周期の比率である。
- デューティサイクルが大きいほど、平均電力が高くなる。
- 例えば、50%のデューティサイクルは、パルスがオンとオフの時間が等しいことを意味する。
- 周波数
- PWM信号の周波数は、1周期あたりのパルス数のことである。
- 周波数が高いほど、平均電力の変化がスムーズになる。
- ただし、周波数が高すぎると、接続されたデバイスが応答できない場合がある。
- 分解能
- PWMの分解能は、デューティサイクルの調整精度を表す。
- 分解能が高いほど、より細かい電力制御が可能になる。
- ATmegaマイコンのPWM分解能は、通常8ビットまたは16ビットである。
ATmegaマイコンでPWMを生成するには、以下の手順を実行する。
- タイマ / カウンタをPWMモードに設定する。
これには、WGM (Waveform Generation Mode) ビットを適切に設定する必要がある。 - PWM周波数を設定する。
これは、プリスケーラとTOP値 (カウンタの最大値) を調整することで行う。 - デューティサイクルを設定する。
これは、OCR (Output Compare Register) の値を変更することで行う。 - PWM出力ピンを有効にする。
これには、DDRとPORTレジスタを適切に設定する必要がある。
ATmegaマイコンには複数のタイマ / カウンタがあり、それぞれ独立してPWM信号を生成できる。
これにより、複数のデバイスを同時に制御することが可能となる。
また、PWM信号は、LEDの明るさ制御、モータの速度制御、音声の生成等に幅広く使用されている。
LEDの調光制御
タイマ未使用の場合
以下の例では、PB1ピンに接続されたLEDをPWM制御して、徐々に明るく、および、消灯している。
#include <avr/io.h>
#include <util/delay.h>
#define LED_PIN PB1
void init()
{
// PB1ピンを出力に設定して、Timer/Counter1をPWMモードに設定
// PWM周波数は約976[Hz]に設定
DDRB |= (1 << LED_PIN); // PB1を出力に設定
TCCR1A = (1 << COM1A1) | (1 << WGM10); // 非反転PWMモード
TCCR1B = (1 << WGM12) | (1 << CS11); // PWM周波数を約976Hzに設定
}
void main()
{
init();
while (1) {
// LEDを徐々に明るくするため、OCR1Aレジスタの値を0から255まで徐々に増加させる
// 各ステップ間に10[mS]の遅延を入れる
for (int i = 0; i < 255; i++) {
OCR1A = i;
_delay_ms(10);
}
// LEDが最大輝度に達した後、
// OCR1Aレジスタの値を255から0まで徐々に減少させることにより、LEDを徐々に消灯させる
// 同様に、各ステップ間に10[mS]の遅延を入れる
for (int i = 255; i > 0; i--) {
OCR1A = i;
_delay_ms(10);
}
}
}
タイマを使用する場合
以下の例では、Timer/Counter1の比較一致割り込みを使用して、PB1ピンに接続されたLEDをPWM制御して、徐々に明るく、および、消灯している。
タイマ割り込みを使用して、割り込みハンドラでLEDのPWM値を更新することにより、メインループとは独立してLEDを調光制御する。
これにより、他の処理を実行しながらLEDのフェードインおよびフェードアウト効果を実現することができる。
#include <avr/io.h>
#include <avr/interrupt.h>
#define LED_PIN PB1
volatile uint8_t pwmValue = 0;
volatile uint8_t fadeDirection = 1;
// Timer/Counter1の比較一致A割り込みハンドラ
// この割り込みは、Timer/Counter1の値がOCR1Aレジスタの値と一致したときに発生する
// pwmValueの値を更新して、fadeDirectionに応じてLEDの明るさを増減する
ISR(TIMER1_COMPA_vect)
{
OCR1A = pwmValue;
if (fadeDirection == 1) {
pwmValue++;
if (pwmValue == 255) {
fadeDirection = 0;
}
}
else {
pwmValue--;
if (pwmValue == 0) {
fadeDirection = 1;
}
}
}
// PB1ピンを出力に設定して、Timer/Counter1をPWMモードに設定する
// また、OCR1Aレジスタの初期値を0に設定して、Timer/Counter1の比較一致A割り込みを有効にする
void init()
{
DDRB |= (1 << LED_PIN); // PB1を出力に設定
TCCR1A = (1 << COM1A1) | (1 << WGM10); // 非反転PWMモード
TCCR1B = (1 << WGM12) | (1 << CS11); // PWM周波数を約976[Hz]に設定
OCR1A = 0; // 初期PWM値を0に設定
TIMSK1 = (1 << OCIE1A); // Timer/Counter1の比較一致A割り込みを有効化
sei(); // 全体の割り込みを有効化
}
void main()
{
init();
while (1) {
// メインループ処理
// ...略
}
}