2002.11.27-

AVRマイコンで学ぶ コンピュータの仕組み

小山智史(弘前大学)
目次



1. ブレッドボードの利用
2. プログラム開発の手順
3. コンピュータの動作
4. プログラミング 1 (LEDを点灯・消灯する)
5. プログラミング 2 (LEDを点滅させる)
6. プログラミング 3 (トーンを鳴らす)
7. プログラミング 4 (LEDの明るさを変える)
8. プログラミング 5 (数字を表示する)
9. 外部回路の制御

(付録1) 使用する主な部品
(付録2) AVRライタ
(付録3) バッチプログラムの内容
(付録4) コマンドプロンプトでの操作
(付録5) マクロ定義とマクロ展開
(付録6) ATtiny2313の主な命令
(付録7) AVRマイコンを使ったものづくりの例

 私達の身近にある家電機器の多くにコンピュータが内蔵されており、このようなコンピュータは「マイコン」と呼ばれます。マイクロコンピュータあるいはマイクロコントローラの略です。マイコンにはメーカーが開発したプログラムが書き込まれています。リモコンであれば、押したボタンに応じて決まったパターンで赤外線をオンオフするプログラムが書き込まれています。このプログラムは製造時に書き込まれ、後から書き換えることはできませんが、フラッシュメモリ(電気的に書き換え可能なプログラムメモリ)を搭載したマイコンを使えば、私達もさまざまな機器を作ることができます。

 マイコンを使った機器を設計・製作するには、電子回路、論理回路、コンピュータの仕組み、プログラミングなど広範囲の知識が要求されます。これは大変なことではありますが、一方ではこれらのことを学ぶ格好の教材であるということを意味しています。

 このテキストでは、AVRマイコンを使った実習を行いながら、主にコンピュータの内部動作について学習します。理解を深めていただきたい箇所は3章です。ATtiny2313のマニュアル(英文)[1](1〜14ページ, 211〜214ページ, および必要に応じて他のページ)を読みながら学習を進めます。

 4章〜8章はプログラミングを扱っています。プログラミングについて本格的に学ぶというよりも、原始的な命令を組み合わせて、条件分岐や繰り返しなどの処理がどのように行われるのかを見ていきます。更に、さまざまな「ものづくり」に発展させたいという方は、9章や「Arduino風パソコン制御とマイコン制御」[2]を参考にしてください。最近話題のArduinoを用いる場合にも、このテキストで学習した内容は役立つのではないかと思います。

 ここでは複雑な電子回路は登場していませんが、電気回路の最低限の知識は前提としています。自信の無い方は[3]を参考にしてください。なお、このテキストは実習時に適宜解説や補足を行うことを前提にしています。自学自習には適していないかもしれません。

1. ブレッドボードの利用

 私自身ブレッドボードを使うようになったのは、つい最近のことです。半田付けをしないでさまざまなモノを作ることができるので、実習用に適していると実感しています。ブレッドボードを使ったことがある方は、この章を読み飛ばして構いません。

1.1 ブレッドボード

 ここでは下図左のブレッドボードを使います(秋月 EIC-301)。ボードの内部は下図右のように接続されています。

(概観)(内部の接続)

1.2 ブレッドボードの練習 1(LEDの点灯)

 電子工作の第一歩として、下図左の回路図を組み立ててみましょう。実際の配線は下図右のようになります。これを実体配線図と言います。なお、結線用のワイヤは「ブレッドボード・ジャンパーワイヤ15cm(秋月)」を使います。

(回路図)(実体配線図)

LEDは点灯しましたか? 下の写真は実際の様子です。


(12cm×5cm 程の板を用意し、ブレッドボードと電池ケースを貼りつけています。)

 ここで、ブレッドボード内部の接続を念頭に、下図のような電流の流れをイメージすることが重要です。LEDは電流が流れるから点灯するのです。

1.3 ブレッドボードの練習 2(スイッチ操作によるLEDの点灯)

 それでは、下図のように押しボタンスイッチを追加し、スイッチを押すとLEDが点灯するようにしてみましょう。スイッチを押すと電流が流れるわけですが、ここでも「電流が流れる経路」を(ブレッドボードの内部結線を含めて)イメージしてください。

(回路図)(実体配線図)

1.4 AVRマイコンの接続

 それでは次章以降の準備として、AVRマイコンを接続してみましょう。電池のスイッチは切り、AVRマイコンの向きに気を付けて差し込んでください。

(回路図)(実体配線図)


2. プログラム開発の手順

2.1 準備

  1. ここでは、HIDaspxというAVRライタを用います(ライタソフトはHIDspx)。他のライタを使用する場合は適宜読み替えてください。

  2. avrdevフォルダには以下のファイルが入っています。

    ファイル名内容
    prog.asmソースプログラム(サンプル)
    prog.cソースプログラム(サンプル)
    tn2313def.incアセンブラ用マイコン定義ファイル
    avra.batアセンブルバッチコマンド(付録3)
    avrc.batCコンパイルバッチコマンド(付録3)
    avrw.batライタバッチコマンド(HIDaspx用)(付録3)
    avrwp.batライタバッチコマンド(ヒダピオ用)(付録3)
    toolsフォルダ AVRアセンブラavrasm32.exe[1]
    ライタソフトHIDspx.exe[4]
    ※ C言語のプログラミングを行う場合は、上記の他にWinAVR-20100110[5]を別途インストールします。

  3. ショートカットの作成

    (1) avra.batのショートカットを作成し、名前を「アセンブル」にします。

    操作の説明図

    (2) avrc.batのショートカットを作成し、名前を「Cコンパイル」にします。

    操作の説明図

    (3) ライタにHIDaspx[4]を用いる場合はavrw.bat、ヒダピオ(付録2)を用いる場合はavrwp.batのショートカットを作成し、名前を「書き込み」にします。

    操作の説明図

2.2 回路の組み立て

 プログラムは回路と密接に関係しています。例えば、LEDをマイコンのどのピンに接続するかでプログラムは変わってきます。ここから先の実習を行うにあたり、以下の回路を組み立ててください。以降のプログラムはこの回路を前提としています。

(回路図)(実体配線図)

2.3 アセンブラプログラムから機械語への変換(アセンブル)

(1)メモ帳などでソースプログラムを作成・編集します。ここではprog.asmというファイル名とします。

prog.asmをメモ帳で編集

(2)ソースプログラム(prog.asm)を「アセンブル」にドラッグ&ドロップすると、リストファイル(list.txt)と機械語ファイル(prog.hex)が作られます。

アセンブル操作

 下図はリストファイル(list.txt)をメモ帳で開いた様子です。

list.txtをメモ帳で見る

リストファイルを見ることにより、ソースプログラムがどのような機械語プログラムに変換されるかがわかります。例えば、「LDI R16,0b00001000」は機械語「e008H」に変換されます。

 コンピュータのプログラム領域(Program Flash)に書き込む機械語のみをファイルにしたものが機械語ファイル(prog.hex)で、下図はこれをメモ帳で開いた様子です。

