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

BASCOM-AVR 秋月DDSのコントロール(その2)

 秋月電子のDDSキットをシリアル制御するプログラムの続きです。ロータリーエンコーダで出力周波数を設定できるようにしました。

1. ロータリーエンコーダによる周波数設定

 初期設定で出力周波数を1000Hzとし、ロータリーエンコーダを右へ回すと1クリックごとに周波数が100Hzずつ上昇、左へ回すと100Hzずつ下降するプログラムです。出力周波数の範囲は0Hz〜10kHzとしました。

 実験回路を下に示します。PB0, PB1, およびGNDにロータリーエンコーダをつなぎました。クリスタルイヤホンで音が聞けるようにしますが、出力が数kHzになると音が大きくなってうるさいので、イヤホンと直列に47kΩの抵抗を入れました。

 第1図

 プログラムは下記の通りです。

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

1 $regfile = "attiny2313.dat" ATtiny2313を使用する。
2 $crystal = 1000000 クロック周波数を1MHzに設定。
3
4 Config Portb = Input ポートBを入力に設定する。
5 Config Portd = Output ポートDを出力に設定する。
6 Config Debounce = 1 デバウンス時間を1mSとする。
7 Declare Sub Encode サブルーチン「Encode」を使用する。
8 Declare Sub Datashift サブルーチン「Datashift」を使用する。
9 Dim C As Byte バイト型変数「C」を使用する。
10 Dim F As Long ロング型変数「F」を使用する。
11 C = &B1100111 変数「C」の値を「1100111」(2進数)にする。
12 F = 1000 変数「F」の値を「1000」(10進数)にする。
13 Portb = 255 PB0〜PB7をプルアップする。
14 A Alias Pinb.0 PB0入力を「A」という名前にする。
15 B Alias Pinb.1 PB1入力を「B」という名前にする。
16 Call Datashift サブルーチン「Datashift」を実行する。
17
18 Do Doループの範囲ここから。
19  Debounce A , 0 , Encode , Sub 「A=0」になったらサブルーチン「Encode」を実行する。
20 Loop Doループの範囲ここまで。
21
22 End メインプログラム終わり。
23
24 Sub Encode サブルーチン「Encode」ここから。
25  If B = 1 Then 条件分岐A。「B=1」(右回転)ならば、
26   F = F + 100 変数「F」に100を加える。
27   If F > 10000 Then F = 10000 条件分岐B1。「F」が10000を超えたら「F=10000」とする。
28   Call Datashift サブルーチン「Datashift」を実行する。
29  Else 「B=0」(左回転)ならば、
30   F = F - 100 変数「F」から100を引く。
31   If F < 0 Then F = 0 条件分岐B2。「F」が負になったら「F=0」とする。
32   Call Datashift サブルーチン「Datashift」を実行する。
33  End If 条件分岐Aここまで。
34 End Sub サブルーチン「Encode」ここまで。
35
36 Sub Datashift サブルーチン「Datashift」ここから。
37  Set Portd.4 PD4 (STB出力) を「1」にする。
38  Shiftout Portd.5 , Portd.6 , C , 3 , 7 変数「C」のデータ (7ビット) を送る。
39  Shiftout Portd.5 , Portd.6 , F , 3 , 26 変数「F」のデータ (26ビット) を送る。
40  Reset Portd.4 PD4 (STB出力) を「0」にする。
41  Set Portd.4 PD4 (STB出力) を「1」にする。
42 End Sub サブルーチン「Datashift」ここまで。

 ロータリーエンコーダはポートBに接続したので、ポートBを入力に設定してプルアップします。デバウンス時間は1mSにしました。回転の検知はこれまでと同じ方法です。Do〜Loopで端子Aの変化を監視して、変化があればサブルーチン「Encode」へジャンプします。端子Bが「1」ならば右回転ですので、変数「F」を100増やします。つまり出力周波数が100Hzアップします。端子Bが「0」ならば左回転なので「F」を100減らします。「F」の値に変化があるたび、サブルーチン「Datashift」を実行して新しいデータをDDSへ送ります。

 「F」の範囲は0〜10000にしました。したがって出力周波数は0Hz〜10kHzです。こうしたのは単に実験上の都合で、プログラム的に制約があるわけではありません。上限を設けなければ周波数はいくらでも高くなります。また、「F」がマイナスになった場合はその絶対値の周波数が出力されます。つまり「F=−100」なら100Hz、「F=−200」なら200Hzの音が出ます。

