私達の身近にある家電機器の多くにコンピュータが内蔵されており、このようなコンピュータは「マイコン」と呼ばれます。マイクロコンピュータあるいはマイクロコントローラの略です。マイコンにはメーカーが開発したプログラムが書き込まれています。リモコンであれば、押したボタンに応じて決まったパターンで赤外線をオンオフするプログラムが書き込まれています。このプログラムは製造時に書き込まれ、後から書き換えることはできませんが、フラッシュメモリ(電気的に書き換え可能なプログラムメモリ)を搭載したマイコンを使えば、私達もさまざまな機器を作ることができます。
マイコンを使った機器を設計・製作するには、電子回路、論理回路、コンピュータの仕組み、プログラミングなど広範囲の知識が要求されます。これは大変なことではありますが、一方ではこれらのことを学ぶ格好の教材であるということを意味しています。
このテキストでは、AVRマイコンを使った実習を行いながら、主にコンピュータの内部動作について学習します。理解を深めていただきたい箇所は3章です。ATtiny2313のマニュアル(英文)[1](1〜14ページ, 211〜214ページ, および必要に応じて他のページ)を読みながら学習を進めます。
4章〜8章はプログラミングを扱っています。プログラミングについて本格的に学ぶというよりも、原始的な命令を組み合わせて、条件分岐や繰り返しなどの処理がどのように行われるのかを見ていきます。更に、さまざまな「ものづくり」に発展させたいという方は、9章や「Arduino風パソコン制御とマイコン制御」[2]を参考にしてください。最近話題のArduinoを用いる場合にも、このテキストで学習した内容は役立つのではないかと思います。
ここでは複雑な電子回路は登場していませんが、電気回路の最低限の知識は前提としています。自信の無い方は[3]を参考にしてください。なお、このテキストは実習時に適宜解説や補足を行うことを前提にしています。自学自習には適していないかもしれません。
私自身ブレッドボードを使うようになったのは、つい最近のことです。半田付けをしないでさまざまなモノを作ることができるので、実習用に適していると実感しています。ブレッドボードを使ったことがある方は、この章を読み飛ばして構いません。
ここでは下図左のブレッドボードを使います(秋月 EIC-301)。ボードの内部は下図右のように接続されています。
| (概観) | (内部の接続) |
|---|---|
![]() | ![]() |
電子工作の第一歩として、下図左の回路図を組み立ててみましょう。実際の配線は下図右のようになります。これを実体配線図と言います。なお、結線用のワイヤは「ブレッドボード・ジャンパーワイヤ15cm(秋月)」を使います。
| (回路図) | (実体配線図) |
|---|---|
![]() | ![]() |
LEDは点灯しましたか? 下の写真は実際の様子です。

ここで、ブレッドボード内部の接続を念頭に、下図のような電流の流れをイメージすることが重要です。LEDは電流が流れるから点灯するのです。
![]() | ![]() |
それでは、下図のように押しボタンスイッチを追加し、スイッチを押すとLEDが点灯するようにしてみましょう。スイッチを押すと電流が流れるわけですが、ここでも「電流が流れる経路」を(ブレッドボードの内部結線を含めて)イメージしてください。
| (回路図) | (実体配線図) |
|---|---|
![]() | ![]() |
それでは次章以降の準備として、AVRマイコンを接続してみましょう。電池のスイッチは切り、AVRマイコンの向きに気を付けて差し込んでください。
| (回路図) | (実体配線図) |
|---|---|
![]() | ![]() |
| ファイル名 | 内容 |
|---|---|
| prog.asm | ソースプログラム(サンプル) |
| prog.c | ソースプログラム(サンプル) |
| tn2313def.inc | アセンブラ用マイコン定義ファイル |
| avra.bat | アセンブルバッチコマンド(付録3) |
| avrc.bat | Cコンパイルバッチコマンド(付録3) |
| avrw.bat | ライタバッチコマンド(HIDaspx用)(付録3) |
| avrwp.bat | ライタバッチコマンド(ヒダピオ用)(付録3) |
| toolsフォルダ |
AVRアセンブラavrasm32.exe[1] ライタソフトHIDspx.exe[4] |
(1) avra.batのショートカットを作成し、名前を「アセンブル」にします。

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

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

