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

BASCOM-AVR タイマー1比較(その1)

 Timer1のCompare(比較)機能を使うプログラムについて実験しました。Timer1のカウントがあらかじめ設定した値と同じになったら出力端子の状態を変化させるというものです。簡単な設定でデューティー比50%の方形波を出力することができます。マイコンICはATtiny2313を用いました。

1. 実験回路

 プログラムのテスト用回路は下記の通りです。Timer1-Compareの出力端子はPWMと同じくOC1です。したがってマイコン回路もPWMの実験のときと同じです。IC1が今回実験するプログラムを書き込むIC、IC2が出力のパルス幅測定用のICです。IC2には「パルス周期の測定(その2)」でやったパルス幅測定プログラム「pwidth2b.bas」を書き込んでおきます。なお、IC1の出力端子には、おおよその出力周波数を耳で確認できるように圧電スピーカーも付けました。

 図1

2. タイマー1比較プログラムの基本

 PWMプログラムのときもそうでしたが、今回もプログラムの書き方しかわかりません。とりあえず適当に数字を入れて何か起きるか試してみました。BASCOM-AVRがインストールされたパソコンで下記リンクをクリックしてファイルをダウンロードすると、BASCOM-AVR IDEが自動的に立ち上がって画面内にプログラムが表示されます。

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

1 $regfile = "attiny2313.dat" ATtiny2313を使用する。
2 $crystal = 1024000 クロック周波数を1.024MHzに設定。
3 Config Portb = Output ポートBを出力に設定する。
4 Config Timer1 = Timer , Prescale = 1024 , Compare A = Toggle , Clear Timer = 1
Timer1 Compareの設定。
Timer1をタイマーとして使用。分周比は1024。
比較A出力はToggle。Clear Timerは1。
5 Compare1a = 1000 比較値を「1000」にする。
6 End 終わり。

 4行目の横に長いプログラム文がタイマー1比較の設定です。「Compare A = Toggle」はTimer1が設定値になったときに出力がどう変化するかを決めるものです。「Toggle」「Set」「Clear」「Disconnect」の4つの中から選択します。「Toggle」と書くとTimer1のカウントが設定値になるたびOC1出力が反転します。「Toggle」以外は何が起きるのか解明できませんでした。また、最後の「Clear Timer = 1」も何の意味かわかりませんが、こう書いておかないと正しく動作しません。

 5行目「Compare1a = 1000」は、Timer1のカウントがいくつになったら出力を反転するかを記述するものです。最初の実験では「1000」にしてみました。クロック周波数が1.024MHzで分周比が1024ですから、Timer1の1カウントは1mSになります。「Compare1a = 1000」と書けば、1秒後あたりに何か変化が起こるはずです。なお、この「Compare1a」の値のことを今後は「比較値」とよぶことにします。

 このプログラムを実行すると、LEDが1秒ごとに点いたり消えたりしました。IC2による測定値は点灯時間・消灯時間とも1001mSでした。比較値をいろいろ変えてみたとき、出力が「1」になっている時間と出力が「0」になっている時間は下記のようになりました。

比較値出力「1」出力「0」コメント
01mS1mS 約1分後に500Hzの音が出る。
12mS2mS すぐに音が出る。250Hz。
23mS3mS 167Hz。
9991000mS1000mS 1000ミリ秒後に出力反転。
10001001mS1001mS 1001ミリ秒後に出力反転。
6553565536mS65536mS IC2の表示は「0mS」。
655361mS1mS 比較値「0」のときと同じ。

 出力が「0」から「1」になるのはTimer1のカウントが「比較値+1」になったときです。これは、Timer1が0からカウントを始めて、比較値までカウントし終えた瞬間に出力が反転するということだと思います。このときTimer1のカウントもクリアされ、また0からカウントを再開します。Timer1のカウントが再び比較値に達すると、先程「1」になった出力が「0」に戻ります。こうしてデューティー比50%のパルスが連続して出力されます。一連の動作を図に書くと下記のようになります。

 図2

 Timer1のカウントの最大値は65535ですが、比較値を「65536」にすると比較値「0」のときと同じ動作になりました。つまり設定値が65535を超えたときは65535を差し引いた値を比較値として認識するようです。また比較値「0」のときは (比較値「65536」のときも) 500Hz (周期2mS) で発振するのですが、音が出るまでに1分余りかかります。たぶんこれはTimer1の1周分、65536ミリ秒後ということなんだろうと思います。

 比較値が「65535」のときはIC2の表示は「0mS」になります。これはIC2のプログラムがTimer1のオーバーフローを考慮していないためで、実際には65536mSごとにLEDが点滅します。