2. 早送りスイッチを付ける

 希望する周波数をすみやかに設定できるように、周波数ステップを切り替えるためのスイッチを付けました。1Hz, 10Hz, 100Hz, 1kHz, 10kHz, 100kHz, 1MHzの7段階に切り替えることができます。例えば1kHzにセットすると、ロータリーエンコーダを回すたびに出力周波数が1kHzずつ増減します。

 実験回路を下に示します。PA0とPA1、およびPD0〜PD3の6本が早送りスイッチ用の端子です。実験では、ブレッドボード上でジャンパー線を挿し替えることでスイッチに代わりにしました。ジャンパー線をどこにも接続しなければ1Hzステップになります。

 第2図

 プログラムは下記の通りです。毎度おなじみの不細工プログラムでございます。早送りスイッチの端子に「S10」(10Hz用) から「S1000000」(1MHz用) までの名前を付け、サブルーチン「Datashift」の中でそれぞれの端子の状態を調べます。周波数範囲は0Hzから10MHzまでです。なお、6行目「Config Portd = &B1110000」はポートDの7本のうち、PD0〜PD3を入力に、PD4〜PD6を出力にするプログラムです。16行目「Portd = 15」で、入力に設定したPD0〜PD3だけをプルアップしています。

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

1 $regfile = "attiny2313.dat" ATtiny2313を使用する。
2 $crystal = 1000000 クロック周波数を1MHzに設定。
3
4 Config Porta = Input ポートAを入力に設定する。
5 Config Portb = Input ポートBを入力に設定する。
6 Config Portd = &B1110000 PD0〜PD3を入力に、PD4〜PD6を出力に設定する。
7 Config Debounce = 1 デバウンス時間を1mSとする。
8 Declare Sub Encode サブルーチン「Encode」を使用する。
9 Declare Sub Datashift サブルーチン「Datashift」を使用する。
10 Dim C As Byte バイト型変数「C」を使用する。
11 Dim F As Long ロング型変数「F」を使用する。
12 C = &B1100111 変数「C」の値を「1100111」(2進数)にする。
13 F = 1000 変数「F」の値を「1000」(10進数)にする。
14 Porta = 3 PA0, PA1をプルアップする。
15 Portb = 255 PB0〜PB7をプルアップする。
16 Portd = 15 PD0〜PD3をプルアップする。
17 A Alias Pinb.0 PB0入力を「A」という名前にする。
18 B Alias Pinb.1 PB1入力を「B」という名前にする。
19 S10 Alias Pind.0 PD0入力を「S10」という名前にする。
20 S100 Alias Pind.1 PD1入力を「S100」という名前にする。
21 S1000 Alias Pina.1 PA1入力を「S1000」という名前にする。
22 S10000 Alias Pina.0 PA0入力を「S10000」という名前にする。
23 S100000 Alias Pind.2 PD2入力を「S100000」という名前にする。
24 S1000000 Alias Pind.3 PD3入力を「S1000000」という名前にする。
25 Call Datashift サブルーチン「Datashift」を実行する。
26
27 Do Doループの範囲ここから。
28  Debounce A , 0 , Encode , Sub 「A=0」になったらサブルーチン「Encode」を実行する。
29 Loop Doループの範囲ここまで。
30
31 End メインプログラム終わり。
32
33 Sub Encode サブルーチン「Encode」ここから。
34  If B = 1 Then 条件分岐A。「B=1」(右回転)ならば、
35   Incr F 変数「F」に1を加える。
36   If S10 = 0 Then F = F + 9 条件分岐B1。「S10=0」なら「F」に9を加える。
37   If S100 = 0 Then F = F + 99 条件分岐B2。「S100=0」なら「F」に99を加える。
38   If S1000 = 0 Then F = F + 999 条件分岐B3。「S1000=0」なら「F」に999を加える。
39   If S10000 = 0 Then F = F + 9999 条件分岐B4。「S10000=0」なら「F」に9999を加える。
40   If S100000 = 0 Then F = F + 99999 条件分岐B5。「S100000=0」なら「F」に99999を加える。
41   If S1000000 = 0 Then F = F + 999999 条件分岐B6。「S1000000=0」なら「F」に999999を加える。
42   If F > 10000000 Then F = 10000000 条件分岐B7。「F>10000000」なら「F=10000000」にする。
43   Call Datashift サブルーチン「Datashift」を実行する。
44  Else 「B=0」(左回転)ならば、
45   Decr F 変数「F」から1を引く。
46   If S10 = 0 Then F = F - 9 条件分岐C1。「S10=0」なら「F」から9を引く。
47   If S100 = 0 Then F = F - 99 条件分岐C2。「S100=0」なら「F」から99を引く。
48   If S1000 = 0 Then F = F - 999 条件分岐C3。「S1000=0」なら「F」から999を引く。
49   If S10000 = 0 Then F = F - 9999 条件分岐C4。「S10000=0」なら「F」から9999を引く。
50   If S100000 = 0 Then F = F - 99999 条件分岐C5。「S100000=0」なら「F」から99999を引く。
51   If S1000000 = 0 Then F = F - 999999 条件分岐C6。「S1000000=0」なら「F」から999999を引く。
52   If F < 0 Then F = 0 条件分岐C7。「F」が負になったら「F=0」とする。
53   Call Datashift サブルーチン「Datashift」を実行する。
54  End If 条件分岐Aここまで。
55 End Sub サブルーチン「Encode」ここまで。
56
57 Sub Datashift サブルーチン「Datashift」ここから。
58  Set Portd.4 PD4 (STB出力) を「1」にする。
59  Shiftout Portd.5 , Portd.6 , C , 3 , 7 変数「C」のデータ (7ビット) を送る。
60  Shiftout Portd.5 , Portd.6 , F , 3 , 26 変数「F」のデータ (26ビット) を送る。
61  Reset Portd.4 PD4 (STB出力) を「0」にする。
62  Set Portd.4 PD4 (STB出力) を「1」にする。
63 End Sub サブルーチン「Datashift」ここまで。