prog.hexをメモ帳で見る

 機械語ファイルの書式は次のようになっています。

2.4 Cプログラムから機械語への変換(コンパイル)

(1)メモ帳などでソースプログラムを作成・編集します。ここではprog.cというファイル名とします。

prog.cをメモ帳で編集

(2)ソースプログラム(ここではprog.c)を「Cコンパイル」にドラッグ&ドロップすると、リストファイル(list.txt)と機械語ファイル(bin.hex)が作られます。

コンパイル操作

 下図はリストファイル(list.txt)をメモ帳で開いた様子です。

list.txtをメモ帳で見る

リストファイルを見ることにより、C言語のソースプログラムがどのようなアセンブラプログラムに変換され、どのような機械語プログラムになるかがわかります。アセンブラプログラムの各行は基本的に機械語プログラムに1対1に対応しますが、C言語(一般に高級言語)のプログラムは、もっと高度な変換が行われています。

 機械語ファイルの書式は既に説明したとおりです。

2.5 AVRマイコンへの機械語プログラムの書き込み

 ここで用いるAVRマイコンは、ISP(In System Programming)可能なもので、マイコンを装置に組み込んだ状態で、マイコン内にプログラムを書き込みできます。

 ブレッドボード上のAVRマイコンにライタを接続し、電池のスイッチを入れます。電源が入っていないと書き込みができないので注意してください。ソースプログラムから変換して作った機械語ファイルprog.hex(C言語の場合はbin.hex)を「書き込み」にドラッグ&ドロップします。書き込み終了と同時に、書き込んだプログラムがスタートします。

 ライタを切り離し、電源スイッチを入れたり切ったりして、確かに単体で動作していることを確認してください。

AVRライタで書き込み中の写真
書き込みのための操作

2.6 機器の開発プロセス

 マイコンを埋めこんだ機器の開発プロセスは以下のようになります。



3. コンピュータの動作

3.1 AVRマイコンの内部構造

 本テキストで使用するATtiny2313の内部構造を下図に示します。

ATtiny2313の内部構造

3.2 プログラムの実行(フェッチ実行サイクル)

 次のソースプログラムからどのような機械語が作られ、その機械語プログラムがコンピュータ内部でどのように動作するかを詳しくみてみます。

 ソースプログラムの1行目はアセンブラに対する制御命令で、ここで用いているATtiny2313に関する情報が定義された「tn2313def.inc」というファイルを読み込みます。

 2行目の「.cseg」はアセンブラに対する制御命令で、以下がプログラムコードであることを宣言しています。

 3行目以降が機械語になるプログラム部分です。

 このソースプログラムは、アセンブラソフト(ATMEL社のavrasm32.exe)を用いてアセンブルすると5ワード(5×16bit)の機械語プログラムとなります。プログラムのどの箇所がどのような機械語になるかは、以下のようにリストファイル(list.txt)で確認できます。

正味の機械語プログラムは で、これに若干の付加情報を付け加えたものが機械語ファイル(prog.hex)です。短いプログラムであれば、アセンブラソフトを用いずに、機械語の一覧表を見ながら人間が機械語プログラムを直接書くこともできます。機械語プログラムは、ライタとライタソフトを用いてコンピュータのプログラムメモリ(Program Flash) 1Kワード($000〜$3FF番地)の先頭部分($000〜$004番地)に書き込まれます(下図参照)。

 それでは、「書き込まれたプログラムから命令が一つずつ取り出されて実行される仕組み」を詳しく見てみましょう。動作の仕組みはどのコンピュータにも共通する基本的な事項ですから、丁寧に見てください。

000000 e008 LDI R16,0b00001000

(1) 電源投入(またはリセット)により、Program Counterの内容が「0000000000」になります。Program Counterの内容はProgram Flashの実行すべきアドレスを表わしています。

(2) Program Counterの内容が指し示すProgram Flashのアドレスの内容「11100000 00001000」がInstruction Register(命令レジスタ)に取り込まれます。この動作はフェッチ(fetch)と呼ばれます(「取ってくる」という意味です)。

(3) Program Counterの内容に1が加えられます。

(4) Instruction Register(命令レジスタ)の内容がInstruction Decoder(命令デコーダ)によってデコードされます。デコードは具体的には、次のように行われます。

1110 0000 0000 1000
LDI命令 代入する値の上位4bit R16R31のうちのR16 代入する値の下位4bit

LDI」は「LoaD Immediate」の略というように、働きが連想できるような名前(符号)が付けられていて、ニーモニックコードと呼ばれます。また、「LDI(および対応する1110)」はOpCode(オペコード)、「R16,0b00001000」はOperand(オペランド)と呼ばれます。「R16(および対応する0000)」は第1オペランド、「0b00001000」は第2オペランドとなります。

(5) デコードの結果を受けて、その命令の実行に必要なタイミング信号が作られ、実行(execute)されます。この場合はレジスタR16の中が「00001000」となります。

 以上の(2)〜(5)は1クロックサイクルで処理されます。1クロックサイクルは0.125μsです。AVRマイコンの場合は、命令を実行(excecute)している間に次の命令をInstruction Register(命令レジスタ)にフェッチ(プリフェッチ)することにより高速化が図られています。

 このように、コンピュータがプログラムを実行する仕組みは、

フェッチ(fetch)
デコード(decode)
実行(execute)

の繰り返しで、フェッチ実行サイクル(fetch-execute cycle)と呼ばれます

フェッチ実行サイクルの説明図

以下は、フェッチと実行(execute)が繰り返される様子を示したものです。

000001 bb07 OUT DDRB,R16

(1) 上記(3)でProgram Counterの内容が「0000000001」となっているので、その値が指し示すProgram Flashのアドレスの内容「10111011 00000111」がInstruction Register(命令レジスタ)に取り込まれます。

(2) Program Counterの内容に1が加えられます。

(3) Instruction Register(命令レジスタ)の内容がInstruction Decoder(命令デコーダ)によってデコードされます。デコードは具体的には次のように行われます。

10111 01 10000 0111
OUT命令 DDRBを表わすIOアドレス
$17(010111)の上位2bit
R0R31のうちのR16 DDRBを表わすIOアドレス
$17(010111)の下位4bit

OUT」は「OUTput」を意味するニーモニックコードです。

(4) デコードの結果を受けて、その命令の実行に必要なタイミング信号が作られ、実行(execute)されます。この場合はDDRBレジスタの内容が「00001000」となります。

 IOポートに直接値を出力する命令が無いために、このように初めの命令でレジスタに値をセットし、次の命令でレジスタの内容をIOポートに出力します。ここで行ったDDRBレジスタの設定は、「PB0〜PB2, PB4〜PB7を入力として使い、PB3を出力として使う」ということを指示するものです。

