2007年03月26日

プログラムの説明

あんまりたいした内容ではないのですが、eyecat-0.1.zipに含まれる eyecat-test.c についてポイントを解説しておきます。
読み手を想定して書いているわけではありません。-- 実はプログラムを引用して説明を書く練習だったりします。


平タスク

平タスクともメインループとも呼ばれる典型的な処理です。いろいろ凝った仕掛けを作ろうかと思ったこともありましたが、最近はもっぱらこの形式で書いています。注意点としては、イベントの中で止まらないようにすること。特にこのプログラムでは、LED の連続点灯になってしまうとマズイので注意が必要です。具体的に書くと getc() は入力データがないとき待ちになってしまうので、 can_getc(1) で読み込めるかどうか確認するとか...
あと、イベントに変数を使うときは volatile を付けること。これを忘れるとレジスタにコピーした値をずっと参照して、イベントが上がらないケースがあります。


int main(void)
{

/* set system_clock pre scaler 1/8 => 1/1 */
CLKPR = (1<<CLKPCE);
CLKPR = 0;

各種初期化

sei();

for(;;) {
wdt_reset();
poll();

if (イベント1) {
      イベント1の処理
}
if (イベント2) {
      イベント2の処理
}
:
}
}


タイマー処理

一定間隔である処理をさせたいとき使う処理に以下の set_timeout / check_timeout ってのを作って使っています。時間の定義は 最小の時間と最大の時間が int16_t の正の範囲(0-32767)に収まるようにプログラム毎に調整しています。ちなみに、変数とかの型は、uint8_t とか使ってサイズと signed/unsigned を明示するようこころがけています。-- こう書いておくと、プログラムの一部を PC にもっていってテストする場合に便利なのです。


static inline uint16_t get_time() {
return TCNT1;
}

static void set_timeout(uint8_t chan, uint16_t t) {
to_time[chan] = t + get_time();
to_flag[chan] = 1;
}

static int8_t check_timeout(uint8_t chan) {
if (to_flag[chan] && (to_time[chan]
         - (int16_t)(get_time()) <= 0)) {
to_flag[chan] = 0;
}
return !to_flag[chan];
}

使用例:
if(check_timeout(TO_DOT)) {
          :
set_timeout(TO_DOT, 24);
    }


詳しいコメント:

TCNT1を直接使えばよいものを get_time で ラップ(wrap)しているのは、ATtiny861 みたいな HIとLO が別々のレジスタになる拡張に対応できるようにしたため。

to_flagが冗長で無駄のように思えるかも知れません。以前は使っていなかったのですが、そうすると set_timeoutで最初の TIMEOUT を設定しないといけないので、フラグを使うようにしました。1bit の情報を扱うのに 1バイトも!使うのは無駄だと思う場合は、set_timeout/check_timeout を inline 化して to_flag を bitmap にする場合もあります。

timeoutの名前の由来は、UNIX。もともとは、timeout という関数で時間が来れば登録した関数を callするものですが、そこまでするとコードを小さくできないので set_/check_ という プレフィックスを付けた二組の関数にしました。もちろん 定期的な処理だけでなく(名前のとおり)一定の時間が立つのを待ち合わせるのにも使えます。

ボタンの処理


static uint8_t button_read() {
static uint8_t b1_state;

b1_state <<=1;
if (bit_is_clear(ROW2_PIN, ROW2)) {
b1_state |= 1;
}
if (b1_state == 0 || b1_state == 0xff) {
:
}
}


ざっくり簡略化すると上のような処理になっています。これはチャタリング除去の処理で、8回連続(120Hz なので、66ms の間)同じ値なら採用するというもの。
posted by すz at 21:18| Comment(0) | TrackBack(0) | USBアイキャッチャー

製作とテスト



製作とテストが完了しました。以下レポート

製作
オモテ



表は、わりとすっきりした感じになりました。隠れている右上の部分に、↓のように割とゴミゴミした感じで USB の電流制限抵抗と電圧制限のツエナーダイオードが付いています。ISPコネクタは一列でないと、ISPを付けたまま動作確認ができません。(LED と干渉します)



ウラ



