電源電圧は5V、クロックは10MHzのレゾネータを使用しています。LEDやスイッチを同じポートに接続すれば、#175/#175A ATtiny2313 USB DIPモジュールでも使用できます。
mega168用はこちら
(1) LED点灯
(2) LED点灯,スイッチ入力
(3) LED点滅(TIMER0/CTC)
(4) 高速PWM制御(TIMER0/PWM)
(5) I2Cマスタ送信 #176 MCP23017制御
(6) I2Cマスタ送受信 I2C-EEPROMのデータの読み出し
(7) I2Cスレーブ送受信
(8) I2Cマスタ送受信
このページのサンプル・プログラムは、AVR初心者の導入として用意しました。作者もAVR初心者です。実は#179は作者自身が学習に使用するために製作した基板です。ここに掲載しているプログラムはAVRで初めて作ったプログラムです。サンプル(6)の掲載時点でAVRプログラム暦4日ですので、まずいところがあるかもしれませんが、その点はご容赦ください。
I2C関係のプログラムは複雑になったため、初心者向けとはいえませんので、難しいと思ったら無視してもらって結構です。
学習の過程で作成したプログラムは初心者のかたに有用と思われるものはここに追加していきます。とりあえず、アセンブラで作成していますが、そのうちAVRのC言語を始めたらC言語のプログラムも掲載する予定です。
プログラムは無保証、無サポートです。改良などのため予告なく変更することがあります。
なお、ファイル名変更やロケーション変更などの可能性があるため、個別ファイルに直リンクされないようにお願いします。
(1) LED点灯 (07/08/11) | 出力ポートの使用法 |
単純にLED1を点灯させるプログラムです。PORTDを出力ポートに設定して、そのLEDを点灯させるだけです。マイコンを使う上で最も基本となる処理です。 | test1.zip |
(2) LED点灯,スイッチ入力 (07/08/11) | 入力ポートの使用法 |
スイッチの状態によりLEDをON/OFFさせます。タクト・スイッチを押したときにOFF、離したときにONします。入力はPORTDレジスタではなく、PINDレジスタから読み出すことに注意してください。また、入力に設定したPORTDのビットに"1"を書き込むとそのビットに対応するポートのプルアップが有効になります。マイコンを使う上で最も基本となる処理です。 | test2.zip |
(3) LED点滅(TIMER0/CTC) (07/08/11) | CTCモードの使用法 |
タイマ0を使用してLEDを点滅させます。タイマ0のコンペア機能を利用して一定の周期タイミングを生成します。コンペア・マッチすると、タイマ0は自動的にクリアされます(CTCモード)。時計などを作るときの基本となる仕組みです。 | test3.zip |
(4) 高速PWM制御(TIMER0/PWM) (07/08/11) | PWMの使用法 |
LED2を消灯状態からだんだん明るくしてまた消灯してと、それを繰り返します。PWMでLEDの明るさを制御するプログラムです。LEDが接続されている0Bチャネル(OC0B/RD5)を使用しています。LEDの代りにトランジスタなどを使ってDCモータをドライブすれば、回転速度制御などに応用できます。 | test4.zip |
(5) I2Cマスタ送信 #176 MCP23017制御 (07/08/13) | USI使用I2Cマスタ |
tiny2313のUSIモジュールを使用したI2Cマスタ(マスタ送信のみ)のプログラム・サンプルです。#176 I2C 16ビットI/Oエクスパンダ のGPIOAを出力ポートに設定して、そこに接続されたLEDの表示を約1秒毎に更新します。0〜255のバイナリ値を順番に表示し、それを繰り返します。 クロック・ストレッチはサポートしていません。 今回からスタックを定義してサブルーチンを使っています。 ロジアナ実測波形 配線
TWIモジュール使用のプログラムはこちらのページにあります。 |
test5.zip PW="avr" |
(6) I2Cマスタ送受信 I2C-EEPROMのデータの読み出し(07/08/23更新) | USI使用I2Cマスタ |
tiny2313のUSIモジュールを使用したI2Cマスタ(マスタ送信、マスタ受信)のプログラム・サンプルです。 I2C-EEPROMの24LC64のデータ読み出しの簡単な使用例です。 最初に1度だけデータを書き込む処理を追加したプログラム"test6-2"を用意しました。(07/08/26) 従来からの"test6"にはROM書き込みの処理は含まれていません。 クロック・ストレッチはサポートしていません。 動作中はスタート・コンディションを発行するたびにLED1の状態が反転します。ROMがつながっていない場合でも点滅します。このLED1はハングアップしていないか確認するためのものです。 ROMアドレス0x1234にROMデータ0x56が書き込まれている場合、それが正常に読み出されるとLED2が点灯します。それ以外は消灯した状態です。 初めに1度だけROMアドレスの0x1234、0x1235にROMデータ0x56、0x78の2バイトを書き込む処理を追加したプログラム test6-2を追加しました。(07/08/26) 配線
※SCL、SDAのラインは4.7K程度のプルアップ抵抗が必要です。 BUG FIX 07/08/23 ファイルを差し替えました(ファイル名は同じ)。 TWIモジュール使用のプログラムはこちらのページにあります。 |
更新 07/08/23 test6.zip P/W="avr" 追加 |
(7) I2Cスレーブ送受信 (07/08/23) | USI使用I2Cスレーブ |
tiny2313のUSIモジュールを使用したI2Cスレーブのプログラム・サンプルです。1バイトのデータをスレーブ受信し、そのデータを保持して次回マスタから読み出されたときに、そのデータをスレーブ送信します。 また、受信した内容の下位2ビットの値をLED1とLED2に表示します("1"でON、"0"でOFF)。 この処理は、コンパイラのライブラリにあるような、1つの関数で送受信を待ち受けるものとは違い、簡易マルチタスク型のイベント・ドリブン方式になっています。これは「マイコンの1線2線3線インターフェース活用入門」で作成したPIC、H8版のスレーブ・プログラムと同等なものです。このような構造にすることの利点は、いつでも送受信の処理ができることです。したがって他の処理(たとえば7セグメントLEDのダイナミック・ドライブの周期処理やRS-232Cシリアル受信など)とは非同期に処理ができます。 <メイン・ループ> <イベント・ハンドラ> サブルーチン"SlaveSend"はマスタがデータを読み出そうとしたときに、スレーブ送信する直前にコールされます。このルーチンがコールされたら、送信するデータをレジスタAccにセットして戻ります。ここでは、先に保存したレジスタ"I2CData"の値を返します。 TWIモジュール使用のプログラムはこちらのページにあります。 |
test7.zip PW="avr" |
(8) I2Cマスタ送受信 マスタ-スレーブ送受信テスト用のマスタ (07/08/23) | USI使用I2Cマスタ |
(6)のマスタ送受信の処理を元に、(7)のスレーブと通信するように変更したものです。I2Cのサブルーチン部分は同じものです。
図のように2つの#179相当のボードに(7)のプログラムと(8)のプログラムをそれぞれ書き込み、2つをI2Cバスで接続して通信させます。 マスタからは、1バイトのデータをマスタ送信します。 スレーブはそのデータをスレーブ受信して、レジスタへ保存します。また、このデータの下位2ビットの状態をLEDに表示します。 マスタは、データをマスタ送信したあと、少し待ってから今度は1バイトのデータをマスタ受信します。この受信データの内容は先ほどマスタ自信が送信したものと同一ですが、この値に+1したものを次回のマスタ送信データとします。 スレーブはマスタからデータを読み出されたときは、先に受信してレジスタに保存してあるデータをスレーブ送信します。 マスタがわざわざ、マスタ受信した内容を+1したものを次回の送信データとしているのは、マスタとスレーブのそれぞれで送受信が正常に行われたことを確認するためです。マスタ受信した内容が不正なら、次回マスタ送信するデータも不正になり、結果的にスレーブのLEDの表示が乱れることになります。 |
test8.zip PW="avr" |
検索エンジン対策のため、一部パスワードがかかっているものがありますが、パスワードはzipファイルの下にかかれていますので、お手数ですが、それを使って解凍してください。
I2Cに関してはこちらで簡単に説明していますので、参照ください。
マスタ・プログラムはまだ簡単なほうなので、スレーブ・プログラムを作成するときにはもっと手間取りそうです。今回I2Cマスタのプログラムを作りはじめてから、まともに動くまで、ロジアナを使いながら思考錯誤した結果、丸一日費やしました。ロジアナがなければ、手探り状態なので、もっと時間がかかったことでしょう。
スレーブ・プログラムの場合、スタート・コンディションを割り込みで検知したあと、スレーブ・アドレスのチェックなどはソフトウェアで処理しなければなりません。つまり、自分宛てかどうかはコントロール・バイトを受信しなければ分からないため、他のスレーブ宛ての通信でも、コントロール・バイトの受信処理だけは、バス上の全てデバイス(AVR USI使用デバイス)が実行しなければならないということです。たくさんのスレーブ・デバイスがつながっていて、かつ、通信の頻度が高いと、各スレーブ・デバイスは自分宛てでない通信でのオーバヘッドが増えるということになります。
片やPICのMSSPでマスタ送信する場合、基本的にはあるレジスタにデータを書き込むと、あとは8ビットのデータ出力からACKの入力まで自動でやってくれますので、割り込みやフラグで送信が終わったことをチェックするだけで済みます。またスレーブの場合でも、スタート・コンディションを受けて、アドレスが一致するまでは、すべてハードウェアが面倒を見てくれるため、自分宛ての受信があったことを割り込みやフラグで検知すれば、あとはデータを取り出すだけの簡単な処理で済みます。PICのMSSPを使ったあとにAVRのUSIを使うと、プログラムの煩雑さに少々戸惑うことになります。
USIにもいいところがあって、たとえば、シフト・レジスタのおかげで、1ビットずつ入出力するという手間が省けて、ソフトウェア処理ではどうしても時間のかかるビット処理の部分が短時間で処理できます。とくにスレーブ側のプログラムでSCLのエッジを監視しなくてよいのはかなり楽です。この部分はスルーレートにかかわりますので、ソフトウェアだけで作るよりはかなり有利です。
ところで、マニュアルの誤記と思われるものを1つ挙げておきます。まだtiny2313しか使ったことがないので、これがtiny2313に限られるかどうかはわかりません。
USICRのUSICS1とUSICS0でクロック・ソースを外部クロック(SCL)に設定する際、マニュアルには「立ち下がりエッジ」でシフトする、という設定が、実際は「立ち上がりエッジ」でシフトします。これは、回路のブロック図とも食い違っているのですが、実際にマニュアルの通りでは動きませんでした。他をいくらいじってもシフト・レジスタに入るデータが1ビットずれるので不審に思い、逆にしてみたらうまくいったという次第です。ターゲット・ボードには8ビットの数値を表示する手段がなにもないので、LEDのポートに8ビットのパルスを出力させて(0/1でパルス幅を変える)、それをロジアナで読んで確認したりしました。ずれているのは分かっても、何でずれるのかがさっぱり分かりませんでした。
まあ、時間はかかりましたが、ATtiny2313を使ってI2Cスレーブがつくられれば、安価なスレーブ・デバイスへの応用が期待できます。作者がUSIにこだわる理由はそこにあります。
別の案件として、そのうちtiny2313を使ってOne Wireのスレーブ・デバイスも作ってみたいと考えています。