OUT命令実行の説明図

000002 e008 LDI R16,0b00001000

(1) Program Counterの内容が「0000000010」となっているので、その値が指し示すProgram Flashのアドレスの内容「11100000 00001000」がInstruction Register(命令レジスタ)に取り込まれます。

(2) Program Counterの内容に1が加えられます。

(3) Instruction Register(命令レジスタ)の内容がInstruction Decoder(命令デコーダ)によってデコードされます。デコードは具体的には次のように行われます。

1110 0000 0000 1000
LDI命令 代入する値の上位4bit R16R31のうちのR16 代入する値の下位4bit

(4) デコードの結果を受けて、その命令の実行に必要なタイミング信号が作られ、実行(execute)されます。この場合はレジスタR16の中が「00001000」となります。

LDI命令実行の説明図

000003 bb08 OUT PORTB,R16

(1) Program Counterの内容が「0000000011」となっているので、その値が指し示すProgram Flashのアドレスの内容「10111011 00001000」がInstruction Register(命令レジスタ)に取り込まれます。

(2) Program Counterの内容に1が加えられます。

(3) Instruction Register(命令レジスタ)の内容がInstruction Decoder(命令デコーダ)によってデコードされます。デコードは具体的には次のように行われます。

10111 01 10000 1000
OUT命令 PORTBを表わすIOアドレス
$18(011000)の上位2bit
R0R31のうちのR16 PORTBを表わすIOアドレス
$18(011000)の下位4bit

(4) デコードの結果を受けて、その命令の実行に必要なタイミング信号が作られ、実行(execute)されます。ここではPORTBのbit3(PB3ピン)が1(高い電圧)となり、外部回路のLEDが点灯します。PORTBはレジスタになっているので、一旦値をセットすると保持されます。

OUT命令実行の説明図

000004 cffd RJMP LOOP

(1) Program Counterの内容が「0000000100」となっているので、その値が指し示すProgram Flashのアドレスの内容「11001111 11111101」がInstruction Register(命令レジスタ)に取り込まれます。

(2) Program Counterの内容に1が加えられます。

(3) Instruction Register(命令レジスタ)の内容がInstruction Decoder(命令デコーダ)によってデコードされます。デコードは具体的には次のように行われます。

1100 111111111101
RJMP命令 ジャンプ先の相対アドレスで、2の補数表現の「-3

RJMP」は「Relative JuMP」を意味するニーモニックコードです。

(4) デコードの結果を受けて、その命令の実行に必要なタイミング信号が作られ、実行(execute)されます。通常であれば、この命令実行後のProgram Counterの内容が「0000000101」となるわけですが、相対的に「-3」された「0000000010」がProgram Counterの内容となります。

RJMP命令実行の説明図

■ 以降「LDI R16,0b00001000」「OUT PORTB,R16」「RJMP LOOP」が繰り返されます

(練習) 以下のように、プログラム6行目の「LDI R16,0b00001000」を「LDI R16,0b00000000」に変更し、動作を確認しなさい。これは、PORTBのbit3を1から0に変更するということを意味しています。その結果、プログラムの一連の命令が実行されると、それまで点灯していたLEDが消灯します。

メモ帳を使ってprog.asm中の
LDI R16,0b00001000」を
LDI R16,0b00000000」に変更
prog.asmのアセンブル
prog.hexの書き込み
動作の確認

(練習) PB2にもLEDと抵抗を接続し、
(1)2つのLEDを同時に点灯されるプログラム
(2)一方だけ点灯させるプログラム
を作りなさい。

3.3 プログラムの実行(サブルーチンの呼び出し)

 次のようにLEDを点灯させる正味のプログラムをサブルーチンとして分離し、これを例に、サブルーチンの呼び出しがどのように実行されるかを詳しくみてみます。

 このソースプログラムは、アセンブルすると9ワードの機械語プログラムとなります。プログラムのどの箇所がどのような機械語になるかは、以下のようにリストファイル(list.txt)で確認できます。

正味の機械語プログラムは です。機械語プログラムは、ライタとライタソフトを用いてコンピュータのプログラムメモリ(Program Flash) 1Kワード($000〜$3FF番地)の先頭部分($000〜$008番地)に書き込まれます(下図参照)。

 それでは、プログラムがどのように実行されるかを詳しく見てみましょう。

000000 e008 LDI R16,0b00001000
000001 bb07 OUT DDRB,R16

 先頭の2つの命令は冒頭の例と同様ですので説明は省略します。

000002 ed0f LDI R16,RAMEND

(1) Program Counterの内容が「0000000010」となっているので、その値が指し示すProgram Flashのアドレスの内容「1110110100001111」がInstruction Register(命令レジスタ)に取り込まれます。

(2) Program Counterの内容に1が加えられます。

(3) Instruction Register(命令レジスタ)の内容がInstruction Decoder(命令デコーダ)によってデコードされます。デコードは具体的には次のように行われます。

1110 1101 0000 1111
LDI命令 代入する値の上位4bit R16R31のうちのR16 代入する値の下位4bit

(4) デコードの結果を受けて、R16に「11011111」が代入されます。

000003 bf0d OUT SPL,R16

(1) Program Counterの内容が「0000000011」となっているので、その値が指し示すProgram Flashのアドレスの内容「10111111 00001101」がInstruction Register(命令レジスタ)に取り込まれます。

(2) Program Counterの内容に1が加えられます。

(3) Instruction Register(命令レジスタ)の内容がInstruction Decoder(命令デコーダ)によってデコードされます。デコードは具体的には次のように行われます。

10111 11 10000 1101
OUT命令 SPLを表わすIOアドレス
$3D(111101)の上位2bit
R0R31のうちのR16 SPLを表わすIOアドレス
$3D(111101)の下位4bit

(4) デコードの結果を受けて、SPLレジスタの内容が「11011111」となります。SPLレジスタ(スタックポインタ)の働きについては、次のRCALL命令の箇所で説明します。

OUT命令実行の説明図

000004 d001 RCALL LED

(1) Program Counterの内容が「0000000100」となっているので、その値が指し示すProgram Flashのアドレスの内容「11010000 00000001」がInstruction Register(命令レジスタ)に取り込まれます。

(2) Program Counterの内容に1が加えられます。

(3) Instruction Register(命令レジスタ)の内容がInstruction Decoder(命令デコーダ)によってデコードされます。デコードは具体的には次のように行われます。

1101 0000 0000 0001
RCALL命令 呼び出すサブルーチンの相対アドレスで「1

RCALL」は「Relative CALL」を意味するニーモニックコードです。

