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」ここまで。 |