3. LCD画面に周波数とステップを表示する

 LCD・液晶ディスプレイの画面に出力周波数と周波数の切り替えステップを表示するプログラムをやってみました。プログラムが長くなりすぎるので、早送りモードは1Hz, 10Hz, 100Hz, 1kHzの4種類だけにしました。回路図は下記の通りです。

 第3図

 ブレッドボード上の配線図と試作写真を下に掲げます。早送りスイッチは10Hzにセットした状態です。

図4 写真1

 第5図

 プログラムは下記の通りです。ステップの表示用に「S」という変数を新たに用いました。ステップを切り替えてロータリーエンコーダを回した時点で「S」の値も変化します。変数「S」あるいは「F」が変化するたび、サブルーチン「Lcdisplay」でLCD画面に周波数とステップを表示し、サブルーチン「Datashift」でDDSにデータを送信します。周波数は変数「F」の値をそのまま表示しています。

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

1 $regfile = "attiny2313.dat" ATtiny2313を使用する。
2 $crystal = 1000000 クロック周波数を1MHzに設定。
3
4 Config Portb = &B11111100 PB0, PB1は入力、PB2〜PB7は出力。
5 Config Portd = &B1110000 PD0〜PD3は入力、PD4〜PD6は出力。
6 Config Lcdpin=Pin, Db4=Portb.5, Db5=Portb.4 LCDの接続設定。DB4=PB5, DB5=PB4。
7 Config Lcdpin=Pin, Db6=Portb.3, Db7=Portb.2 LCDの接続設定。DB6=PB3, DB7=PB2。
8 Config Lcdpin=Pin, E=Portb.6, Rs=Portb.7 LCDの接続設定。E=PB6, RS=PB7。
9 Config Lcd = 16 * 2 16文字x2行のLCDを使用する。
10 Cls : Cursor Off LCDの表示を消去。カーソル非表示。
11 Config Debounce = 1 デバウンス時間を1mSとする。
12 Declare Sub Encode サブルーチン「Encode」を使用。
13 Declare Sub Lcdisplay サブルーチン「Lcdisplay」を使用。
14 Declare Sub Datashift サブルーチン「Datashift」を使用。
15 Dim C As Byte バイト型変数「C」を使用する。
16 Dim F As Long ロング型変数「F」を使用する。
17 Dim S As Integer インテジャー型変数「S」を使用する。
18 C = &B1100111 「C」の値を「1100111」(2進数)にする。
19 F = 1000 「F」の値を「1000」(10進数)にする。
20 S = 1 「S」の値を「1」(10進数)にする。
21 Portb = 3 PB0, PB1をプルアップする。
22 Portd = 15 PD0〜PD3をプルアップする。
23 A Alias Pinb.0 PB0入力を「A」という名前にする。
24 B Alias Pinb.1 PB1入力を「B」という名前にする。
25 S10 Alias Pind.0 PD0入力を「S10」という名前にする。
26 S100 Alias Pind.1 PD1入力を「S100」という名前にする。
27 S1000 Alias Pind.2 PD2入力を「S1000」という名前にする。
28 Call Lcdisplay サブルーチン「Lcdisplay」を実行。
29 Call Datashift サブルーチン「Datashift」を実行。
30
31 Do Doループの範囲ここから。
32  Debounce A , 0 , Encode , Sub 「A=0」になったらサブルーチン「Encode」へ。
33 Loop Doループの範囲ここまで。
34
35 End メインプログラム終わり。
36
37 Sub Encode サブルーチン「Encode」ここから。
38  If B = 1 Then 条件分岐A。「B=1」(右回転)ならば、
39   Incr F 変数「F」に1を加える。
40   S = 1 「S」を「1」にする。
41   If S10 = 0 Then 条件分岐B1。「S10=0」ならば、
42   F = F + 9 : S = 10 「F」に9を加える。「S」を「10」にする。
43   End If 条件分岐B1ここまで。
44   If S100 = 0 Then 条件分岐B2。「S100=0」ならば、
45   F = F + 99 : S = 100 「F」に99を加える。「S」を「100」にする。
46   End If 条件分岐B2ここまで。
47   If S1000 = 0 Then 条件分岐B3。「S1000=0」ならば、
48   F = F + 999 : S = 1000 「F」に999を加える。「S」を「1000」にする。
49   End If 条件分岐B3ここまで。
50   If F > 10000 Then F = 10000 条件分岐B4。「F」の上限を「10000」にする。
51   Call Lcdisplay サブルーチン「Lcdisplay」を実行する。
52   Call Datashift サブルーチン「Datashift」を実行する。
53  Else 「B=0」(左回転)ならば、
54   Decr F 変数「F」から1を引く。
55   S = 1 「S」を「1」にする。
56   If S10 = 0 Then 条件分岐C1。「S10=0」ならば、
57   F = F - 9 : S = 10 「F」から9を引く。「S」を「10」にする。
58   End If 条件分岐C1ここまで。
59   If S100 = 0 Then 条件分岐C2。「S100=0」ならば、
60   F = F - 99 : S = 100 「F」から99を引く。「S」を「100」にする。
61   End If 条件分岐C2ここまで。
62   If S1000 = 0 Then 条件分岐C3。「S1000=0」ならば、
63   F = F - 999 : S = 1000 「F」から999を引く。「S」を「1000」にする。
64   End If 条件分岐C3ここまで。
65   If F < 0 Then F = 0 条件分岐C4。「F」の下限を「0」にする。
66   Call Lcdisplay サブルーチン「Lcdisplay」を実行する。
67   Call Datashift サブルーチン「Datashift」を実行する。
68  End If 条件分岐Aここまで。
69 End Sub サブルーチン「Encode」ここまで。
70
71 Sub Lcdisplay サブルーチン「Lcdisplay」ここから。
72  Cls LCDの表示を消去する。
73  Lcd "FREQ " ; F ; "Hz" LCDに「F」の値(周波数)を表示する。
74  Lowerline LCDの下の行に、
75  Lcd "STEP " ; S ; "Hz" 「S」の値(ステップ)を表示する。
76 End Sub サブルーチン「Lcdisplay」ここまで。
77
78 Sub Datashift サブルーチン「Datashift」ここから。
79  Set Portd.4 PD4 (STB出力) を「1」にする。
80  Shiftout Portd.5 , Portd.6 , C , 3 , 7 変数「C」のデータ (7ビット) を送る。
81  Shiftout Portd.5 , Portd.6 , F , 3 , 26 変数「F」のデータ (26ビット) を送る。
82  Reset Portd.4 PD4 (STB出力) を「0」にする。
83  Set Portd.4 PD4 (STB出力) を「1」にする。
84 End Sub サブルーチン「Datashift」ここまで。