(4) 通常であれば、この命令実行後のProgram Counterの内容が「0000000101」となるところですが、相対的に「+1」された「0000000110」がProgram Counterの内容となります。これだけだとRJMP命令と同じですが、RCALL命令の場合は、呼び出し先の末尾に記載されたRET命令で「呼び出した次の番地(この場合は0000000111番地)」に戻る点が異なります。この「戻り番地」はスタック(積み重ね)という方法を使ってSRAMに記憶されています。Stack Pointer(SPL)の値「11011111」が指し示すSRAMの番地に戻るべきProgram Counterの値をしまいます。Program Counterの値(10ビット)を保存するために、SRAMの2バイトを使います。そして、Stack Pointer(SPL)の値を「-2」します。もしもサブルーチンの中で別のサブルーチンを呼び出した場合は、その戻り番地は同じ方法でSRAM中に積み重ね(stack)られます。このような方法で、多重のサブルーチン呼び出し(サブルーチンの中で他のサブルーチンを呼び出すこと)が可能になっているのです。

RCALL命令実行の説明図

000006 e008 LDI R16,0b00001000

(1) Program Counterの内容が「0000000110」となっているので、その値が指し示すProgram Flashのアドレスの内容「11100000 00001000」がInstruction Register(命令レジスタ)に取り込まれます。

(2) Program Counterの内容に1が加えられます。

(3) Instruction Register(命令レジスタ)の内容がInstruction Decoder(命令デコーダ)によってデコードされます。デコードは具体的には次のように行われます。

1110 0000 0000 1000
LDI命令 代入する値の上位4bit R16R31のうちのR16 代入する値の下位4bit

(4) デコードの結果を受けて、その命令の実行に必要なタイミング信号が作られ、実行(execute)されます。この場合はレジスタR16の中が「00001000」となります。

000007 bb08 OUT PORTB,R16

(1) Program Counterの内容が「0000000111」となっているので、その値が指し示すProgram Flashのアドレスの内容「10111011 00001000」がInstruction Register(命令レジスタ)に取り込まれます。

(2) Program Counterの内容に1が加えられます。

(3) Instruction Register(命令レジスタ)の内容がInstruction Decoder(命令デコーダ)によってデコードされます。デコードは具体的には次のように行われます。

10111 01 10000 1000
OUT命令 PORTBを表わすIOアドレス
$18(011000)の上位2bit
R0R31のうちのR16 PORTBを表わすIOアドレス
$18(011000)の下位4bit

(4) デコードの結果を受けて、PORTBのbit3(PB3ピン)が1(高い電圧)となり、外部回路のLEDが点灯します。

CBI命令実行の説明図

000008 9508 RET

(1) Program Counterの内容が「0000001000」となっているので、その値が指し示すProgram Flashのアドレスの内容「10010101 00001000」がInstruction Register(命令レジスタ)に取り込まれます。

(2) Program Counterの内容に1が加えられます。

(3) Instruction Register(命令レジスタ)の内容がInstruction Decoder(命令デコーダ)によってデコードされます。デコードは具体的には次のように行われます。

1001010100001000
RET命令

RET」は「RETurn」を意味するニーモニックコードです。

(4) デコードの結果を受けて、Stack Pointer(SPL)の値「11011101」に「+1」および「+2」した値が指し示すSRAMの番地の内容「0000000111」をProgram Counterにしまいます。つまり、次には7番地の命令が実行されることになります。そして、Stack Pointer(SPL)の値を「+2」します。

RET命令実行の説明図

000005 cffe RJMP LOOP

(1) Program Counterの内容が「0000000101」となっているので、その値が指し示すProgram Flashのアドレスの内容「11001111 11111110」がInstruction Register(命令レジスタ)に取り込まれます。

(2) Program Counterの内容に1が加えられます。

(3) Instruction Register(命令レジスタ)の内容がInstruction Decoder(命令デコーダ)によってデコードされます。デコードは具体的には次のように行われます。

1100 111111111110
RJMP命令 ジャンプ先の相対アドレスで、2の補数表現の「-2」

(4) デコードの結果を受けて、通常であれば、この命令実行後のProgram Counterの内容が「0000000110」となるところ、相対的に「-2」された「0000000100」がProgram Counterの内容となります。

RJMP命令実行の説明図


4. プログラミング 1 (LEDの点灯・消灯)

 前章で、コンピュータが動作する仕組みが理解できたことと思います。4〜8章では原始的な命令を組み合わせて条件分岐や繰り返しの処理がどのように行われるのか、そして、それがどのような応用に結びつくのかを、例題を通して理解してほしいと思います。

4.1 LEDを点灯する

 2章〜3章のはじめで扱った回路は以下のようになっていました。

マイコンの入出力ポートPB0PB7の各ピン(ビット)は以下のようになっています。

  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 機能
PORTB - - - - LED
(1で点灯,
0で消灯)
- - - 入出力ピンに値を出力
DDRB 0 0 0 0 1 0 0 0 入出力の方向設定
PINB - - - - - - - - 入出力ピンの値を入力

 プログラムprog.asmは次のようなものでした。

 初めにDDRB0b00001000を出力しています。これは、PB3を出力、他を入力に設定することを指示しています。

 それぞれの命令は1クロックサイクル(0.125μs)で実行されます。

 「LOOP:」は、「LOOPの箇所に...」のようにアドレスを参照するための「ラベル」です。

 次にPB3(PORTBのビット3)を1にしています。この命令が実行されると、PB3ピンが1(高い電圧)になります。

 次に、「RJMP LOOP」でLOOPのところにジャンプしています。LDI命令とOUT命令は1クロックサイクル、RJMPは2クロックサイクルで実行されますから、計4クロックサイクル 0.5μs周期という超高速で、この部分が繰り返されることになります。

C言語によるプログラム

(練習) LEDの接続をPB3からPD2に変更し、LEDを点灯・消灯させなさい。

4.2 条件分岐: スイッチが押されている時にLEDを点灯する

 条件によってプログラムの流れを変える場合はどうするのかをみてみます。

 スイッチと抵抗を追加し、以下の回路にします。

回路図

 マイコンの入出力ポートPORTBPORTDの各ピン(ビット)は以下のようになっています。

  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 機能
PORTB - - - - LED
(1で点灯,
0で消灯)
- - - 入出力ピンに値を出力
DDRB 0 0 0 0 1 0 0 0 入出力の方向設定
PINB - - - - - - - - 入出力ピンの値を入力
  bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 機能
PORTD - - - - - - - - 入出力ピンに値を出力
DDRD 0 0 0 0 0 0 0 0 入出力の方向設定
PIND - - - - - - - スイッチ
(オンで1,
オフで0)
入出力ピンの値を入力

 スイッチが押されているとLEDが点灯、つまりスイッチ(PD0)が1ならばLEDを点灯、0ならば消灯するプログラムを考えてみましょう。

 必要な処理の流れをフローチャートで表すと以下のようになります。

 プログラムは以下のようになります。

 「BRNE(BRanch if Not Equal)」は、その前の演算結果が「0」でなければ(正確にはZフラグが1でなければ)指定箇所に分岐する命令です。「BRNE LEDON」を実行すると、その前の「ANDI R16,0b01000000」の結果が「0」であれば(つまりスイッチが押されていなければ)そのまま次の番地に進み、「0」でなければ(つまりスイッチが押されていれば)LEDONに分岐し、LEDを点灯してLOOPに戻ります。

