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

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

 Timer1のCompare機能を使うプログラムの続きです。ロータリーエンコーダによる比較値設定の際、スイッチを切り替えて早送りするプログラム、およびラジオ用マーカー発振器の実験をしました。

1. 押しボタンスイッチによる早送り

 「タイマー1比較(その1)」で実験したパルス発生器に早送りスイッチを付けたものです。回路図を下に示します。ロータリーエンコーダを回すと比較値が1ずつ増減します。これとは別に押しボタンスイッチが2個付いていて、比較値を100ずつ、あるいは1000ずつアップさせることができます。LCD画面では、先のプログラムと同じように比較値と出力パルスの周期を表示します。

 図1

 プログラムは下記の通りです。ロータリーエンコーダは普通の入力スイッチプログラムで、一方早送りスイッチは外部割込みで処理しています。

 プログラムファイル compare2a.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 Declare Sub Lcdisplay サブルーチン「Lcdisplay」を使用する。
17 On Int0 S0_int INT0割込みが起きたら「S0_int」を実行する。
18 On Int1 S1_int INT1割込みが起きたら「S1_int」を実行する。
19 Dim C As Word ワード型変数「C」を使用する。
20 Dim T1 As Long ロング型変数「T1」を使用する。
21 Dim T2 As String*10 10文字の変数「T2」を使用する。
22 A Alias Pind.4 PD4入力を「A」という名前にする。
23 B Alias Pind.5 PD5入力を「B」という名前にする。
24
25 Enable Interrupts 割り込み全般を許可する。
26 Enable Int0 INT0割込みを許可する。
27 Enable Int1 INT1割込みを許可する。
28 Compare1a = 0 「Compare1a」(比較値)の初期値を「1」とする。
29 Lcd "C=0" LCDの上の行に「C=0」と表示する。
30 Lowerline LCDの下の行に、
31 Lcd "T=0.125mS" 「T=0.125mS」と表示する。
32
33 Do Doループの範囲ここから。
34  Debounce A , 0 , Encode , Sub 「A(Pind.2)=0」になったら「Encode」を実行。
35  Compare1a = C 「C」の値を比較値にする。
36 Loop Doループの範囲ここまで。
37
38 End メインプログラム終わり。
39
40 S0_int: サブルーチン「S0_int」ここから。
(比較値を100ずつアップするプログラム。)
41  C = C + 100 「C+100」を新たな「C」とする。
42  Waitms 250 250ミリ秒間そのまま。
43  Call Lcdisplay サブルーチン「Lcdisplay」へジャンプ。
44 Return サブルーチン「S0_int」ここまで。
45
46 S1_int: サブルーチン「S1_int」ここから。
(比較値を1000ずつアップするプログラム。)
47  C = C + 1000 「C+1000」を新たな「C」とする。
48  Waitms 250 250ミリ秒間そのまま。
49  Call Lcdisplay サブルーチン「Lcdisplay」へジャンプ。
50 Return サブルーチン「S1_int」ここまで。
51
52 Sub Encode サブルーチン「Encode」ここから。
(比較値を1ずつ増減するプログラム。)
53  If B = 1 Then Incr C 「B=1」(右回し)なら「C」の値を1増やす。
54  If B = 0 Then Decr C 「B=0」(左回し)なら「C」の値を1減らす。
55  Call Lcdisplay サブルーチン「Lcdisplay」へジャンプ。
56 End Sub サブルーチン「Encode」ここまで。
57
58 Sub Lcdisplay サブルーチン「Lcdisplay」ここから。
(LCDに比較値と周期を表示するプログラム。)
59  T1 = C + 1 「C+1」を「T1」とする。
60  T1 = T1 * 125 「T1×125」を新たな「T1」とする。
61  T2 = Str(t1) 「T1」の値を文字変数「T2」に変換する。
62  T2 = Format(t2 , "0.000") 「T2」を「0.000」の形にする。
63  Cls : Lcd "C=" ; C LCDの上の行に「C」の値を表示する。
64  Lowerline LCDの下の行に、
65  Lcd "T=" ; T2 ; "mS" 「T2」の値を表示する。
66 End Sub サブルーチン「Lcdisplay」ここまで。

 サブルーチンが4つあります。「S0_int」はS0が押されたときに実行されるプログラムで、比較値「C」を100アップさせます。「S1_int」はS1が押されたときに実行されるプログラムで、比較値「C」を1000アップさせます。「Encode」はロータリーエンコーダを回したときに比較値が1ずつ増減するプログラムです。これらのプログラムで「C」の値が変わるたび、サブルーチン「Lcdisplay」を実行してLCD画面に比較値と周期を表示します。

 プログラムをスタートして何もスイッチに触らないときはLCDに「C=0 T=0.125mS」と表示されます。スピーカーからは8kHzの音が出ます。ロータリーエンコーダを右へ回すと「C」値が1ずつ増え、それにともなって「T」値も少しずつ大きくなります。左へ回すと「C」値が1ずつ減ります。変数「C」はワード型で定義したので、「C=0」の状態でロータリーエンコーダを左へ回すと「C=65535」になります。

 S0を1回チョンと押すたびに「C」値が100増えます。「C=1」の状態でS0を押すと「C=101」になります。また、S0を長押しすると、250ミリ秒ごとに「C」値が100ずつ増えていきます。S1は1000ずつカウントアップするスイッチで、動作はS0と同じです。S0, S1ともにカウントアップ専用です。数を減らすことはできません。