3. 比較値と出力パルス周期の関係

 上記の実験結果から、比較値 (Compare1aの設定値) と出力パルスの周期 (T) との間には、下のような関係があることがわかりました。

 周期T[μS] = (分周比÷クロック周波数[MHz])×(比較値+1)×2

 クロック周波数が1.024MHzの場合についていくつか数値例を計算してみたので下に掲げます。

比較値分周比1分周比8分周比64 分周比256分周比1024
01.953μS
(512kHz)
15.63μS
(64kHz)
125μS
(8kHz)
500μS
(2kHz)
2mS
(500Hz)
13.906μS31.25μS250μS 1mS4mS
37.813μS62.5μS500μS 2mS8mS
715.63μS125μS1mS 4mS16mS
1531.25μS250μS2mS 8mS32mS
63125μS1mS8mS 32mS128mS
255500μS4mS32mS 128mS512mS
10232mS16mS128mS 512mS2048mS
40958mS64mS512mS 2048mS8192mS
1638332mS256mS2048mS 8192mS32768mS
65535128mS1024mS8192mS 32768mS131072mS

4. ロータリーエンコーダで比較値を変える

 ロータリーエンコーダで比較値を任意に設定できるプログラムです。1ずつの増減ではまどろっこしいので、2の累乗の指数部分を変数にして、2倍あるいは2分の1ずつ変化するようにしました。ロータリーエンコーダを右へ回すと1クリックごとに比較値が2倍になります。つまり出力パルスの周期も2倍になります。左へ回すと1クリックごとに比較値が2分の1になります。低周波アンプやデジタル回路のテスト用信号発生器として使えるかもしれません。

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

1 $regfile = "attiny2313.dat" ATtiny2313を使用する。
2 $crystal = 1024000 クロック周波数を1.024MHzに設定。
3
4 Config Timer1 = Timer , Prescale = 64 , Compare A = Toggle , Clear Timer = 1
Timer1をタイマーとして使用。分周比は64。
比較A出力はToggle。Clear Timerは1。
5 Config Debounce = 1 デバウンスタイムを1mSとする。
6 Config Portb = Output ポートBを出力に設定する。
7 Config Portd = Input ポートDを入力に設定する。
8 Portd = 127 PD0〜PD6をプルアップ。
9
10 Declare Sub Encode サブルーチン「Encode」を使用する。
11 Dim C As Long ロング型変数「C」を使用する。
12 Dim N As Integer インテジャー型変数「N」を使用する。
13 A Alias Pind.2 PD2入力を「A」という名前にする。
14 B Alias Pind.3 PD3入力を「B」という名前にする。
15
16 Do Doループの範囲ここから。
17  Debounce A , 0 , Encode , Sub 「A(Pind.2)=0」になったら「Encode」を実行。
18 Loop Doループの範囲ここまで。
19
20 End メインプログラム終わり。
21
22 Sub Encode サブルーチン「Encode」ここから。
23  If B = 1 Then Incr N 「B=1」(右回し)なら「N」の値を1増やす。
24  If B = 0 Then Decr N 「B=0」(左回し)なら「N」の値を1減らす。
25  If N > 16 Then N = 0 「N > 16」になったら「N=0」にする。
26  If N < 0 Then N = 16 「N < 0」になったら「N=16」にする。
27  C = 2 ^ N 2の「N」乗を「C」とする。
28  C = C - 1 「C−1」を新たな「C」とする。
29  Compare1a = C 「C」の値を比較値にする。
30 End Sub サブルーチン「Encode」ここまで。

 分周比を64にしたので、Timer1の1カウントは62.5μSです。したがって出力パルスの周期は比較値「C」が「0」のとき125μS、「65535」のとき8192mSです。周期125μSのときはスピーカーから周波数8kHzの音が出ます。周期8192mSのときはLEDが約4秒ごとに点滅します。変数「N」の初期値は「0」なので、プログラムを実行すると最初は比較値「C」が「0」 (2^0−1=0) になり、スピーカーからは8kHzの「ピー」という高い音が出ます。ただし音が出てくるまでに4秒ほど時間がかかります。

 ロータリーエンコーダのツマミを1クリック分右へ回すと、変数「N」の値が「1」になります。これにより比較値「C」は「1」になり、出力パルスの周期は2倍の250μS (周波数4kHz) になります。もう1クリック右へ回すと「N=2, C=3」となって出力周期は500μSになります。このように右へ1クリック回すごとに周期は2倍になるので、スピーカーから出る音はだんだん低くなり、やがてLEDの点滅を確認できるくらいになります。「N=16, C=65535」の状態からもう1クリック右へ回すと、最初の「N=0」に戻ります。

 逆にロータリーエンコーダを左へ回すと1クリックごとに「N」の値は1ずつ減り、出力波の周期は2分の1になります。「N=0」になると、次は「16」に戻ります。ただ、周期を短くしていったときは、出力が切り替わるまで4秒ほど待たされることがあります。これについては下の図を見てください。最初の比較値が「C1」で、図のA点のところで「C2」に切り換えたとすると、出力周期が切り替わるのはTimer1が1周した後になります。

 図3