C言語によるプログラム

 次に、下図のようにスイッチを1個追加し、一方のスイッチ(SW1)を押すと点灯し、もう一方のスイッチ(SW2)を押すと消灯するようにしてみます。

 必要な処理の流れをフローチャートで表すと以下のようになります。

 プログラムは以下のようになります。

C言語によるプログラム

 上の例のように少し処理が複雑になると、高級言語(ここではC言語)を利用すると見通しを持ちやすいことがわかると思います。



5. プログラミング 2 (LEDを点滅させる)

5.1 サブルーチン呼び出し: LEDを点滅させる

 ここでは、サブルーチンを定義し、呼び出すプログラムを作ります。また、命令がクロック単位(ここでは0.125μs)で実行されることを利用して、タイマープログラムを作ります。

 スイッチの回路をはずし、以下の回路に戻してください。

 ここで、1秒の時間を費やすサブルーチン「T1S」が利用できるならば、次のようなプログラムでLEDを点滅させることができます。

 はじめにSPL(スタックポインタ)の値をSRAMの末尾RAMENDにセットしています。RAMENDtn2313def.incの中で0xDF(0b11011111)に定義されています。サブルーチンコールを使う場合には必ず設定する必要があります。

このために、blink.asmに以下のプログラムを追加します。これにより下表のサブルーチンが利用できるようになります。

T100US 100μsの時間を費やす RCALL T100US
_T100US 100μs×R21の時間を費やす LDI R21,0〜255
RCALL _T100US
T1MS 1msの時間を費やす RCALL T1MS
_T1MS 1ms×R22の時間を費やす LDI R22,0〜255
RCALL _T1MS
T10MS 10msの時間を費やす RCALL T10MS
_T10MS 10ms×R23の時間を費やす LDI R23,0〜255
RCALL _T10MS
T1S 1秒の時間を費やす RCALL T1S

 サブルーチンT100USの中で使われている命令について補足しておきます。
(1) 「NOP(No OPeration)」は何もしない命令です。
(2) 「DEC(DECrement)」は1減ずる命令で、「DEC R16」を実行すると「R16レジスタの内容が1減少」します。
(3) 「BRNE(BRanch if Not Equal)」は、その前の演算結果が「0」でなければ(正確にはZフラグが0であれば)指定箇所に分岐する命令です。「BRNE LOOP100US」を実行すると、その前の「DEC R16」の結果が「0」であればそのまま次の命令(RET)が実行され、「0」でなければLOOP100USに分岐します。

 なお、コメント欄はクロックサイクルの計算値です。マイコンは8MHz(周期は0.125μs)のクロックで動作しており、それぞれ記載のクロックサイクルで命令が実行されます(多くは1クロックサイクル)。サブルーチン「T100US」は、次のようになります。
(1) このサブルーチンを呼び出す「RCALL」に3クロックサイクル
(2) 「LDI」に1クロックサイクル
(3) 「NOP」が1、「NOP」が1、「DEC」が1、「BRNE(NotEqualの場合)」が2、計5クロックサイクルで、これを158回繰り返すので、5*158クロックサイクル
(4) ただし、158回目は「DEC R16」で演算結果が「0」となり(Zフラグが1になる)、「BRNE」が1クロックサイクルなので(3)に対して「-1
(5) 「RET」が4クロックサイクル
(1)〜(5)を合計すると797クロックサイクルとなります。これに0.125μsが掛けると99.625μs(概ね100μs)となります。このように、サブルーチンが呼び出されてから戻るまでにどれだけの時間がかかるかを正確に計算することができます。内蔵クロックが正確に8MHzでないと、計算どおりの時間にならないわけですが、正確を期したい場合は内蔵クロックではなく水晶発振子を使います。また、次節のようにハードウェアタイマーを使うとクロックサイクルの計算をせずに済みます。

C言語によるプログラム

 以下のプログラムの初めでT80と定義していますが、これは経験値です。Cコンパイラのバージョンやコンパイラオプションが異なると、 t100us() がだいたい100μsを費やすように(つまり t1s() がだいたい1秒を費やすように)「80」の値を変える必要があります。

5.2 LEDを点滅させる(内蔵のハードウェアタイマーを使用)

 これまでのタイマープログラムは、プログラムの実行に所定の時間を費やすように調整したもので、「ソフトウェアタイマー」と呼ばれます。

 AVRマイコンにはハードウェアタイマーが内蔵されていますので、ここではこれを利用してみます。

C言語によるプログラム

5.3 応用: テレビのリモコンを作る

 テレビなどのリモコンも、ボタンを押した時に赤外線LEDを「決められたタイミングで点滅」するように作られています。どのように点滅させるかは、Webで検索すると情報が得られます。

 リモコンの回路は、4.2の時の下図から、LEDを「赤外線LED」に交換し、直列抵抗の値を「100Ω」に交換します。

 ここでは東芝のテレビの「チャンネルUP」専用リモコンを作ってみます。赤外線LEDを以下のように光らせると、テレビのチャンネルがUPします。

 以下の説明で、「オン」とは「赤外線LEDを13μs点灯し、13μs消灯し、これを一定時間繰り返す」ことです。上の図の着色した部分が「オン」の箇所です。「オフ」とは「一定時間消灯する」ことです。
(1) リモコン信号の始まりの目印として、9ms「オン」続く4.5ms「オフ」とします。
(2) 0x40のデータを下のビットから順に送信します。ビット0は「0」なので、560μs「オン」、565μs「オフ」とします。
(3) ビット1〜5も「0」なので、560μs「オン」、565μs「オフ」を繰り返します。
(4) ビット6は「1」なので、560μs「オン」、1690μs「オフ」とします。
(5) ビット7は「0」なので、560μs「オン」、565μs「オフ」とします。
(6) (2)〜(5)と同様の方法で0xbfを送信します。
(7) 同じように0x1bを送信します。
(8) 同じように0xe4を送信します。
(9) 最後に終わりの目印として、560μs「オン」、565μs「オフ」とします。

C言語によるプログラム

(練習) 東芝のテレビの「チャンネルDOWN」のコードは

です。4.2の時と同様にスイッチを1個追加し、「チャンネルUP/DOWN」のリモコンを作りなさい。

(練習) 上記のプログラムを参考に、自宅にあるAV機器のリモコン信号のタイミングを調べ、リモコンを作ってみなさい。



6. プログラミング 3 (トーンを鳴らす)

6.1 トーンを鳴らす

 以下のように、LEDと同じ箇所に圧電ブザー(Bzz)を接続してください。

