ブレッドボードラジオAVRマイコン入門

BASCOM-AVR パルス幅変調(その1)

 ATtiny2313を使って、パルス幅変調・PWMに関する基礎的な実験をしました。出力波形のデューティ比を変えてLEDの明るさをコントロールするプログラムです。

1. 実験回路

 プログラムのテスト用回路は下記の通りです。ATtiny2313にロータリーエンコーダと赤緑2色LED(カソードコモン)をつなぎます。このページのプログラムはすべてこの回路で実験できます。クロックは内部RC発振(1MHz)です。

 図1

 ブレッドボード上の配線図と試作写真を下に掲げます。

図1b 写真1

2. パルス幅によってLEDの明るさを変えるプログラム

 LEDの明るさが1秒ごとに自動的に変化していくプログラムです。完全に消灯した状態から5段階でだんだん明るくなっていく動作を繰り返します。LEDは赤色の方だけが光ります。

 図2

 明るさの調節はポート出力のデューティ比を変えることで可能になります。上の図のようなイメージです。状態1から状態5は、周期がいずれも5mSですが、デューティ比が違います。デューティー比が大きいほど、つまり「1」レベルになっている時間の割合が大きいほどLEDは明るく光ります。下記のプログラムでは、1秒ごとに状態0から状態5まで変化させることによってLEDの明るさを変えています。状態5になった後はまた状態0に戻って同じことを繰り返します。

 プログラムファイル pwm1a.bas

1 $regfile = "attiny2313.dat" ATtiny2313を使用する。
2 $crystal = 1000000 クロック周波数を1MHzに設定。
3
4 Config Portb = Output ポートBを出力に設定する。
5 Dim N As Byte バイト型変数「N」を使用する。
6 Dim H As Byte バイト型変数「H」を使用する。
7 Dim L As Byte バイト型変数「L」を使用する。
8
9 Do Doループ1の範囲ここから。
10  For H = 0 To 5 Forループ。6回繰り返し。
11  L = 5 - H 「5−H」を「L」とする。
12  N = 1 「N」の初期値を「1」とする。
13  Do Doループ2の範囲ここから。
14   Set Portb.0 PB0の出力を「1」にする。
15   Waitms H 「H」ミリ秒間そのまま。
16   Reset Portb.0 PB0の出力を「0」にする。
17   Waitms L 「L」ミリ秒間そのまま。
18   Incr N 「N」に1を加える。
19  Loop Until N = 200 Doループ2の範囲ここまで。
「N=200」になるまで(200回・1秒間)繰り返し。
20  Next H Forループここまで。10行目へ戻る。
21 Loop Doループ1の範囲ここまで。
22
23 End 終わり。

 2つのDoループとForループが入れ子になっています。内側のDoループ(Doループ2)は5mS周期のパルス波を200回(1秒間)出力するプログラム、Forループはデューティ比を6段階で変えていくプログラムです。外側のDoループ(Doループ1)はこれら全体の動作を繰り返します。

 出力が「1」になっている時間が「H」(mS)、「0」になっている時間が「L」(mS)です。「H」の値はForループによって0から5まで変わります。それにともなって「L」の値は5から0まで変わります。「H=1」のときは「L=4」で、これは上の図の状態1です。「H=2」のときは「L=3」となり、これは状態2にあたります。このようにしてデューティ比が5分の1ずつ大きくなっていきます。

3. ロータリーエンコーダでLEDの明るさを変える

 ロータリーエンコーダのツマミを回すとLEDの明るさが変化するプログラムです。先のプログラムのデューティ比用変数「H」と「L」の値をロータリーエンコーダで操作します。

 プログラムファイル pwm1b.bas