プログラムは回路と密接に関係しています。例えば、LEDをマイコンのどのピンに接続するかでプログラムは変わってきます。ここから先の実習を行うにあたり、以下の回路を組み立ててください。以降のプログラムはこの回路を前提としています。
| (回路図) | (実体配線図) |
|---|---|
![]() | ![]() |
(1)メモ帳などでソースプログラムを作成・編集します。ここではprog.asmというファイル名とします。

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

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

リストファイルを見ることにより、ソースプログラムがどのような機械語プログラムに変換されるかがわかります。例えば、「LDI R16,0b00001000」は機械語「e008H」に変換されます。
コンピュータのプログラム領域(Program Flash)に書き込む機械語のみをファイルにしたものが機械語ファイル(prog.hex)で、下図はこれをメモ帳で開いた様子です。

機械語ファイルの書式は次のようになっています。
(1)メモ帳などでソースプログラムを作成・編集します。ここではprog.cというファイル名とします。

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

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

リストファイルを見ることにより、C言語のソースプログラムがどのようなアセンブラプログラムに変換され、どのような機械語プログラムになるかがわかります。アセンブラプログラムの各行は基本的に機械語プログラムに1対1に対応しますが、C言語(一般に高級言語)のプログラムは、もっと高度な変換が行われています。
機械語ファイルの書式は既に説明したとおりです。
ここで用いるAVRマイコンは、ISP(In System Programming)可能なもので、マイコンを装置に組み込んだ状態で、マイコン内にプログラムを書き込みできます。
ブレッドボード上のAVRマイコンにライタを接続し、電池のスイッチを入れます。電源が入っていないと書き込みができないので注意してください。ソースプログラムから変換して作った機械語ファイルprog.hex(C言語の場合はbin.hex)を「書き込み」にドラッグ&ドロップします。書き込み終了と同時に、書き込んだプログラムがスタートします。
ライタを切り離し、電源スイッチを入れたり切ったりして、確かに単体で動作していることを確認してください。


マイコンを埋めこんだ機器の開発プロセスは以下のようになります。
本テキストで使用するATtiny2313の内部構造を下図に示します。