5. LCD画面に比較値と周期を表示する

 上記のプログラムと同じ動作ですが、LCD画面の上の行に比較値を、下の行に出力波の周期を表示します。周期は実際に測定しているわけではなく、比較値から計算で求めてmS単位で表示します。マイコン回路は下記の通りです。LCDユニットをIC1につなぎます。PB3はOC1出力なので、LCDの端子はPB0〜PB2, PB4〜PB6に接続しました。IC2は不要です。

 図4

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

1 $regfile = "attiny2313.dat" ATtiny2313を使用する。
2 $crystal = 1024000 クロック周波数を1.024MHzに設定。
3
4 Config Lcdpin=Pin, Db7=Portb.0, Db6=Portb.1 LCDの接続設定。DB7=PB0, DB6=PB1。
5 Config Lcdpin=Pin, Db5=Portb.2, Db4=Portb.4 LCDの接続設定。DB5=PB2, DB4=PB4。
6 Config Lcdpin=Pin, E=Portb.5, Rs=Portb.6 LCDの接続設定。E=PB5, RST=PB6。
7 Config Lcd = 16 * 2 16文字×2行表示のLCDを使用する。
8 Cls : Cursor Off LCDの表示を消去。カーソルを消去。
9 Config Timer1 = Timer , Prescale = 64 , Compare A = Toggle , Clear Timer = 1
Timer1をタイマーとして使用。分周比は64。
比較A出力はToggle。Clear Timerは1。
10 Config Debounce = 1 デバウンスタイムを1mSとする。
11 Config Portb = Output ポートBを出力に設定する。
12 Config Portd = Input ポートDを入力に設定する。
13 Portd = 127 PD0〜PD6をプルアップ。
14
15 Declare Sub Encode サブルーチン「Encode」を使用する。
16 Dim C1 As Long ロング型変数「C1」を使用する。
17 Dim C2 As Long ロング型変数「C2」を使用する。
18 Dim T1 As Long ロング型変数「T1」を使用する。
19 Dim T2 As String*10 10文字の変数「T2」を使用する。
20 Dim N As Integer インテジャー型変数「N」を使用する。
21 A Alias Pind.2 PD2入力を「A」という名前にする。
22 B Alias Pind.3 PD3入力を「B」という名前にする。
23
24 Compare1a = 0 「Compare1a」(比較値)の初期値を「1」とする。
25 Lcd "C=0" LCDの上の行に「C=0」と表示する。
26 Lowerline LCDの下の行に、
27 Lcd "T=0.125mS" 「T=0.125mS」と表示する。
28
29 Do Doループの範囲ここから。
30  Debounce A , 0 , Encode , Sub 「A(Pind.2)=0」になったら「Encode」を実行。
31 Loop Doループの範囲ここまで。
32
33 End メインプログラム終わり。
34
35 Sub Encode サブルーチン「Encode」ここから。
36  If B = 1 Then Incr N 「B=1」(右回し)なら「N」の値を1増やす。
37  If B = 0 Then Decr N 「B=0」(左回し)なら「N」の値を1減らす。
38  If N > 16 Then N = 0 「N > 16」になったら「N=0」にする。
39  If N < 0 Then N = 16 「N < 0」になったら「N=16」にする。
40  C1 = 2 ^ N 2の「N」乗を「C1」とする。
41  C2 = C1 - 1 「C1−1」を「C2」とする。
42  T1 = C1 * 125 「C1×125」を「T1」とする。
43  T2 = Str(t1) 「T1」の値を文字変数「T2」に変換する。
44  T2 = Format(t2 , "0.000") 「T2」を「0.000」の形にする。
45  Compare1a = C2 「C2」の値を比較値にする。
46  Cls : Lcd "C=" ; C2 LCDの上の行に「C2」の値を表示する。
47  Lowerline LCDの下の行に、
48  Lcd "T=" ; T2 ; "mS" 「T2」の値を表示する。
49 End Sub サブルーチン「Encode」ここまで。