1 $regfile = "attiny2313.dat" ATtiny2313を使用する。
2 $crystal = 1000000 クロック周波数を1MHzに設定。
3
4 Config Portb = Output ポートBを出力に設定する。
5 Config Portd = Input ポートDを入力に設定する。
6 Portd = 127 PD0〜PD6をプルアップする。
7 Config Debounce = 1 デバウンス時間を1ミリ秒とする。
8
9 Declare Sub Encode サブルーチン「Encode」を使用する。
10 Dim H As Integer インテジャー型変数「H」を使用する。
11 Dim L As Byte バイト型変数「L」を使用する。
12 A Alias Pind.2 PD2入力を「A」という名前にする。
13 B Alias Pind.3 PD3入力を「B」という名前にする。
14 H = 3 変数「H」の初期値を「3」とする。
15
16 Do Doループの範囲ここから。
17  Debounce A , 0 , Encode , Sub 「A(Pind.2)=0」になったら、
サブルーチン「Encode」を実行する。
18  L = 5 - H 「5−H」を「L」とする。
19  Set Portb.0 PB0の出力を「1」にする。
20  Waitms H 「H」ミリ秒間そのまま。
21  Reset Portb.0 PB0の出力を「0」にする。
22  Waitms L 「L」ミリ秒間そのまま。
23 Loop Doループの範囲ここまで。
24
25 End メインプログラム終わり。
26
27 Sub Encode サブルーチン「Encode」ここから。
28  If B = 1 Then 条件分岐1。「B(Pind.3)=1」(右回転)ならば、
29   Incr H 変数「H」に1を加える。LEDが明るくなる。
30  Else 「B(Pind.3)=0」(左回転)ならば、
31   Decr H 変数「H」から1を減じる。LEDが暗くなる。
32  End If 条件分岐1ここまで。
33  If H > 5 Then H = 5 条件分岐2。「 H > 5」なら「H=5」とする。
34  If H < 0 Then H = 0 条件分岐3。「 H < 0」なら「H=0」とする。
35 End Sub サブルーチン「Encode」ここまで。

 変数「H」の初期値は「3」なので、LEDは中間の明るさで光っています。ロータリーエンコーダを右へ回すと、1クリックごとに「H」の値が1ずつ増えるので、LEDは明るさを増します。左へ回すとだんだん暗くなって消灯します。

 LEDの明るさの変化は消灯状態を含めて6段階です。つまり変数「H」は0〜5の範囲の値しか取りません。33行目「If H > 5 Then H = 5」と34行目「If H < 0 Then H = 0」の2つの条件分岐プログラムは、「H」の値がこれ以外の数値にならないようにするためのものです。1番明るい状態からさらにツマミを右へ回しても明るさは変化しません。同様に消灯した状態からさらにツマミを左へ回しても消灯したままです。

 「H」をインテジャー型にしたのは変数の範囲指定のプログラムを簡単にするためです。バイト型にすると、「0」から1減らすと「255」になってしまうので、条件の設定が面倒くさくなります。インテジャー型なら「0−1=-1」なので、上記のような簡単な記述で済みます。

4. 2色LEDの色合いを変える

 2色LEDの色が1秒ごとに緑からオレンジ、赤へとだんだんに変化していくプログラムです。「pwm1a.bas」とよく似た形ですが、変数「H」を赤の点灯時間、「L」を緑の点灯時間としています。「H=1」のときは「L=4」なので緑がかった色に、「H=4」のときは「L=1」なので赤っぽい色になる仕組みです。

 プログラムファイル pwm1c.bas

1 $regfile = "attiny2313.dat" ATtiny2313を使用する。
2 $crystal = 1000000 クロック周波数を1MHzに設定。
3
4 Config Portb = Output ポートBを出力に設定する。
5 Dim N As Byte バイト型変数「N」を使用する。
6 Dim H As Byte バイト型変数「H」を使用する。
7 Dim L As Byte バイト型変数「L」を使用する。
8
9 Do Doループ1の範囲ここから。
10  For H = 0 To 5 Forループ。6回繰り返し。
11  L = 5 - H 「5−H」を「L」とする。
12  N = 1 「N」の初期値を「1」とする。
13  Do Doループ2の範囲ここから。
14   Set Portb.0 PB0の出力を「1」にする。赤LEDが点灯。
15   Reset Portb.1 PB1の出力を「0」にする。緑LEDが消灯。
16   Waitms H 「H」ミリ秒間そのまま。
17   Reset Portb.0 PB0の出力を「0」にする。赤LEDが消灯。
18   Set Portb.1 PB1の出力を「1」にする。緑LEDが点灯。
19   Waitms L 「L」ミリ秒間そのまま。
20   Incr N 「N」に1を加える。
21  Loop Until N = 200 Doループ2の範囲ここまで。
「N=200」になるまで(200回・1秒間)繰り返し。
22  Next H Forループここまで。10行目へ戻る。
23 Loop Doループ1の範囲ここまで。
24
25 End 終わり。