5.1の「1秒ごとにLEDを点滅させるプログラム」を実行してみてください。するとブザーからカチカチと音が聞こえます。このプログラムを「1秒ごと」ではなく、もっと高速に「1msごとに」点滅させてみましょう。この時の波形は下図のように500Hzの矩形波となります。

トーン波形

プログラムは以下のようになります。500Hzの「音」が聞こえるでしょう(500Hzといってもその倍音成分が含まれていますが)。

C言語によるプログラム

(練習) オシロスコープでトーン信号の波形を観測しなさい。また、WaveGeneなどの信号発生ソフトを用い、パソコンで500Hzの矩形波を出し、音を比べてみなさい。マイコンの内蔵クロックはそれほど正確ではありませんので多少の違いがあるかもしれません。

(練習) ラの音440Hz(A4)のトーンを出すサブルーチンを作り、動作を確かめなさい。また、WaveGeneで発声させた440Hzの矩形波の音や身近な楽器のラ(A4)の音と比べてみなさい。

6.2 音階を演奏する(楽譜を命令の並びで表現)

 440Hzのラの音(A4)に対し1オクターブ高いラ(A5)の音は880Hzで、その間は隣同士(半音)の周波数の比が一定(21/12)となるように音階が作られます。表計算ソフトを使い、440Hzを基点に各音の周波数F、周期T(ms)、T/2を計算すると次のようになります。

 表中、「T/2/0.005」の箇所は、5μsのサブルーチンがあった時に、「0」または「1」の時間(T/2)はその何回分に相当するかを計算したものです。また、「200/T」の箇所は、200ms音を継続させるには何周期繰り返せばいいかを計算したものです。

 次のプログラムは、上の計算結果に基づき、指定した音階で波形が200ms繰り返すようにTONEというサブルーチンを呼び出し、「ドレミファミレド」のメロディーにしています。

 また、以下のプログラムは、「DO」「RE」「MI」...という命令をマクロ定義して、メロディーをプログラムしやすくしたものです。マクロ定義については「付録5」を参照してください。このような工夫をすると、長いメロディーもプログラミングが簡単になります。

C言語によるプログラム

(練習) tone2.asm(またはtone2.c)の音階を拡張し、好きな曲の電子オルゴールを作りなさい。



7. プログラミング 3 (LEDの明るさを変える)

7.1 LEDの明るさを変える

 圧電ブザーをはずし、再び下の回路に戻します。

 コンピュータの出力信号は基本的に「高い電圧(+3V)」か「低い電圧(0V)」のいずれかです。ですから、LEDの点灯・消灯プログラムで見たように、LEDは一定の明るさで点灯するかあるいは消灯するかのいずれかです。ではその中間の明るさにはできないかというと、「見掛け上は可能」です。

 トーンのプログラムtone.asm(またはtone.c)の時のLEDの明るさと、初期のprog.asm(またはprog.c)の時のLEDの明るさを比べてみてください。tone.asm(またはtone.c)の方が少し暗いのがわかります。tone.asm(またはtone.c)の場合は、1msの点灯と1msの消灯を繰り返していたわけですから、正味半分の時間しか点灯していなかったことになります。また、高速に点滅すれば私達の目は点滅に気付きません。このような人間の目の特性をうまく利用し、見掛け上(あるいは平均的に)任意の明るさを表すことができます。この技術は「パルス幅変調(PWM)」と呼ばれます。

 tone.asm(またはtone.c)では、点灯時間が50%ですが、これを「デューティ比50%」といいます(下図左)。prog.asm(またはprog.c)のように点灯しっぱなしの時は「デューティ比100%」といいます。

PWM波形

 デューティ比を変えてみましょう。下のプログラム(fade.asm)は、1ms点灯し9ms消灯することを繰り返します。つまり、LEDをデューティ比10%で点灯します。

LEDの明るさがどうなるかに注目してください。

 PWMを使えば任意の波形を表すことができます(下図)。

PWM波形

 デューティ比を変えることにより、平均的に任意の中間値を表現でき、例えば、モータのスピードコントロールや、デジタルオーディオアンプなどに利用されています。

 なお、ここでは、「0」の時間も「1」の時間もプログラムで調整していますが、マイコン内蔵のハードウェアタイマーにPWMの機能が備わっているので、これを使えば、高速で正確なPWM波形を得ることができます。

C言語によるプログラム

(練習) デューティ比を1%(100μs点灯し9.9ms消灯を繰り返す)にして、LEDの明るさを調べなさい。

7.2 LEDの明るさを連続的に変える

 以下のプログラムはデューティ比を0%から100%まで連続的に変化させています。暗い状態から次第に明るくなり、1秒後に最大の明るさになり、これを繰り返します。

C言語によるプログラム

(練習) LEDが、だんだん明るくなり、だんだん暗くなるプログラムを作りなさい。



8. プログラミング 4 (数字を表示する)

8.1 数字表示LEDに数字を表示する

 数字表示LED(7セグメントLED)に数字を表示してみます。以下の回路を組み立ててください。

回路図

 PB0〜PB6はLEDのa〜gのセグメントに接続されていて、それぞれ1を出力した時に点灯する回路となっています。各数字を表示する際にPB0〜PB6に何を出力するとよいか、そしてPORTBに出力すべき16進値を表にしたものです。

数字 PB6(g) PB5(f) PB4(e) PB3(d) PB2(c) PB1(b) PB0(a) HEX
0 0 1 1 1 1 1 1 $3F
1 0 0 0 0 1 1 0 $06
2 1 0 1 1 0 1 1 $5B
3 1 0 0 1 1 1 1 $4F
4 1 1 0 0 1 1 0 $66
5 1 1 0 1 1 0 1 $6D
6 1 1 1 1 1 0 1 $7D
7 0 1 0 0 1 1 1 $27
8 1 1 1 1 1 1 1 $7F
9 1 1 0 0 1 1 1 $67

 以下のプログラムは、数字表示LEDに「5」を表示するものです。

C言語によるプログラム

(練習) 表示する数字を他の数字に変更してみなさい。

8.2 数字表示をカウントアップする

 1秒毎に表示される数字がカウントアップするようにしてみましょう。プログラムは以下のようになります。

 これまではプログラム中に表示データが埋めこまれていましたが、参照テーブルを用いることにより、データとプログラムを分離することができます。以下は、表を参照する方法に書き換えたものです。

C言語によるプログラム

(練習) 数字表示がカウントダウンするプログラムcountdown.asm(あるいはcountdown.c)を作りなさい。

(練習) スイッチを押すとカウントダウンが始まり、カウントが「0」になるとアラーム(ブザー音)が鳴るようにしなさい。

(練習) 8.2のプログラムcountup.asm(またはcountup.c)を、1秒毎ではなく10ms毎に高速でカウントアップするようにし、スイッチが押されるとそこで停止するようにしなさい。