2. トグルスイッチによる早送り

 本題からそれてロータリーエンコーダプログラムの練習みたいになっていますが、今度はトグルスイッチによる早送りを試してみました。回路は下記の通りです。S0, S1をトグルスイッチに換えました。S0, S1ともに開いているときはロータリーエンコーダで比較値を1ずつアップダウンできます。S0を閉じた状態でロータリーエンコーダを回すと、1クリックごとに100ずつ早送り (アップダウン) します。S1は1000ずつ早送りするスイッチです。このプログラムではアップダウン両方向へ早送りできます。

 図2

 プログラムは下記の通りです。基本的に「ロータリーエンコーダ(その2)」でやったのと同じ方法です。右回しと左回しそれぞれの条件分岐プログラムの中に、さらに早送り用の条件分岐が入れ子になっています。14行目までは上のプログラムと同じなので省略します。

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

( 前 略 ) 
15 Declare Sub Encode サブルーチン「Encode」を使用する。
16 Dim C As Word ワード型変数「C」を使用する。
17 Dim T1 As Long ロング型変数「T1」を使用する。
18 Dim T2 As String*10 10文字の変数「T2」を使用する。
19 A Alias Pind.4 PD4入力を「A」という名前にする。
20 B Alias Pind.5 PD5入力を「B」という名前にする。
21 S0 Alias Pind.2 PD2入力を「S0」という名前にする。
22 S1 Alias Pind.3 PD3入力を「S1」という名前にする。
23 Compare1a = 0 「Compare1a」(比較値)の初期値を「1」とする。
24 Lcd "C=0" LCDの上の行に「C=0」と表示する。
25 Lowerline LCDの下の行に、
26 Lcd "T=0.125mS" 「T=0.125mS」と表示する。
27
28 Do Doループの範囲ここから。
29  Debounce A , 0 , Encode , Sub 「A(Pind.2)=0」になったら「Encode」を実行。
30  Compare1a = C 「C」の値を比較値にする。
31 Loop Doループの範囲ここまで。
32
33 End メインプログラム終わり。
34
35 Sub Encode サブルーチン「Encode」ここから。
36  If B = 1 Then 条件分岐1。「B=1」(右回し)ならば、
37   Incr C 「C」の値を1増やす。
38   If S0 = 0 Then C = C + 99 「S0=0」ならば「C」の値を99増やす。
39   If S1 = 0 Then C = C + 999 「S1=0」ならば「C」の値を999増やす。
40  End If 条件分岐1ここまで。
41  If B = 0 Then 条件分岐2。「B=0」(左回し)ならば、
42   Decr C 「C」の値を1減らす。
43   If S0 = 0 Then C = C - 99 「S0=0」ならば「C」の値を99減らす。
44   If S1 = 0 Then C = C - 999 「S1=0」ならば「C」の値を999減らす。
45  End If 条件分岐2ここまで。
46  T1 = C + 1 「C+1」を「T1」とする。
47  T1 = T1 * 125 「T1×125」を新たな「T1」とする。
48  T2 = Str(t1) 「T1」の値を文字変数「T2」に変換する。
49  T2 = Format(t2 , "0.000") 「T2」を「0.000」の形にする。
50  Cls : Lcd "C=" ; C LCDの上の行に「C」の値を表示する。
51  Lowerline LCDの下の行に、
52  Lcd "T=" ; T2 ; "mS" 「T2」の値を表示する。
53 End Sub サブルーチン「Encode」ここまで。