(1) プログラムメモリ(Program Flash)は、1ワード16ビットで1024ワード($000〜$3FF)の領域があります。
(2) データメモリ(SRAM)は、128バイトの領域($60〜$DF)があります。
(3) 不揮発データメモリ(EEPROM)は、128バイトの領域($00〜$7F)があります。
(4) 汎用レジスタ(Registers)は、8ビットのものが32個あります。
(5) プログラムカウンタ(Program Counter)には、次に実行すべき命令語のアドレス($000〜$3FF)が入っています。
(6) 命令レジスタ(Instruction Register)には、プログラムメモリから、プログラムカウンタが指し示す番地の内容つまり次に実行すべき命令語が転送されます。その内容は命令デコーダ(Instruction Decoder)で解読され、実行されます。
(7) スタックポインタ(Stack Pointer)は、データメモリ(SRAM)の後ろから確保するスタック領域の先頭アドレスを指し示しています(〜$DF)。スタックを利用するためには、あらかじめデータメモリ(SRAM)の最終番地$DFにセットしておく必要があります。サブルーチンコールを行った場合、戻り番地はスタック領域に保存されます。
(8) 算術論理演算ユニット(ALU)は、主にレジスタに格納された値相互の演算を行います。
(9) 状態レジスタ(Status Rester)は、ALUの演算結果が「0」ならZフラグ(Bit 1)が1になり、キャリーを生じたらCフラグ(Bit 0)が1になります。
(10) DDRBレジスタは、PB0〜PB7の各端子を入力とするか出力とするかを指定するために用います。PB0〜PB7に対応するDDRBレジスタのビットを、入力とする場合は「0」、出力とする場合は「1」にします。
(11) DDRDレジスタは、PD0〜PD6の各端子を入力とするか出力とするかを指定するために用います。PD0〜PD6に対応するDDRDレジスタのビットを、入力とする場合は「0」、出力とする場合は「1」にします。
(12) PORTBレジスタは、各ビットを「0」または「1」にすると、PB0〜PB7のうち出力に指定されているビットにはその値を出力します。「0」が出力されるとそのピンは「低い電圧(0V)」、「1」が出力されると「高い電圧(+3V)」となります。
(13) PORTDレジスタは、各ビットを「0」または「1」にすると、PD0〜PD6のうち出力に指定されているビットにはその値を出力します。
(14) Timer/Counter0は、8ビットカウンタで、クロック周波数(またはその1/8, 1/64, 1/256, 1/1024)をカウントします。
(15) Timer/Counter1は、16ビットカウンタで、クロック周波数(またはその1/8, 1/64, 1/256, 1/1024)をカウントします。
(16) 8MHzのクロックオシレータを内蔵しています。
次のソースプログラムからどのような機械語が作られ、その機械語プログラムがコンピュータ内部でどのように動作するかを詳しくみてみます。
|
|
ソースプログラムの1行目はアセンブラに対する制御命令で、ここで用いているATtiny2313に関する情報が定義された「tn2313def.inc」というファイルを読み込みます。
2行目の「.cseg」はアセンブラに対する制御命令で、以下がプログラムコードであることを宣言しています。
3行目以降が機械語になるプログラム部分です。
このソースプログラムは、アセンブラソフト(ATMEL社のavrasm32.exe)を用いてアセンブルすると5ワード(5×16bit)の機械語プログラムとなります。プログラムのどの箇所がどのような機械語になるかは、以下のようにリストファイル(list.txt)で確認できます。
|
|
それでは、「書き込まれたプログラムから命令が一つずつ取り出されて実行される仕組み」を詳しく見てみましょう。動作の仕組みはどのコンピュータにも共通する基本的な事項ですから、丁寧に見てください。
■ 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 | R16〜R31のうちの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-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 |
R0〜R31のうちのR16 | DDRBを表わすIOアドレス $17(010111)の下位4bit |
「OUT」は「OUTput」を意味するニーモニックコードです。
(4) デコードの結果を受けて、その命令の実行に必要なタイミング信号が作られ、実行(execute)されます。この場合はDDRBレジスタの内容が「00001000」となります。
IOポートに直接値を出力する命令が無いために、このように初めの命令でレジスタに値をセットし、次の命令でレジスタの内容をIOポートに出力します。ここで行ったDDRBレジスタの設定は、「PB0〜PB2, PB4〜PB7を入力として使い、PB3を出力として使う」ということを指示するものです。

■ 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 | R16〜R31のうちのR16 | 代入する値の下位4bit |
(4) デコードの結果を受けて、その命令の実行に必要なタイミング信号が作られ、実行(execute)されます。この場合はレジスタR16の中が「00001000」となります。

■ 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 |
R0〜R31のうちのR16 | PORTBを表わすIOアドレス $18(011000)の下位4bit |
(4) デコードの結果を受けて、その命令の実行に必要なタイミング信号が作られ、実行(execute)されます。ここではPORTBのbit3(PB3ピン)が1(高い電圧)となり、外部回路のLEDが点灯します。PORTBはレジスタになっているので、一旦値をセットすると保持されます。

■ 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の内容となります。

■ 以降「LDI R16,0b00001000」「OUT PORTB,R16」「RJMP LOOP」が繰り返されます
(練習) 以下のように、プログラム6行目の「LDI R16,0b00001000」を「LDI R16,0b00000000」に変更し、動作を確認しなさい。これは、PORTBのbit3を1から0に変更するということを意味しています。その結果、プログラムの一連の命令が実行されると、それまで点灯していたLEDが消灯します。
| → |
| → |
| → |
|
(練習) PB2にもLEDと抵抗を接続し、
(1)2つのLEDを同時に点灯されるプログラム
(2)一方だけ点灯させるプログラム
を作りなさい。
次のようにLEDを点灯させる正味のプログラムをサブルーチンとして分離し、これを例に、サブルーチンの呼び出しがどのように実行されるかを詳しくみてみます。
|
|
このソースプログラムは、アセンブルすると9ワードの機械語プログラムとなります。プログラムのどの箇所がどのような機械語になるかは、以下のようにリストファイル(list.txt)で確認できます。
|
|
それでは、プログラムがどのように実行されるかを詳しく見てみましょう。
■ 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 | R16〜R31のうちの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 |
R0〜R31のうちのR16 | SPLを表わすIOアドレス $3D(111101)の下位4bit |
(4) デコードの結果を受けて、SPLレジスタの内容が「11011111」となります。SPLレジスタ(スタックポインタ)の働きについては、次のRCALL命令の箇所で説明します。