(練習) スイッチを押すと数字表示がカウントアップするプログラムを作りなさい。スイッチを押した時や放した時に接点がバタバタとオンオフしてしまう「チャタリング」という現象が生じ、誤動作が起きるかもしれませんが、このような問題もプログラムの工夫で回避することができます。今の段階では、このような問題があることを体験するだけで構いません。

(練習) 1秒毎に「H」「E」「L」「L」「O」を表示し、その後3秒間消え、再びこれを繰り返すプログラムを作りなさい。また、「E」「r」「r」「o」「r」の表示にしてみなさい。



9. 外部回路の制御

 これまでの例では、マイコンの出力ピンにLEDや圧電ブザーを接続しました。AVRマイコンは最大20mAの電流を流すことができるので、この範囲であれば直接接続できます。この章では、モータなど大きな電流が流れる素子を駆動する例を、今まで製作した中から紹介します。1章でも触れましたが、大きな電流が流れる回路を制御する場合は、「電流が流れる経路」を意識することが回路の誤動作を防ぐことにつながります。

9.1 リレーの駆動

 リレーをマイコンに接続し、リレーの接点で他の素子を制御するのが最も汎用性に富む方法です。「BDアダプタ」と組み合わせると、電池で動くおもちゃなどを簡単に制御できます(BDアダプタは製作も容易です)。

 「タッチでチャイム」では、リードリレーAPA3319(5V 24mA)をマイコンで直接駆動しました。マイコンに逆電圧がかからないように並列にダイオードを入れます。リードリレーSS1A05(秋月)は、5V 10mAで駆動できます。

 電池で動くおもちゃを制御したい場合などは、Y14H-1C-3DS(秋月)(3V 50mA)を使うと、1Aまで接点でオンオフ制御できます。この場合は、リレーをマイコンに直接接続できず、トランジスタを追加する必要があります。

9.2 DCモータの駆動

 「ミニドラムマシン」では、バチを動かすのにDCモータを使い、2SC2120で駆動しました。赤外線リモコン自動車ではDCモータを2SK3142で駆動しました。

 モータのオンオフだけでなく、正転逆転させたい場合は、Hブリッジ回路を用います。ザリガニロボット自律走行台車ではドライバICとしてTA7257Pを使いました。IC内部での電圧降下が少なくないので注意が必要です。

9.3 振動モータの駆動

 Midiコントローラ「ジングルベル」では、振動モータFM34F(100mA以下)を使い、「鈴」を鳴らました。2SC2120(最大800mA)や2SC735など、少し多目に電流を流せるトランジスタを使っています。

9.4 サーボモータの駆動

 「ミニドラムマシン」では、ドラムの位置にバチを動かすためにPICO/STD/Fを使いました。サーボモータの制御端子はマイコンに直接接続できます。

9.5 LEDの駆動

 それほど大電流ではなく、しかし駆動する素子がたくさんある場合は専用のドライバICを使うと便利です。「交通安全教室用信号機」では12V 60mA のLEDの駆動にTD62083(最大500mA)を利用しました。



(参考資料)

[1] ATtiny2313 データシート, Atmel社
[2] Arduino風 パソコン制御とマイコン制御, http://siva.cc.hirosaki-u.ac.jp/usr/koyama/arduino/
[3] 豆電球と乾電池, http://siva.cc.hirosaki-u.ac.jp/usr/koyama/lecture/it/load.htm
[4] HIDaspx, http://www-ice.yamagata-cit.ac.jp/ken/senshu/sitedev/index.php?AVR%2FHIDaspx_news02
[5] WinAVR-20100110, http://sourceforge.net/project/showfiles.php?group_id=68108
[6] ヒダピオ学習回路, http://www.topman.co.jp/ky/download/hidapio/hidapio_00.html

(付録1) 使用する主な部品

部品表
名称 概観 備考
ブレッドボード(EIC-301) 秋月 150円
ブレッドボード ジャンパーワイヤ   秋月 10本 300円
LED 秋月 10個 100円
赤外線LED 秋月 10個 100円
数字表示LED(C-551SR) 秋月 50円
圧電スピーカー 秋月 2個 100円
プッシュスイッチ(DS-660R-C) 千石 84円
抵抗 1/4W 1kΩ, 220Ω, 100Ω 秋月 100本 100円
AVRマイコン(ATtiny2313V) 秋月 100円
電池ケース(単3×2本 SW付) 秋月 60円

(付録2) AVRライタ

 AVRライタは、senshu氏が開発したHIDaspx[4]を使用します。実習用に下図のものを製作しました。

 HIDaspxは、トップマンから「ヒダピオ学習回路」[6]として販売されています。これを利用する場合は、下図のような接続ケーブルを作ります。12ピンに切断したピンヘッダに100Ωの抵抗を半田づけし、ICクリップとの間をケーブルで接続します。ICクリップが無い場合は、ジャンパワイヤを使い、その一方をピンヘッダや抵抗に半田づけし、もう一方をブレッドボードに挿して書き込みます。

必要な部品
名称備考
ヒダピオ学習回路トップマン 1785円
ピンヘッダ(オス 40P)秋月 40円
抵抗 1/4W 100Ω 4個秋月 100本 100円
ICクリップ STC-20Aサンハヤト 1502円
ラベル 

 どちらも、ライタソフトとしてHIDspx[4]を使いますが、オプションの指示が異なります(2.1および付録3)。

(付録3) バッチプログラムの内容

avra.bat(抜粋):
tools\avrasm32 -l list.txt -fI %1
avrw.bat(抜粋...HIDaspx用):
tools\hidspx -ph -d4 %1
avrwp.bat(抜粋...ヒダピオ用):
tools\hidspx -php -d4 %1
avrc.bat(抜粋):
avr-gcc -Os -g -Wall -mmcu=attiny2313 -o bin.elf %1 avr-size -x bin.elf >list.txt avr-objdump -S bin.elf >>list.txt avr-objcopy -O ihex bin.elf bin.hex erase bin.elf

(付録4) コマンドプロンプトでの操作

 GUIによる操作ではなく、コマンドプロンプトの操作で行うこともできます。

(アセンブラの場合)

  1. テキストエディタでソースプログラム(prog.asm)を作成します。
  2. 次に と操作すると、ソースプログラム(prog.asm)からHexプログラム(prog.hex)とリストファイル(list.txt)が作られます。
  3. ライタを接続し、 と操作すると、Hexプログラム(prog.hex)がAVRマイコンに書き込まれます。

(C言語の場合)

  1. テキストエディタでソースプログラム(prog.c)を作成します。
  2. 次に と操作すると、ソースプログラム(prog.c)からHexプログラム(bin.hex)とリストファイル(list.txt)が作られます。
  3. ライタを接続し、 と操作すると、Hexプログラム(bin.hex)がAVRマイコンに書き込まれます。

(付録5) マクロ定義とマクロ展開

 ここでは、マクロ定義について説明します。

 「OUT」命令は値を直接出力することはできないため、

