7セグメントLEDのダイナミック点灯に関して、JN3XBY氏のブログ「1000円で始めるハムのためのAVRマイコン入門」で、タイマー割込みを使う方法があることを知りました。これが普通のやり方なのかもしれません。私もちょっとやってみました。
LEDの表示が000から001, 002, 003... と、約0.5秒ごとに999までカウントアップしていくプログラムです。「(その1)」の「7seg1e.bas」と同じ動作です。回路図を下記に示します。Timer0とTimer1のオーバーフロー割込みを使うので、ICはATtiny2313を用いました。クロックは内蔵RC発振 (1MHz) です。
ブレッドボード上の配線図と試作写真を下に掲げます。
プログラムは下記の通りです。LEDの点灯桁を切り替えるのにTimer0割り込み、カウントアップのタイミングを計るのにTimer1割込みを使っています。
プログラムファイル 7seg3a.bas
1 | $regfile = "attiny2313.dat" | ATtiny2313を使用する。 | |
2 | $crystal = 1000000 | クロック周波数を1MHzに設定。 | |
3 | |||
4 | Config Portb = Output | ポートBを出力に設定する。 | |
5 | Config Portd = Output | ポートDを出力に設定する。 | |
6 | Config Timer0 = Timer , Prescale = 8 | Timer0をタイマーとして使用。分周比は8。 | |
7 | Config Timer1 = Timer , Prescale = 8 | Timer1をタイマーとして使用。分周比は8。 | |
8 | On Timer0 Timer0_int | Timer0割込みルーチンは「Timer0_int」。 | |
9 | On Timer1 Timer1_int | Timer1割込みルーチンは「Timer1_int」。 | |
10 | Declare Sub Lednumber | サブルーチン「Lednumber」を使用する。 | |
11 | Dim N0 As Word | ワード型変数「N0」を使用する | |
12 | Dim N1 As Word | ワード型変数「N1」を使用する。 | |
13 | Dim N2 As Word | ワード型変数「N2」を使用する。 | |
14 | Dim N3 As Word | ワード型変数「N3」を使用する。 | |
15 | Dim M As Word | ワード型変数「M」を使用する。 | |
16 | Dim D As Byte | バイト型変数「D」を使用する。 | |
17 | Dim LED(10) As Byte | バイト型変数「LED」(値は10個)を使用する。 | |
18 | |||
19 | Led(1) = 63 | 変数「LED」の1番目の値は「63」(「0」の表示用)。 | |
20 | Led(2) = 6 | 変数「LED」の2番目の値は「6」(「1」の表示用)。 | |
21 | Led(3) = 91 | 変数「LED」の3番目の値は「91」(「2」の表示用)。 | |
22 | Led(4) = 79 | 変数「LED」の4番目の値は「79」(「3」の表示用)。 | |
23 | Led(5) = 102 | 変数「LED」の5番目の値は「102」(「4」の表示用)。 | |
24 | Led(6) = 109 | 変数「LED」の6番目の値は「109」(「5」の表示用)。 | |
25 | Led(7) = 125 | 変数「LED」の7番目の値は「125」(「6」の表示用)。 | |
26 | Led(8) = 7 | 変数「LED」の8番目の値は「7」(「7」の表示用)。 | |
27 | Led(9) = 127 | 変数「LED」の9番目の値は「127」(「8」の表示用)。 | |
28 | Led(10) = 111 | 変数「LED」の10番目の値は「111」(「9」の表示用)。 | |
29 | Enable Interrupts | 割込み全般を許可する。 | |
30 | Enable Timer0 | Timer0割込みを許可する。 | |
31 | Enable Timer1 | Timer1割込みを許可する。 | |
32 | |||
33 | Do | Doループここから。 | |
34 | Call Lednumber | サブルーチン「Lednumber」を実行する。 | |
35 | If D = 1 Then | 条件分岐1。「D=1」ならば、 | |
36 | Portd = 16 | PD4を「1」にする。DIG1が点灯。 | |
37 | Portb = Led(n1) | 変数「LED」の「N1」番目の値をポートBに出力。 | |
38 | End If | 条件分岐1ここまで。 | |
39 | If D = 2 Then | 条件分岐2。「D=2」ならば、 | |
40 | Portd = 32 | PD5を「1」にする。DIG2が点灯。 | |
41 | Portb = Led(n2) | 変数「LED」の「N2」番目の値をポートBに出力。 | |
42 | End If | 条件分岐2ここまで。 | |
43 | If D = 3 Then | 条件分岐3。「D=3」ならば、 | |
44 | Portd = 64 | PD6を「1」にする。DIG3が点灯。 | |
45 | Portb = Led(n3) | 変数「LED」の「N3」番目の値をポートBに出力。 | |
46 | End If | 条件分岐3ここまで。 | |
47 | Loop | Doループここまで。 | |
48 | |||
49 | End | メインプログラム終わり。 | |
50 | |||
51 | Timer0_int: | サブルーチン「Timer0_int」ここから。 | |
52 | Incr D | 変数「D」の値を1増やす。 | |
53 | If D > 3 Then D = 1 | 「D」が「3」を超えたら「1」に戻す。 | |
54 | Return | サブルーチン「Timer0_int」ここまで。 | |
55 | |||
56 | Timer1_int: | サブルーチン「Timer1_int」ここから。 | |
57 | Incr N0 | 変数「N0」の値を1増やす。 | |
58 | If N0 > 999 Then N0 = 0 | 「N0」が「999」を超えたら「0」に戻す。 | |
59 | Return | サブルーチン「Timer1_int」ここまで。 | |
60 | |||
61 | Sub Lednumber | サブルーチン「Lednumber」ここから。 | |
62 | N3 = N0 ⁄ 100 | 「N0÷100」の商(整数部分)を「N3」とする。 | |
63 | M = N0 Mod 100 | 「N0÷100」の余りを「M」とする。 | |
64 | N2 = M ⁄ 10 | 「M÷10」の商(整数部分)を「N2」とする。 | |
65 | N1 = M Mod 10 | 「M÷10」の余りを「N1」とする。 | |
66 | N3 = N3 + 1 | 「N3+1」を新たな「N3」とする。 | |
67 | N2 = N2 + 1 | 「N2+1」を新たな「N2」とする。 | |
68 | N1 = N1 + 1 | 「N1+1」を新たな「N1」とする。 | |
69 | End Sub | サブルーチン「Lednumber」ここまで。 |
マイコンICのクロック周波数は1MHz、Timer0の分周比は「8」なので (6行目)、Timer0の1カウントの長さは8μSです。Timer0は256カウントごとにオーバーフロー割込みが起きます。8μSを256倍すると約2mSですので、2mSごとに51行目からのサブルーチン「Timer0_int」が実行され、変数「D」の値が1→2→3→1...というふうに変化します。これによってLEDの表示桁を切り替えます。
Timer1の分周比も「8」なので (7行目)、1カウントの長さは同じく8μSですが、Timer1割り込みは65536カウントごとに起きます。8×65536=524288、つまり約0.5秒ごとに割り込みが発生し、56行目からのサブルーチン「Timer1_int」が実行されます。ここでLEDのカウント用の変数「N0」が1ずつ増えます。あとはこれまでのプログラムと同じようにサブルーチン「Lednumber」で各桁の数字を計算して表示します。
押しボタンスイッチを1回押すたびにカウントが1ずつアップするプログラムです。回路図は下記の通りです。PA0〜GND間に押しボタンスイッチをつなぎます。
プログラムは下記の通りです。ポートAを入力に設定します。メインプログラム内でスイッチの状態を監視し、スイッチが押されればサブルーチン「Switch」へ飛んで変数「N0」を1増やします。表示桁の切り替えにTimer0割込みを使うところは上のプログラムと同じです。
プログラムファイル 7seg3b.bas
1 | $regfile = "attiny2313.dat" | ATtiny2313を使用する。 | |
2 | $crystal = 1000000 | クロック周波数を1MHzに設定。 | |
3 | |||
4 | Config Porta = Input | ポートAを入力に設定する。 | |
5 | Config Portb = Output | ポートBを出力に設定する。 | |
6 | Config Portd = Output | ポートDを出力に設定する。 | |
7 | Config Timer0 = Timer , Prescale = 8 | Timer0をタイマーとして使用。分周比は8。 | |
8 | Config Debounce = 1 | デバウンス時間を1mSとする。 | |
9 | On Timer0 Timer0_int | Timer0割込みルーチンは「Timer0_int」。 | |
10 | Declare Sub Switch | サブルーチン「Switch」を使用する。 | |
11 | Declare Sub Lednumber | サブルーチン「Lednumber」を使用する。 | |
12 | Dim N0 As Word | ワード型変数「N0」を使用する | |
13 | Dim N1 As Word | ワード型変数「N1」を使用する。 | |
14 | Dim N2 As Word | ワード型変数「N2」を使用する。 | |
15 | Dim N3 As Word | ワード型変数「N3」を使用する。 | |
16 | Dim M As Word | ワード型変数「M」を使用する。 | |
17 | Dim D As Byte | バイト型変数「D」を使用する。 | |
18 | Dim LED(10) As Byte | バイト型変数「LED」(値は10個)を使用する。 | |
19 | |||
20 | Porta = 3 | PA0, PA1をプルアップする。 | |
21 | Led(1) = 63 | 変数「LED」の1番目の値は「63」(「0」の表示用)。 | |
22 | Led(2) = 6 | 変数「LED」の2番目の値は「6」(「1」の表示用)。 | |
23 | Led(3) = 91 | 変数「LED」の3番目の値は「91」(「2」の表示用)。 | |
24 | Led(4) = 79 | 変数「LED」の4番目の値は「79」(「3」の表示用)。 | |
25 | Led(5) = 102 | 変数「LED」の5番目の値は「102」(「4」の表示用)。 | |
26 | Led(6) = 109 | 変数「LED」の6番目の値は「109」(「5」の表示用)。 | |
27 | Led(7) = 125 | 変数「LED」の7番目の値は「125」(「6」の表示用)。 | |
28 | Led(8) = 7 | 変数「LED」の8番目の値は「7」(「7」の表示用)。 | |
29 | Led(9) = 127 | 変数「LED」の9番目の値は「127」(「8」の表示用)。 | |
30 | Led(10) = 111 | 変数「LED」の10番目の値は「111」(「9」の表示用)。 | |
31 | Enable Interrupts | 割込み全般を許可する。 | |
32 | Enable Timer0 | Timer0割込みを許可する。 | |
33 | |||
34 | Do | Doループここから。 | |
35 | Debounce Pina.0, 0, Switch, Sub | 「Pina.0=0」になったらサブルーチン「Switch」へ。 | |
36 | Call Lednumber | サブルーチン「Lednumber」を実行する。 | |
37 | If D = 1 Then | 条件分岐1。「D=1」ならば、 | |
38 | Portd = 16 | PD4を「1」にする。DIG1が点灯。 | |
39 | Portb = Led(n1) | 変数「LED」の「N1」番目の値をポートBに出力。 | |
40 | End If | 条件分岐1ここまで。 | |
41 | If D = 2 Then | 条件分岐2。「D=2」ならば、 | |
42 | Portd = 32 | PD5を「1」にする。DIG2が点灯。 | |
43 | Portb = Led(n2) | 変数「LED」の「N2」番目の値をポートBに出力。 | |
44 | End If | 条件分岐2ここまで。 | |
45 | If D = 3 Then | 条件分岐3。「D=3」ならば、 | |
46 | Portd = 64 | PD6を「1」にする。DIG3が点灯。 | |
47 | Portb = Led(n3) | 変数「LED」の「N3」番目の値をポートBに出力。 | |
48 | End If | 条件分岐3ここまで。 | |
49 | Loop | Doループここまで。 | |
50 | |||
51 | End | メインプログラム終わり。 | |
52 | |||
53 | Timer0_int: | サブルーチン「Timer0_int」ここから。 | |
54 | Incr D | 変数「D」の値を1増やす。 | |
55 | If D > 3 Then D = 1 | 「D」が「3」を超えたら「1」に戻す。 | |
56 | Return | サブルーチン「Timer0_int」ここまで。 | |
57 | |||
58 | Sub Switch | サブルーチン「Switch」ここから。 | |
59 | Incr N0 | 変数「N0」の値を1増やす。 | |
60 | If N0 > 999 Then N0 = 0 | 「N0」が「999」を超えたら「0」に戻す。 | |
61 | End Sub | サブルーチン「Switch」ここまで。 | |
62 | |||
63 | Sub Lednumber | サブルーチン「Lednumber」ここから。 | |
64 | N3 = N0 ⁄ 100 | 「N0÷100」の商(整数部分)を「N3」とする。 | |
65 | M = N0 Mod 100 | 「N0÷100」の余りを「M」とする。 | |
66 | N2 = M ⁄ 10 | 「M÷10」の商(整数部分)を「N2」とする。 | |
67 | N1 = M Mod 10 | 「M÷10」の余りを「N1」とする。 | |
68 | N3 = N3 + 1 | 「N3+1」を新たな「N3」とする。 | |
69 | N2 = N2 + 1 | 「N2+1」を新たな「N2」とする。 | |
70 | N1 = N1 + 1 | 「N1+1」を新たな「N1」とする。 | |
71 | End Sub | サブルーチン「Lednumber」ここまで。 |
ロータリーエンコーダを回すと数字が増えたり減ったりするプログラムです。回路図は下記の通りです。ポートAにロータリーエンコーダをつなぎました。
プログラムは下記の通りです。メインプログラム内に「Wait」命令がないので、回転の検出ミスはほとんど生じないと思います。こちらの方がスマートなやり方のように感じます。
プログラムファイル 7seg3c.bas
1 | $regfile = "attiny2313.dat" | ATtiny2313を使用する。 | |
2 | $crystal = 1000000 | クロック周波数を1MHzに設定。 | |
3 | |||
4 | Config Porta = Input | ポートAを入力に設定する。 | |
5 | Config Portb = Output | ポートBを出力に設定する。 | |
6 | Config Portd = Output | ポートDを出力に設定する。 | |
7 | Config Timer0 = Timer , Prescale = 8 | Timer0をタイマーとして使用。分周比は8。 | |
8 | Config Debounce = 1 | デバウンス時間を1mSとする。 | |
9 | On Timer0 Timer0_int | Timer0割込みルーチンは「Timer0_int」。 | |
10 | Declare Sub Encode | サブルーチン「Encode」を使用する。 | |
11 | Declare Sub Lednumber | サブルーチン「Lednumber」を使用する。 | |
12 | Dim N0 As Word | ワード型変数「N0」を使用する | |
13 | Dim N1 As Word | ワード型変数「N1」を使用する。 | |
14 | Dim N2 As Word | ワード型変数「N2」を使用する。 | |
15 | Dim N3 As Word | ワード型変数「N3」を使用する。 | |
16 | Dim M As Word | ワード型変数「M」を使用する。 | |
17 | Dim D As Byte | バイト型変数「D」を使用する。 | |
18 | Dim LED(10) As Byte | バイト型変数「LED」(値は10個)を使用する。 | |
19 | A Alias Pina.1 | PA1入力を「A」という名前にする。 | |
20 | B Alias Pina.0 | PA0入力を「B」という名前にする。 | |
21 | |||
22 | Porta = 3 | PA0, PA1をプルアップする。 | |
23 | Led(1) = 63 | 変数「LED」の1番目の値は「63」(「0」の表示用)。 | |
24 | Led(2) = 6 | 変数「LED」の2番目の値は「6」(「1」の表示用)。 | |
25 | Led(3) = 91 | 変数「LED」の3番目の値は「91」(「2」の表示用)。 | |
26 | Led(4) = 79 | 変数「LED」の4番目の値は「79」(「3」の表示用)。 | |
27 | Led(5) = 102 | 変数「LED」の5番目の値は「102」(「4」の表示用)。 | |
28 | Led(6) = 109 | 変数「LED」の6番目の値は「109」(「5」の表示用)。 | |
29 | Led(7) = 125 | 変数「LED」の7番目の値は「125」(「6」の表示用)。 | |
30 | Led(8) = 7 | 変数「LED」の8番目の値は「7」(「7」の表示用)。 | |
31 | Led(9) = 127 | 変数「LED」の9番目の値は「127」(「8」の表示用)。 | |
32 | Led(10) = 111 | 変数「LED」の10番目の値は「111」(「9」の表示用)。 | |
33 | Enable Interrupts | 割込み全般を許可する。 | |
34 | Enable Timer0 | Timer0割込みを許可する。 | |
35 | |||
36 | Do | Doループここから。 | |
37 | Debounce A, 0, Encode, Sub | 「A=0」になったらサブルーチン「Encode」へ。 | |
38 | Call Lednumber | サブルーチン「Lednumber」を実行する。 | |
39 | If D = 1 Then | 条件分岐1。「D=1」ならば、 | |
40 | Portd = 16 | PD4を「1」にする。DIG1が点灯。 | |
41 | Portb = Led(n1) | 変数「LED」の「N1」番目の値をポートBに出力。 | |
42 | End If | 条件分岐1ここまで。 | |
43 | If D = 2 Then | 条件分岐2。「D=2」ならば、 | |
44 | Portd = 32 | PD5を「1」にする。DIG2が点灯。 | |
45 | Portb = Led(n2) | 変数「LED」の「N2」番目の値をポートBに出力。 | |
46 | End If | 条件分岐2ここまで。 | |
47 | If D = 3 Then | 条件分岐3。「D=3」ならば、 | |
48 | Portd = 64 | PD6を「1」にする。DIG3が点灯。 | |
49 | Portb = Led(n3) | 変数「LED」の「N3」番目の値をポートBに出力。 | |
50 | End If | 条件分岐3ここまで。 | |
51 | Loop | Doループここまで。 | |
52 | |||
53 | End | メインプログラム終わり。 | |
54 | |||
55 | Timer0_int: | サブルーチン「Timer0_int」ここから。 | |
56 | Incr D | 変数「D」の値を1増やす。 | |
57 | If D > 3 Then D = 1 | 「D」が「3」を超えたら「1」に戻す。 | |
58 | Return | サブルーチン「Timer0_int」ここまで。 | |
59 | |||
60 | Sub Encode | サブルーチン「Encode」ここから。 | |
61 | If B = 1 Then | 条件分岐4。「B=1」(右回転) ならば、 | |
62 | Incr N0 | 「N0」の値を1増やす。 | |
63 | If N0 > 999 Then N0 = 999 | 「N0」の最大値を「999」とする。 | |
64 | End If | 条件分岐4ここまで。 | |
65 | If B = 0 Then | 条件分岐5。「B=0」(左回転) ならば、 | |
66 | Decr N0 | 「N0」の値を1減らす。 | |
67 | If N0 < 0 Then N0 = 0 | 「N0」の最小値を「0」とする。 | |
68 | End If | 条件分岐5ここまで。 | |
69 | End Sub | サブルーチン「Encode」ここまで。 | |
70 | |||
71 | Sub Lednumber | サブルーチン「Lednumber」ここから。 | |
72 | N3 = N0 ⁄ 100 | 「N0÷100」の商(整数部分)を「N3」とする。 | |
73 | M = N0 Mod 100 | 「N0÷100」の余りを「M」とする。 | |
74 | N2 = M ⁄ 10 | 「M÷10」の商(整数部分)を「N2」とする。 | |
75 | N1 = M Mod 10 | 「M÷10」の余りを「N1」とする。 | |
76 | N3 = N3 + 1 | 「N3+1」を新たな「N3」とする。 | |
77 | N2 = N2 + 1 | 「N2+1」を新たな「N2」とする。 | |
78 | N1 = N1 + 1 | 「N1+1」を新たな「N1」とする。 | |
79 | End Sub | サブルーチン「Lednumber」ここまで。 |