裏には、LED の電流制限抵抗が結構あります。中央の 2.2Kは USBのプルアップ。(部品直結以外の)配線は電源入れて16。ほとんど1:1なので楽な方ではないかと思います。↓は抵抗直結の部分の拡大写真。高さを 3mm に抑える必要があるので、こんなつけ方になりました。片側を先に付けて、押し込みながら反対側を付けるというやりかたでなんとかなりました。配線材は色つきのポリウレタン線(UEW) 0.18φ(らしい)。千石(店頭)で買ったやつ -- 色が付いていないと被覆が熔けたかどうか(私には)わからないです。(次は、エレ工房さくらいの 0.2φ(赤)にしようと思います)あと、左端の部分は使っていませんが、これはケースと干渉するためです -- 要注意。



製作時間は 6時間ぐらい。量のわりに時間がかかっているのは、配置をアレコレ考えながら作ったため。

テスト

普通は、LED を点灯させることから入りますが、このケースでは連続点灯はやばいので、USB の動作確認を先にやりました。通信さえできれば、あとは自由に制御できます。まず、端末ソフトを使ってコマンド入力できるようにしました。S を入力すると EYECAT なんてのが帰ってくれば OK 。つぎは点灯コマンドを追加していって確認。点灯コマンドは、z -- 全点灯 、x -- 縦線移動 、c -- 横線移動。あと大事なのは 消灯コマンド(v) やばいと思ったらすぐ消灯できる必要があります。

最初の写真は、全点灯の実行結果。十分かどうかわかりませんが、結構あかるく点灯しました。作ってしまってから思ったのですが、75Ωで作っておいて、電源側にダイオードをソケットでつけられるようにしておくと、緑のLEDと差し替えできてよかったかも知れません。

ボタンのテスト

ボタンは、ROW1/ROW2 の線を共用しました。作ってしまってから気がついたのですが ROW は、アノードじゃなくてカソードでした。これだと ボタンを押したとき 2.2Kの抵抗を通して電流がながれて ROW1/ROW2 の1ラインがうっすらと点灯してしまいます。この部分は、(抵抗の切れ端で)直接配線してしまったので、直すの面倒。そのまま使うことにしました。

それはともかく、テストしていたらボタンを誤認識します。どうもプルアップしてから電圧が安定するまでに時間がかかるのが原因らしく、delayを入れたら解決しました。

テストまでのソースコードを eyecat-0.1.tar.gzeyecat-0.1.zipに置いておきます。USBのコードが GPL なので、ライセンスはGPLになります。このテストコードを元にあれこれやったほうが楽しいのではないかと思いますので、完成版のコードは公開しないかも。
posted by すz at 16:13| Comment(0) | TrackBack(0) | USBアイキャッチャー

2007年03月22日

USBアイキャッチャーの設計

USB シリアル接続で、8x8ドットマトリックスLEDとボタン2つを制御するものを作りたい思っています。玄箱にとりつけて、ちょっとした情報を表示させたりする用途を考えていますが、他にも面白い使い方ができるかも知れません。8x8しか表示できないものをディスプレイとは言い難いのでアイキャッチャーと名づけました。

コンセプト

まず、玄箱の上に乗せても違和感のないサイズにするというのが第一。タカチ SW-55に入るようにしたいと思います。たった8x8しか表示できないものにあんまり手間やお金をかけたくないので、次に安く簡単に作れるということを目標にしたいと思います。

部品の選定
8x8ドットマトリックスLEDは、秋月の BU5004-R..このサイズでないとケースに入らない。しかも90円と格安なので文句なし。ボタンは、プッシュスイッチ AJN1B32 ケースに入れるので、背が高いこれにしました。コントローラは、ATmega48。必要ピン数をクリアして最も安いもの。(300円〜350円ぐらい)
ちなみに 200円のBU5004-RGの 中央部のピンを切り取ることで緑バージョンも作れます。ただし電流制限抵抗も変えないと暗めになってしまいます。

部品の配置




仮組みですが、こんな感じになりました。ATmega48をじか付けしないと無理そうです。しかもピン数が多いので↑のようにしか配置できない。逆にBU5004-Rは、ソケットにします。普通に差すとUSBコネクタと同じ高さで、ケースぎりぎり。プッシュスイッチはこの配置にしないと、外観が悪くなってしまいそうです。簡単に作れるのが目標なのに、なんだか配線が辛そうになってしまいました。

