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

BASCOM-AVR タイマー機能(その3)

 ATtiny2313を使って、Timer1のカウンタ機能の実験をしました。ICの「T1」端子に入力されたパルスの数をカウントするプログラムです。

1. テスト用マイコン回路

 プログラムのテスト用回路は下記の通りです。ATtiny2313は9番ピン(PD5)がT1用の入力端子です。ここにLEDと押しボタンスイッチをつなぎました。クロックは1MHzの水晶発振器です。

 第1図

2. LEDの点滅回数をカウントする

 T1端子につないだLEDを1秒周期で点滅させ、その回数をLCD画面に表示するプログラムを試してみました。1個のマイコンICでLEDの点滅と回数のカウントが同時にできます。

 第2図

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

1 $regfile = "attiny2313.dat" ATtiny2313を使用する。
2 $crystal = 1000000 クロック周波数を1MHzに設定。
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.3 LCDの接続設定。DB5=PB2, DB4=PB3。
6 Config Lcdpin=Pin, E=Portb.4, Rs=Portb.5 LCDの接続設定。E=PB4, RST=PB5。
7 Config Lcd = 16 * 2 16文字×2行表示のLCDを使用する。
8 Config Portd = Output ポートDを出力に設定する。
9 Config Timer1 = Counter , Edge = Falling Timer1をカウンタとして使用。
入力パルスの立下りでカウント。
10
11 Cls : Cursor Off LCDの表示を消去。カーソルを消去。
12 Lcd "COUNT 0" LCDに「COUNT 0」と表示する。
13
14 Do Doループの範囲ここから。
15  Toggle Portd.5 PD5の出力を反転する。
16  Cls LCDの表示を消去する。
17  Lcd "COUNT " ; Timer1 LCDに「COUNT」の文字とカウント数を表示。
18  Waitms 500 0.5秒間そのまま。
19 Loop Doループの範囲ここまで。
20
21 End 終わり。

 T1端子(PD5)につないだLEDを点滅させるため、8行目「Config Portd = Output」でポートDを出力に設定しておきます。T1端子が出力になっていてもカウンタ機能には影響ありません。9行目「Config Timer1 = Counter , Edge = Falling」はTimer1をカウンタとして使用するための設定です。「Edge = Falling」は入力信号の立下り(1から0になった瞬間)にカウントを進めるという意味です。入力信号の立上りでカウントするときは「Edge = Rising」と書きます。

 メインプログラム内ではLEDの点滅とカウント数の表示をしています。17行目「Lcd "COUNT " ; Timer1」の「Timer1」のところは「Counter1」と書いてもOKです。ループ1回目でPD5出力(T1入力)は0から1になります。このときはカウントされませんので表示は「0」のままです。ループ2回目でPD5が1から0になるとカウントは「1」になります。つまり、LEDが消灯する瞬間にカウントが1ずつ増えるわけです。9行目を「〜 , Edge = Rising」に変えると、LEDが点灯する瞬間にカウントします。LEDが付いていなくてもカウントは同じように行なわれますが、LEDがあれば「Edge = Falling」と「Edge = Rising」の違いがよくわかります。

3. スイッチを押した回数をカウントする

 T1端子につないだ押しボタンスイッチを1回押すたびにカウントが1ずつアップするプログラムです。メインプログラムでスイッチの状態を検知し、サブルーチン内でLCDへの表示を行ないます。ポートDは入力に設定します。実際に動作させて見ると、10回に1回くらい、スイッチひと押しで2カウント進むことがありました。理由はわかりません。デバウンス処理をしなければひと押しで数十カウントも進んでしまいますから、デバウンスが効いていることは確かですが。

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