3. ラジオ用マーカー発振器

 自作ラジオの調整や目盛付けに使えそうなマーカー発振器のプログラムを考えました。マイコンのクロック周波数を20MHzとし、出力端子からその分周波を出力します。今回は出力周波数を10MHz, 5MHz, 2MHz, 1MHz, 500kHz, 200kHz,100kHz, 50kHz, 20kHz, 10kHzの10種類としました。出力周波数はロータリーエンコーダで設定します。出力は方形波ですから、基本波のほかに整数倍の高調波も出ます。例えば出力を1MHzにしてラジオをそばに置くと、1MHz, 2MHz, 3MHz,・・・というように1MHzおきにマーカーの信号が受信できます。

 回路図を下に掲げます。クロック源は20MHzの水晶発振器EXO-3の原周波数を用います。原周波数と分周出力では出力端子が違うので注意してください。他に出力周波数設定用のロータリーエンコーダ、出力周波数表示用のLCDを接続します。水晶発振器を使用する場合のヒューズビットは、周波数にかかわらず「1110 0000」です。

 図3

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

1 $regfile = "attiny2313.dat" ATtiny2313を使用する。
2 $crystal = 20000000 クロック周波数を20MHzに設定。
3
4 Config Timer1 = Timer , Prescale = 1 , Compare A = Toggle , Clear Timer = 1
Timer1をタイマーとして使用。分周比は1。
比較A出力はToggle。Clear Timerは1。
5 Config Lcdpin=Pin, Db7=Portb.0, Db6=Portb.1 LCDの接続設定。DB7=PB0, DB6=PB1。
6 Config Lcdpin=Pin, Db5=Portb.2, Db4=Portb.4 LCDの接続設定。DB5=PB2, DB4=PB4。
7 Config Lcdpin=Pin, E=Portb.5, Rs=Portb.6 LCDの接続設定。E=PB5, RST=PB6。
8 Config Lcd = 16 * 2 16文字×2行表示のLCDを使用する。
9 Cls : Cursor Off LCDの表示を消去。カーソルを消去。
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 N As Byte バイト型変数「N」を使用する。
17 Dim C(10) As Word 10値のワード型変数「C」を使用する。
18 Dim F(10) As Word 10値のワード型変数「F」を使用する。
19 A Alias Pind.2 PD2入力を「A」という名前にする。
20 B Alias Pind.3 PD3入力を「B」という名前にする。
21 N = 1 変数「N」の初期値を「1」とする。
22 Lcd "MARKER 10MHz" LCDに「MARKER 10MHz」と表示する。
23
24 C(1) = 0 変数「C」の1番目の値は「0」。
25 C(2) = 1 変数「C」の2番目の値は「1」。
26 C(3) = 4 変数「C」の3番目の値は「4」。
27 C(4) = 9 変数「C」の4番目の値は「9」。
28 C(5) = 19 変数「C」の5番目の値は「19」。
29 C(6) = 49 変数「C」の6番目の値は「49」。
30 C(7) = 99 変数「C」の7番目の値は「99」。
31 C(8) = 199 変数「C」の8番目の値は「199」。
32 C(9) = 499 変数「C」の9番目の値は「499」。
33 C(10) = 999 変数「C」の10番目の値は「999」。
34
35 F(1) = 10 変数「F」の1番目の値は「10」。
36 F(2) = 5 変数「F」の2番目の値は「5」。
37 F(3) = 2 変数「F」の3番目の値は「2」。
38 F(4) = 1 変数「F」の4番目の値は「1」。
39 F(5) = 500 変数「F」の5番目の値は「500」。
40 F(6) = 200 変数「F」の6番目の値は「200」。
41 F(7) = 100 変数「F」の7番目の値は「100」。
42 F(8) = 50 変数「F」の8番目の値は「50」。
43 F(9) = 20 変数「F」の9番目の値は「20」。
44 F(10) = 10 変数「F」の10番目の値は「10」。
45
46 Do Doループの範囲ここから。
47  Debounce A , 0 , Encode , Sub 「A(Pind.2)=0」になったら「Encode」を実行。
48 Loop Doループの範囲ここまで。
49
50 End メインプログラム終わり。
51
52 Sub Encode サブルーチン「Encode」ここから。
53  If B = 1 Then Incr N 「B=1」(右回し)なら「N」の値を1増やす。
54  If B = 0 Then Decr N 「B=0」(左回し)なら「N」の値を1減らす。
55  If N > 10 Then N = 1 「N > 10」になったら「N = 1」にする。
56  If N < 1 Then N = 10 「N < 1」になったら「N = 10」にする。
57  Compare1a = C(n) 「C」の「N」番目の値を比較値にする。
58  If N < 5 Then 条件分岐。「N < 5」ならば、
59   Cls : Lcd "MARKER " ; F(n) ; "MHz" LCDにMHz単位で周波数を表示する。
60  Else 「N ≥ 5」ならば、
61   Cls : Lcd "MARKER " ; F(n) ; "kHz" LCDにkHz単位で周波数を表示する。
62  End If 条件分岐ここまで。
63 End Sub サブルーチン「Encode」ここまで。

 マイコンICのクロック周波数は20MHz、Timer1の分周比は1にしたので、Timer1の1カウントの時間は0.05μSです。したがって比較値(変数「C」)と出力周波数の関係は下記のようになります。