ピンの割り当て

ATmega48 は、28 pin ですが、電源やリセット、水晶などを除くと自由に使えるピンは、20。USBには2ピン(PD2/PD3) 必要で、16ピンは、ドットマトリックスLEDで使います。のこりは 2。これをボタンに割り当ててしまうと、拡張の余地がなくなってしまうので、ボタンはLEDと兼用することにして..2ピンをあけておくことにします。あけるピンは、TXD/RXD が順当だろうと思います。ドットマトリックス用のピンは極力隣り合ったもの(計10ピンしかないけど)を使うことにします。
具体的に書くとこんな感じ、赤の部分が楽できるところで10ピン。右の部分が変則なのは、ISPのためで COL/ROWをどちらかに統一しないとLEDに電流が流れてしまうのです。

追記: もうひとつ楽できるところがありました。



LEDの制御と電源

ドライバなしで光らせるので流せる電流には限りがあります。複数ドット同時に光らせるとすると、光らせるドット数によって1つのLEDの明るさが変わりムラができてしまう。なので、64ドットを順に光らせる(1/64 duty)ことにします。(これだと確実に同じ明るさになります。) リフレッシュレートを120Hzとすると x64で7.68kHz -- 1dotあたり130 us ほどで切り替える必要があります。この処理を平タスクでやることにします。(USBの応答性を保証しないといけないので、割り込みはちと面倒なのです)。さて、電流はどれぐらい流せるのかというと ... AVR は 40mA流せますし、LEDの方も 1/16 duty 以下なら 60mAほど流せるようです。電源を5Vにして電流制限抵抗を100Ωにすることにします(33mA)。(緑バージョンなら75Ω)。電源に入れるコンデンサは USBの規格上直結だと10uFが最大のようです。...となると光らせる間隔をコントロールするか、リフレッシュレートを上げるかしないといけないかも知れません。


たとえば上半分を光らせるとして普通に制御すると消費電流は、リフレッシュレートと同じ周波数で変動することになります。安定した明るさで光らせるにはそれに見合ったコンデンサをつけないといけないわけです。分散して光らせられるようにすれば、コンデンサも小さくできます。光らせるドットの数がわかっていれば、1/64 に分割した時間のどこで光らせるかを決めるのは難しい処理ではありません。


拡張案

いまのところ、サブ基板でLEDを増やしていけるようなものを考えています。実は過去にこんなの↓を作ったことがあって、サブ基板もそれをベースにモディファイしようと思っています。(もちろんこんないいかげんなものじゃなくて、本体と同じように部品を配置します。)ドットマトリックスLED一個あたりATtiny2313を1個使う前提で良いなら、とても簡単そうです。

↓のように抵抗でつなぐか、直結すればよいわけです。配線を簡単にするためには、あえてTXD/RXDはポートとして使い、余ったICPを通信用(受信ONLYか)にすればよいのではないかと思います。

ベースにするつもりのコードを置いておきます。
bu5004s-0.1.tar.gz と bu5004s-0.1.zip
これは、過去に作ったコードを↑のピン配置にあわせただけのもの。EEPROM に設定した8バイトまでのASCIIコードをスクロール表示するものです。ソフトシリアルの部分は作っただけ -- 動かしたこともありませんので信用できません。


回路図案



いまのところこんな風にしようと思います。ボタンは ANODE 側 ROW1 と ROW2 を共用してつけようと思います。ボタンを押していなければ表示にまったく影響しないし、ボタンを押していても 2.2K の負荷が(並列で)増えるだけなので、ほとんど影響ないと思います。ボタンのセンスは LEDを光らせない HI-Z の状態から、ROW1/ROW2 を pullup にして読み取ればOK。

追記:回路図変更しました。
USBのプルアップ抵抗を 配置の都合で抵抗の内側に変更。

ROW1 と ROW2 で作ってしまったのですが、ROW はカソードでした。もう作ってしまったので直す気はないんですが... カソード側だと ボタンを押したときに2.2K の抵抗を通して電流が流れて ROW1 と ROW2 の列がうっすら点灯します。
posted by すz at 12:37| Comment(0) | TrackBack(0) | USBアイキャッチャー