1 $regfile = "attiny2313.dat" ATtiny2313を使用する。
2 $crystal = 1000000 クロック周波数を1MHzに設定。
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.3 LCDの接続設定。DB5=PB2, DB4=PB3。
6 Config Lcdpin=Pin, E=Portb.4, Rs=Portb.5 LCDの接続設定。E=PB4, RST=PB5。
7 Config Lcd = 16 * 2 16文字×2行表示のLCDを使用する。
8 Config Portd = Input ポートDを入力に設定する。
9 Config Timer1 = Counter , Edge = Rising Timer1をカウンタとして使用。
入力パルスの立上りでカウント。
10
11 Declare Sub Switch サブルーチン「Switch」を使用する。
12 Portd = 127 PD0〜PD6をプルアップする。
13 Cls : Cursor Off LCDの表示を消去。カーソルを消去。
14 Lcd "COUNT 0" LCDに「COUNT 0」と表示する。
15
16 Do Doループの範囲ここから。
17  Debounce Pind.5 , 0 , Switch , Sub 「PD5=0」ならばサブルーチン「Switch」へ。
18 Loop Doループの範囲ここまで。
19
20 End メインプログラム終わり。
21
22 Sub Switch サブルーチン「Switch」ここから。
23  Cls LCDの表示を消去する。
24  Lcd "COUNT " ; Timer1 「COUNT」とカウント数を表示する。
25 End Sub サブルーチン「Switch」ここまで。

4. 簡単な周波数カウンタ

 T1端子に低周波の信号を入力し、パルスの数を1秒間数えてLCDに表示するプログラムを作りました。いうなれば周波数カウンタです。回路図を下に示します。少しごちゃごちゃしていますが、入力信号を別のICで作っているためです。マイコン回路自体は特別なものは何も付いていません。

 入力信号は、水晶発振器の出力をカウンタICで分周したものを用いました。こうすれば、水晶発振器の周波数に誤差があっても関係なくなるので、プログラムの検証に便利だと考えました。もし測定値に端数が出れば、それはすなわちプログラムに不具合があるということになります。IC1・74HC4518では、原周波数(1MHz)の1⁄10(100kHz), 1⁄20(50kHz), 1⁄50(20kHz), 1⁄100(10kHz)の信号を作っています。入力の切替はブレッドボード上でジャンパー線の接続を変えるようにしました。

 第3図

 第4図

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

1 $regfile = "attiny2313.dat" ATtiny2313を使用する。
2 $crystal = 1000000 クロック周波数を1MHzに設定。
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.3 LCDの接続設定。DB5=PB2, DB4=PB3。
6 Config Lcdpin=Pin, E=Portb.4, Rs=Portb.5 LCDの接続設定。E=PB4, RST=PB5。
7 Config Lcd = 16 * 2 16文字×2行表示のLCDを使用する。
8 Config Timer1 = Counter , Edge = Rising Timer1をカウンタとして使用。
入力パルスの立上りでカウント。
9 Cls : Cursor Off LCDの表示を消去。カーソルを消去。
10 Stop Timer1 Timer1をストップ。
11
12 Do Doループの範囲ここから。
13  Timer1 = 0 Timer1のカウントを「0」にする。
14  Start Timer1 Timer1をスタート。
15  Waitms 995 995ミリ秒そのまま。
16  Stop Timer1 Timer1をストップ。
17  Cls LCDの表示を消去する。
18  Lcd "FREQ " ; Timer1 ; "Hz" LCDに「FREQ」, 周波数, 「Hz」を表示。
19 Loop Doループの範囲ここまで。
20
21 End 終わり。

 測定する信号はT1端子に入力するわけですが、T1(PD5)は入力に設定しなくても大丈夫でした。Timer1をカウンタに設定したらいったんストップさせ、Doループに入ってカウント値を「0」にしてから改めてスタートさせます。「Wait」命令で1秒過ぎたらTimer1を止め、その時点のカウント数をLCDに表示します。ループ2回目では再び「0」から数え直します。

 15行目が「Waitms 1000」ではなくて「Waitms 995」なのは、プログラムの実行時間を考慮したためです。シミュレーターによると15行目「Waitms 995」の時点でのサイクル数は「272519」、17行目「Cls」の時点でのサイクル数は「1272517」でした。つまりTimer1の動作時間は0.999998秒で1秒よりわずかに短いですが、測定する周波数が低いのでこれくらいの誤差は問題ありません。

 Timer1のカウントは65535までなので、このプログラムでは65535Hz(65.535kHz)まで測定できます。10〜50kHzの信号を入力してみたところ、1Hzの位まで正確に測定できました。65536Hz以上の信号を入力すると、オーバーフローであふれた分が表示されます。100kHzの場合は 100000−65536=34464 なので、「34464Hz」と表示されます。