■ 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)られます。このような方法で、多重のサブルーチン呼び出し(サブルーチンの中で他のサブルーチンを呼び出すこと)が可能になっているのです。

■ 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 | R16〜R31のうちの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 |
R0〜R31のうちのR16 | PORTBを表わすIOアドレス $18(011000)の下位4bit |
(4) デコードの結果を受けて、PORTBのbit3(PB3ピン)が1(高い電圧)となり、外部回路のLEDが点灯します。

■ 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」します。

■ 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の内容となります。

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

マイコンの入出力ポートPB0〜PB7の各ピン(ビット)は以下のようになっています。
| bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 機能 | |
|---|---|---|---|---|---|---|---|---|---|
| PORTB | - | - | - | - | LED (1で点灯, 0で消灯) |
- | - | - | 入出力ピンに値を出力 |
| DDRB | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 入出力の方向設定 |
| PINB | - | - | - | - | - | - | - | - | 入出力ピンの値を入力 |
プログラムprog.asmは次のようなものでした。
|
|
初めにDDRBに0b00001000を出力しています。これは、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を点灯・消灯させなさい。
条件によってプログラムの流れを変える場合はどうするのかをみてみます。
スイッチと抵抗を追加し、以下の回路にします。

マイコンの入出力ポートPORTBとPORTDの各ピン(ビット)は以下のようになっています。
| 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言語)を利用すると見通しを持ちやすいことがわかると思います。
ここでは、サブルーチンを定義し、呼び出すプログラムを作ります。また、命令がクロック単位(ここでは0.125μs)で実行されることを利用して、タイマープログラムを作ります。
スイッチの回路をはずし、以下の回路に戻してください。

ここで、1秒の時間を費やすサブルーチン「T1S」が利用できるならば、次のようなプログラムでLEDを点滅させることができます。
|
|
はじめにSPL(スタックポインタ)の値をSRAMの末尾RAMENDにセットしています。RAMENDはtn2313def.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言語によるプログラム
以下のプログラムの初めでTを80と定義していますが、これは経験値です。Cコンパイラのバージョンやコンパイラオプションが異なると、 t100us() がだいたい100μsを費やすように(つまり t1s() がだいたい1秒を費やすように)「80」の値を変える必要があります。
|
|
これまでのタイマープログラムは、プログラムの実行に所定の時間を費やすように調整したもので、「ソフトウェアタイマー」と呼ばれます。
AVRマイコンにはハードウェアタイマーが内蔵されていますので、ここではこれを利用してみます。
|
|
C言語によるプログラム
|
|
テレビなどのリモコンも、ボタンを押した時に赤外線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」のコードは
(練習) 上記のプログラムを参考に、自宅にあるAV機器のリモコン信号のタイミングを調べ、リモコンを作ってみなさい。
以下のように、LEDと同じ箇所に圧電ブザー(Bzz)を接続してください。

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

プログラムは以下のようになります。500Hzの「音」が聞こえるでしょう(500Hzといってもその倍音成分が含まれていますが)。
|
|
C言語によるプログラム
|
|
(練習) オシロスコープでトーン信号の波形を観測しなさい。また、WaveGeneなどの信号発生ソフトを用い、パソコンで500Hzの矩形波を出し、音を比べてみなさい。マイコンの内蔵クロックはそれほど正確ではありませんので多少の違いがあるかもしれません。
(練習) ラの音440Hz(A4)のトーンを出すサブルーチンを作り、動作を確かめなさい。また、WaveGeneで発声させた440Hzの矩形波の音や身近な楽器のラ(A4)の音と比べてみなさい。
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)の音階を拡張し、好きな曲の電子オルゴールを作りなさい。
圧電ブザーをはずし、再び下の回路に戻します。