比較値0149 194999199499999
周波数10MHz5MHz2MHz1MHz 500kHz200kHz100kHz 50kHz20kHz10kHz

 比較値の増減のしかたが規則的ではないので、「変数の配列」を使うことにしました。17行目「Dim C(10) As Word」は変数「C」が決められた10個の値を取ることを意味してします。同様に周波数表示用の変数「F」の値も10個です。これらの10個の値には順番があります。24行目から44行目でそれを列挙しています。これらの値を順番に呼び出して比較値に代入あるいはLCDに表示するために「N」という変数を使います。

 ロータリーエンコーダを回すと「N」の値が「1」から「10」の範囲で増えたり減ったりします。「N=1」のときは「C」の1番目の値すなわち「0」が比較値に代入され (57行目「Compare1a = C(n)」)、「F」の1番目の値すなわち「10」がLCDに表示されます (59行目「Cls : Lcd "MARKER " ; F(n) ; "MHz"」)。このようにして出力周波数とLCDの表示を変えていきます。LCDの表示は、「N」が「4」以下のときはMHz単位で、「5」以上のときは「kHz」単位でなされます。

 出力端子に数十cmのビニール線をつなぎ、短波ラジオをそばに持っていったところ、等間隔の周波数で無変調信号が受信できました。ただ出力周波数によっては偶数次の高調波 (基本波の2倍, 4倍, 6倍,・・・) が弱い場合があります。以前に普通のデジタルICでマーカーを作ったときもそうだったように記憶しています。受信テストの際は、マイコン回路をパソコンから切り離し、独自の電源 (DC5V) を接続して実験しました。パソコンから電源を取るとパソコンのノイズがうるさくてだめです。AVRマイコンICもノイズを出しますが、ラジオを極端に近づけない限り、それほど気になりませんでした。