LDI R16,0b00001000 OUT DDRB,R16 のように値を一旦レジスタに入れ、そのレジスタの内容を「OUT」で出力しました。このようなパターンは度々現れるため、「OUTI」のような命令があれば OUTI DDRB,0b00001000 と書くことができて便利なのにと思います。マクロ機能を使うとこのような新しい命令を作り出す(定義する)ことができます。

 以下の例では、「.macro」〜「.endm」の箇所で、新しい命令「OUTI」をマクロ定義しています。そして、「.cseg」以降のプログラムの中で、通常の命令と同じように「OUTI」という命令を使っています。

ここで、「OUTI」命令の1つ目のパラメータ「DDRB」はマクロ定義の「@0」に、2つ目のパラメータ「0b00001000」はマクロ定義の「@1」の箇所に代入されます。

 このソースプログラムは、アセンブルするとどのような機械語プログラムとなるのでしょうか。以下のようにリストファイル(list.txt)で確認することができます。

OUTI」の箇所は、その定義に従ってパラメータを含めてマクロ展開され、そして展開されたプログラムから機械語が作られていることがわかります。なお、プログラム冒頭に書き加えた「.listmac」は、マクロ展開の内容をリストファイルに出力するための指示です。

(付録6) ATtiny2313の主な命令

(ニーモニックと意味) (例と説明)
転送命令
MOVMOVe MOV R16,R17 R17の内容をR16に格納
LDILoaD Immediate LDI R16,100 R16100を格納
LDLoaD indirect LD R16,X Xレジスタで示される番地の内容をR16に格納
LDSLoad Direct from SRAM LDS R16,DATA DATA番地の内容をR16に格納
STSTore indirect ST X,R16 R16の内容をXレジスタで示される番地に格納
STSSTore direct to SRAM STS DATA,R16 R16の内容をDATA番地に格納
LPMLoad Program Memory LPM Zレジスタで示される番地の内容をR0に格納
入出力命令
ININput IN R16,PIND PINDから入力しR16に格納
OUTOUTput OUT PORTB,R16 R16の内容をPORTBに出力
算術演算命令
ADDADD ADD R16,R17 R16R17の内容を足す
SUBSUB SUB R16,R17 R16からR17の内容を引く
SUBISUB Immediate SUBI R16,100 R16から100を引く
CLRCLeaR CLR R16 R16を0にする
論理演算命令
ANDAND AND R16,R17 R16R17の内容とAND
ANDIAND Immediate ANDI R16,0b00000001 R160b00000001とAND
OROR OR R16,R17 R16R17の内容とOR
ORIOR Immediate ORI R16,0b00000010 R160b00000010とOR
EORExcluseve OR EOR R16,R17 R16R17の内容とExclusiveOR
COMCOMplement COM R16 R16のビットを反転(1の補数)
比較演算命令
CPComPare CP R16,R17 R16R17の内容と比較
CPIComPare Immediate CPI R16,100 R16100と比較
シフト演算命令
LSLLogical Shift Left LSL R16 R16の内容を1ビット左にシフト
LSRLogical Shift Right LSR R16 R16の内容を1ビット右にシフト
分岐命令
RJMPRelative JuMP RJMP LOOP LOOPにジャンプ
BREQBRanch if EQual BREQ LOOP Zフラグが1ならLOOPにジャンプ
BRNEBRanch if Not Equal BRNE LOOP Zフラグが0ならLOOPにジャンプ
BRCSBRanch if Carry Set BRCS LOOP Cフラグが1ならLOOPにジャンプ
BRCCBRanch if Carry Cleared BRCC LOOP Cフラグが0ならLOOPにジャンプ
スタック操作命令
PUSHPUSH PUSH R16 R16の内容をスタックに待避
POPPOP POP R16 R16にスタックから値を復旧
サブルーチン命令
RCALLRelative CALL RCALL SUB サブルーチンSUBの呼び出し
RETRETurn RET サブルーチンが呼び出されたアドレスに戻る
その他
NOPNo OPeration NOP 何もしないで1クロック費やす

(付録7) AVRマイコンを使ったものづくりの例

 このテキストで学習したことの延長線上でどのようなものを作ることができるのか、その一例を以下に紹介します。インターネット上では、さまざまな方がたくさんの興味深い作品を公開していますので探してみてください。

  マイコン 開発言語 URL
天文教材 ATtiny2313 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/astro/
ゴミ教材 AT90S2313 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/able/
交通安全教室用信号機 ATtiny2313 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/signal/
なんでもリモコン AT90S2313 アセンブラ http://siva.cc.hirosaki-u.ac.jp/usr/koyama/nandemo/
タッチでチャイム AT90S2313 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/nandemo/chime.htm
タッチ/押しボタン式マウス ATtiny2313 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/nandemo/m12.htm
気になる写真立て ATtiny2313 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/kininaru/
タイムエイド ポケット ATtiny2313 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/timeaid/
タイムエイドforTV ATtiny45 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/video/timaidtv.htm
ビデオ信号ジェネレータ AT90S2313
ATtiny45
ATmega88
アセンブラ
C言語
http://siva.cc.hirosaki-u.ac.jp/usr/koyama/video/
多目的タイマー ATtiny45 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/video/itimer.htm
発表会用タイマー ATmega328 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/video/timer.htm
電光掲示板(ビデオテロッパー) ATtiny85 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/video/telop.htm
TV時計 ATtiny45 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/video/tvclock.htm
PONGゲーム ATtiny45 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/video/pong.htm
自律走行台車 AT90S2313 アセンブラ http://siva.cc.hirosaki-u.ac.jp/usr/koyama/lecture/itx/daisya/
ザリガニロボット AT90S2313 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/lecture/itx/zarigani/zarifunsen.html
ノックの達人 AT90S2313 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/lecture/itx/lock/
TV-BANK(テレビ貯金箱) ATtiny2313 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/lecture/itx/tvbank/
シンプルな時計 AT90S2313
ATtiny2313
C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/product/clock.htm
電子オルゴール AT90S2313
ATtiny2313
C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/product/melody.htm
私だけの電子オルゴール ATtiny2313
ATtiny45
C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/mymelo/
電子ピアノ ATtiny2313 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/product/piano.htm
貯金箱 AT90S2313 C言語 http://siva.cc.hirosaki-u.ac.jp/usr/koyama/product/coinbox.htm
ミニドラム・ミニ鉄琴 ATtiny2313 Arduinoスケッチ http://siva.cc.hirosaki-u.ac.jp/usr/koyama/drum/
Midiコントローラ「ジングルベル」 ATtiny2313 Arduinoスケッチ http://siva.cc.hirosaki-u.ac.jp/usr/koyama/midi/jingle.htm
AAF ATmega2560 Arduinoスケッチ http://siva.cc.hirosaki-u.ac.jp/usr/koyama/aaf/

koyama@cc.hirosaki-u.ac.jp