コンピュータの出力信号は基本的に「高い電圧(+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%」といいます。

デューティ比を変えてみましょう。下のプログラム(fade.asm)は、1ms点灯し9ms消灯することを繰り返します。つまり、LEDをデューティ比10%で点灯します。
LEDの明るさがどうなるかに注目してください。|
|
PWMを使えば任意の波形を表すことができます(下図)。

デューティ比を変えることにより、平均的に任意の中間値を表現でき、例えば、モータのスピードコントロールや、デジタルオーディオアンプなどに利用されています。
なお、ここでは、「0」の時間も「1」の時間もプログラムで調整していますが、マイコン内蔵のハードウェアタイマーにPWMの機能が備わっているので、これを使えば、高速で正確なPWM波形を得ることができます。
C言語によるプログラム
|
|
(練習) デューティ比を1%(100μs点灯し9.9ms消灯を繰り返す)にして、LEDの明るさを調べなさい。
以下のプログラムはデューティ比を0%から100%まで連続的に変化させています。暗い状態から次第に明るくなり、1秒後に最大の明るさになり、これを繰り返します。
|
|
C言語によるプログラム
|
|
(練習) 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言語によるプログラム
|
|
(練習) 表示する数字を他の数字に変更してみなさい。
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」の表示にしてみなさい。
これまでの例では、マイコンの出力ピンにLEDや圧電ブザーを接続しました。AVRマイコンは最大20mAの電流を流すことができるので、この範囲であれば直接接続できます。この章では、モータなど大きな電流が流れる素子を駆動する例を、今まで製作した中から紹介します。1章でも触れましたが、大きな電流が流れる回路を制御する場合は、「電流が流れる経路」を意識することが回路の誤動作を防ぐことにつながります。
リレーをマイコンに接続し、リレーの接点で他の素子を制御するのが最も汎用性に富む方法です。「BDアダプタ」と組み合わせると、電池で動くおもちゃなどを簡単に制御できます(BDアダプタは製作も容易です)。
「タッチでチャイム」では、リードリレーAPA3319(5V 24mA)をマイコンで直接駆動しました。マイコンに逆電圧がかからないように並列にダイオードを入れます。リードリレーSS1A05(秋月)は、5V 10mAで駆動できます。
電池で動くおもちゃを制御したい場合などは、Y14H-1C-3DS(秋月)(3V 50mA)を使うと、1Aまで接点でオンオフ制御できます。この場合は、リレーをマイコンに直接接続できず、トランジスタを追加する必要があります。
「ミニドラムマシン」では、バチを動かすのにDCモータを使い、2SC2120で駆動しました。赤外線リモコン自動車ではDCモータを2SK3142で駆動しました。
モータのオンオフだけでなく、正転逆転させたい場合は、Hブリッジ回路を用います。ザリガニロボットや自律走行台車ではドライバICとしてTA7257Pを使いました。IC内部での電圧降下が少なくないので注意が必要です。
Midiコントローラ「ジングルベル」では、振動モータFM34F(100mA以下)を使い、「鈴」を鳴らました。2SC2120(最大800mA)や2SC735など、少し多目に電流を流せるトランジスタを使っています。
「ミニドラムマシン」では、ドラムの位置にバチを動かすためにPICO/STD/Fを使いました。サーボモータの制御端子はマイコンに直接接続できます。
それほど大電流ではなく、しかし駆動する素子がたくさんある場合は専用のドライバICを使うと便利です。「交通安全教室用信号機」では12V 60mA のLEDの駆動にTD62083(最大500mA)を利用しました。
| 名称 | 概観 | 備考 |
|---|---|---|
| ブレッドボード(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円 |
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)。
GUIによる操作ではなく、コマンドプロンプトの操作で行うこともできます。
(アセンブラの場合)
(C言語の場合)
ここでは、マクロ定義について説明します。
「OUT」命令は値を直接出力することはできないため、
以下の例では、「.macro」〜「.endm」の箇所で、新しい命令「OUTI」をマクロ定義しています。そして、「.cseg」以降のプログラムの中で、通常の命令と同じように「OUTI」という命令を使っています。
|
|
このソースプログラムは、アセンブルするとどのような機械語プログラムとなるのでしょうか。以下のようにリストファイル(list.txt)で確認することができます。
|
|
| (ニーモニックと意味) | (例と説明) | |||
| 転送命令 | ||||
| MOV | MOVe | MOV R16,R17 | R17の内容をR16に格納 | |
| LDI | LoaD Immediate | LDI R16,100 | R16に100を格納 | |
| LD | LoaD indirect | LD R16,X | Xレジスタで示される番地の内容をR16に格納 | |
| LDS | Load Direct from SRAM | LDS R16,DATA | DATA番地の内容をR16に格納 | |
| ST | STore indirect | ST X,R16 | R16の内容をXレジスタで示される番地に格納 | |
| STS | STore direct to SRAM | STS DATA,R16 | R16の内容をDATA番地に格納 | |
| LPM | Load Program Memory | LPM | Zレジスタで示される番地の内容をR0に格納 | |
| 入出力命令 | ||||
| IN | INput | IN R16,PIND | PINDから入力しR16に格納 | |
| OUT | OUTput | OUT PORTB,R16 | R16の内容をPORTBに出力 | |
| 算術演算命令 | ||||
| ADD | ADD | ADD R16,R17 | R16にR17の内容を足す | |
| SUB | SUB | SUB R16,R17 | R16からR17の内容を引く | |
| SUBI | SUB Immediate | SUBI R16,100 | R16から100を引く | |
| CLR | CLeaR | CLR R16 | R16を0にする | |
| 論理演算命令 | ||||
| AND | AND | AND R16,R17 | R16をR17の内容とAND | |
| ANDI | AND Immediate | ANDI R16,0b00000001 | R16を0b00000001とAND | |
| OR | OR | OR R16,R17 | R16をR17の内容とOR | |
| ORI | OR Immediate | ORI R16,0b00000010 | R16を0b00000010とOR | |
| EOR | Excluseve OR | EOR R16,R17 | R16をR17の内容とExclusiveOR | |
| COM | COMplement | COM R16 | R16のビットを反転(1の補数) | |
| 比較演算命令 | ||||
| CP | ComPare | CP R16,R17 | R16をR17の内容と比較 | |
| CPI | ComPare Immediate | CPI R16,100 | R16を100と比較 | |
| シフト演算命令 | ||||
| LSL | Logical Shift Left | LSL R16 | R16の内容を1ビット左にシフト | |
| LSR | Logical Shift Right | LSR R16 | R16の内容を1ビット右にシフト | |
| 分岐命令 | ||||
| RJMP | Relative JuMP | RJMP LOOP | LOOPにジャンプ | |
| BREQ | BRanch if EQual | BREQ LOOP | Zフラグが1ならLOOPにジャンプ | |
| BRNE | BRanch if Not Equal | BRNE LOOP | Zフラグが0ならLOOPにジャンプ | |
| BRCS | BRanch if Carry Set | BRCS LOOP | Cフラグが1ならLOOPにジャンプ | |
| BRCC | BRanch if Carry Cleared | BRCC LOOP | Cフラグが0ならLOOPにジャンプ | |
| スタック操作命令 | ||||
| PUSH | PUSH | PUSH R16 | R16の内容をスタックに待避 | |
| POP | POP | POP R16 | R16にスタックから値を復旧 | |
| サブルーチン命令 | ||||
| RCALL | Relative CALL | RCALL SUB | サブルーチンSUBの呼び出し | |
| RET | RETurn | RET | サブルーチンが呼び出されたアドレスに戻る | |
| その他 | ||||
| NOP | No OPeration | NOP | 何もしないで1クロック費やす | |
このテキストで学習したことの延長線上でどのようなものを作ることができるのか、その一例を以下に紹介します。インターネット上では、さまざまな方がたくさんの興味深い作品を公開していますので探してみてください。
| マイコン | 開発言語 | 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/ |