Sim's blog

電子工作はじめてみました

PSoC NV

2008-09-29 23:53:25 | PSoC
EDNに「Cypress社、不揮発性SRAMを統合した「PSoC」の新ファミリを発表」という記事が出ていました。電源電圧の遮断を検知するとSRAMの内容を不揮発性メモリに自動で退避してくれるんだそうです。「なお、データ退避時の不揮発性メモリーアレイの電源としては、68µFの外付けコンデンサを使用する。」なんて書いてあります。どういう用途を想定しているんでしょうね。
うーん、自分ならこう使うとか、思いつかないのがちょっぴり悲しい。



ICFP 2008の結果が出ています

2008-09-28 14:51:31 | ICFPプログラミングコンテスト
ICFP 2008の顛末の続きです。

ICFP Programming Contest 2008結果が出ています。1位はTeam Smartassで2006年から3連覇です。googleのチームということです。2位は日本人の方です(shinhさんのブログ)。おめでとうございます。
スコアは5回試走したうちの上位3つの合計です。コースは11個あります。各コースに足きりスコアが設定されていて、足きりされると次のコースに進めなくなります。最後の11コースに進んだのは14チームです(11コースの結果)。私のは1コースで足きりされています。

1コースから8コースまではマップが公開されています(9~11の3つはまだ)。どんなコースだったか見てみました。

コース1


コース2


コース3


コース4


コース5


コース6


コース7


コース8


まだ公開されていませんが最後の2つのコースが迷路みたいなコースだったんじゃないかと思います。

AVRイーサネットを作ってみました

2008-09-28 10:35:46 | AVR
AVRイーサネットの続きです。

前回は、スイッチサイエンスさんがAVRイーサネットキットのモニターを募集中という記事でした。その後、オリジナルキット「AVRイーサネットプラットフォーム(キット) 」として発売も開始されました。私も一応、応募していたのですが返事がなかったので抽選にはずれたと思っていました。そんなある日のこと、応募メールが迷惑フォルダーにはいっていたそうで、試してみますか?というメールがきました。ぜひともと、返事をしたところ速達で送ってくれました。こんなこと言うと怒られちゃいそうですが、もう商品化されていることですし、無視しちゃってもよかったのに、わざわざ連絡をくださるなんて本当に誠実な方だと思いました。

とりあえず組み立てたてて、動作するところまで確認しました。途中撮った写真を並べます。

送られてきたパッケージの中身です。

部品がはいっている袋の右上にはMACアドレスがシールで貼ってあります。一緒に入っていた紙は部品表です。

部品のはいっている袋です。


部品を広げてみました。

部品数はそんなに多くないです。AVR ATMega168にもMACアドレスのシールが貼ってあります。シールのない方がENC28J60です。

基板です。

部品の形が印刷されていて分かりやすくなっています。足の間に二本線がついているのがコンデンサです。抵抗のところにも抵抗の形がついていて分かりやすくなっています。

中央に「SSCi AVR Ethernet v0.1」と書かれています。


お約束どおり、背の低い部品からつけていきます。

積層セラミックコンデンサは足の幅が2.54mmのものが入っているので部品の足の加工が不要です。右下の黒いのがフェライトビーズです。

R4'は回路図にはあったのですが、部品にはありませんでした。

チップ抵抗もつけることができるということなのでしょうか。

残るはモジュラージャックだけです。

ICソケットの間のピンはICソケットより前につけています。狭そうだったので後でつけるのが難しそうだったからです。R2の1kΩがLEDの電流制限抵抗です。青とか他の色に変えるときはR2も変える必要がある場合があります。ブレッドボードに挿すことを考えているので足は丸ピンのものにしています。秋月の丸ピンICソケット・両端オスピン(シングル40P)を折って使いました(通販番号P-01382)。手前が18pin、奥が6pinです。

完成です。

モジュラージャックは足がいっぱいあるので、折らないように慎重に挿します。また、平らになっていないので、前の方からつけないと浮いてしまいます。完成しておら思ったのは、AVRの方のICソケットは丸ピンにしておいた方がよかったかもしれません。抜き差しがあるかもしれないからです。

3V3とGNDがショートしていないことをテスターで確認しました。

動作チェックです。

電源は秋月の3.3VのACアダプタです。サンハヤトのコネクター変換基板CK-23を使って給電しています。この変換基板はブレッドボードで使うのにぴったりのサイズです。
このボードのIPアドレスは192.168.18.24です。AVRのEEPROMに書き込まれているそうです。PCとはクロスケーブルでつないでいます。PCのIPアドレスを192.168.18.1に変更しました。ping 192.168.18.24とすると返事が返ってきます。また、arp -aとするとMACアドレスも見れます。ブラウザ(firefox)でhttp://192.168.18.24/secret/につなぐとLEDのオンオフができます。写真はLEDがついているときの様子です。


とりあえず、してみたことは、ここまでです。

作るときの注意は、J2(ICソケットの間の6pin)は、ICソケットより先につけることと、モジュラージャックを浮かないようにつけることの2つです。
改造としては、pinを丸pinにしたことだけです。他に考えられるのはpinのかわりにソケットをつけるとか、LED(と電流制限抵抗R2)を変えることです。
他の部品があたるのでISPコネクタにボックス型のソケットをつけることはできません。
AVCCと電源の間にノイズ低減用のインダクタを入れれるとよかったかもしれません。
スイッチサイエンスさんも書いておられますがリセットは切り離せるとよかったかもしれません。ただし、ジャンパーピンを設置する余裕が基板にはありません。
あと要望としては、AVRの外部クロック動作です。やはり内蔵クロックの8MHzより高速に動かしてみたい気がします。現状ではENC28J60のCLKOUTがAVRのXTAL1につながっています。


とりあえず、スイッチサイエンスさんのAVRイーサネットを作ってみました。ブレッドボードにいいサイズでちっちゃくてかわいいです。
ファームウェアのソースも公開されているので、できれば改造して遊んでみたいのと、超低コスト インターネット・ガジェット設計の例題を動かせないか試してみたいと思っています。

LPT接続版BDMデバッガの記事(Interface 11月号)

2008-09-27 00:45:11 | その他のマイコン
Interface誌2008年11月号に「Interface2008年9月号付属ColdFireマイコン基板を活用するためのLPT接続版BDMデバッガ・インタフェースの製作と使い方」という記事が出ています。最初の2ページだけpdfで読めます。

回路は74LV244Aをバッファにしたレベル変換回路です。74LV244AをぐぐってみるとTIのSN74LV244Aが見つかりました(pdfへのリンク)。動作電圧が-0.5~7V 2V~5.5V、入力電圧も-0.5~7V 2V~5.5Vです(最大定格)。今回は3.3V動作で入力が5Vトレラントです。秋月で売っているTC74VHC244Fでも代用できます(通販番号I-01125)。TC74VHC244Fも動作電圧-0.5~7V 2V~5.5Vで入力電圧も-0.5~7V 2V~5.5Vです(最大定格)。5個で100円なのでお買い得です。

監修にぐらろさんの名前があります。また、参考文献に@eleのURLがあげられています。

最後のページ(p.136)に「緊急告知 USB接続BDMデバッガ開発中!」と書かれています。次号(12月号)で公開する予定だそうです。


以前(8/11)、BDMデバッガについて調べて、すんさんの掲示板に投稿したのですが、ここにも載せておきます(掲示板の記事へのリンク)。1ヶ月くらい前なので情報が古くなっているかもしれません。

- BDMケーブルというかMULTILINKにも色々とあるようです。そのあたりの話はnoritanさんが書かれています(リンク)。
- FREESCALE推奨のものは、以下になります。Interface9月号にも写真が出ていますね(リンク)。
- BDMについては、hamayanさんの所で色々と議論がなされているようです(リンク)。
- また、k_tさんのところでも色々情報が出ています(リンク)。
- BDMの自作については、この掲示板(すんさんの掲示板のこと)にも顔を出されるきぃたんさんが色々と情報を集められています(リンク)。きぃたんさんの製作記事
- sentec社のパラレルポートBDM (回路図あり) (リンク)
- 自作のパラレルポートBDM (cfpod.pdf 回路図あり) (リンク)
- USB版BDMケーブルTBLCF (回路図あり) (リンク)
- パラレルポートのものは、CPLDを、USBのものはHCS08を使っています。
正確な経緯はよくわかっていませんが、きぃたんさんの情報を元にぐらろさんという方が、BDMケーブルを2種類作られているそうです。回路図は@eleというSNSサイトの会員なら見れます。SNSですが、特に紹介もいらず、メールアドレスだけ登録すれば会員になれるようです。一番のお勧めがぐらろさんの回路みたいです。(@eleへのリンク)
- ぐらろさんの回路図を元にmasatoさんが実際にBDMケーブルを作られています(8/9の記事)。 バッファ用のIC1個、抵抗数本といった程度の部品で作れるようです。
- ColdFireはBDM、JTAG、EzPortという3種類の書き込み方法(前2つはデバッグも含む)があります。EzPortについては、きぃたんさんが調べておられます(リンク)。
- masatoさんに教えてもらいました。オプティマイズさんでも作られているそうです。回路図も見れます(リンク)。こちらもぐらろさんの回路を参考にしているみたいです。

その後、すんさんの掲示板の常連さんのkawanaさんがBDMデバッガを作成されたようです。

秋月でAVRISP mkIIが4000円

2008-09-24 22:31:13 | AVR
秋月でAVRISP mkIIの取扱いが始まっています。お値段は4000円とかなりお安くなっています(通販コードM-02582)。ちゃんと調べたわけじゃないですが国内最安じゃないでしょうか?
AVRISP mkIIはATMEL純正のライタで、ほとんど全てのAVRへの書き込みが可能です。USB接続なのでシリアルポートやパラレルポートのないPCでも気軽に使えます。ソフトは純正のAVR Studioを使えます。ISPも可能です。
注意点としては、高電圧書き込みには対応していないことと、デバッグはできないことです。また、給電する機能はありません。接続端子はATMEL標準の6pinのものです。

pickit2の4000円といい、いいぞ秋月!!

温度センサーLM73を使ってみる

2008-09-23 18:54:02 | AVR
エレキジャックNo.8に、ナショナルセミコンダクタの温度センサーLM73が載った基板が付録についてきました。マイコンとはI2Cで通信します。

LM73基板です。

足とパスコン(0.1uF)をつけています。パスコンはつけなくても、基板の外(2pinと3pinの間)につけてもいいです。穴が開いているのでチップコンデンサでなくてもいいのですが、チップ部品のはんだづけの練習もかねてつけてみました。ちょっとななめってます。

pin配置です。エレキジャックにpin配置が載っていなかったので、データシートから写しました。
1 ADDR I2Cのslave addressを決めるpin。openで0b1001100になる
2 GND
3 Vdd 2.7~5.5V
4 SMBCLK I2CのSCL (要pull up)
5 #ALERT 範囲外出力
6 SMBDAT I2CのSDA (要pull up)

つなぐ必要があるのはGND(2pin)、Vdd(3pin)、SMBCLK(4pin)、SMBDAT(6pin)の4本です。内部レジスタに設定した範囲を超えるとALERT信号を出すことができますが、使わなければつながなくていいです。SMBCLKとSMBDATのpull up抵抗はエレキジャックのミッション2第1章では3.3kΩ、第2章では1kΩです。ちなみに第1章ではLM73をPICに、第2章ではHCS08につないでいます。

このところAVRづいているので、AVRにつないでみます。

I2C通信の参考にしたサイトです。
趣味の電子工作の部屋 by すん I2Cコントロール実験
AVR試用記 I2C通信
エレキジャック 1、2、3線シリアル・インターフェース

I2Cでマスターからスレーブにデータを送るには以下の手順になります。
(1) スタートビットを送る
(2) スレーブのアドレスとWを送る(SLA+Wといいます)。
(3) ACK/NAKをもらう
(4) データを送る
(5) ACK/NAKをもらう。必要なだけ(4)と(5)を繰り返す
(6) ストップビットを送る

I2Cでマスターからスレーブのデータを受け取るには以下の手順になります。
(1) スタートビットを送る
(2) スレーブのアドレスとRを送る(SLA+Rといいます)。
(3) ACK/NAKをもらう
(4) データを受信する
(5) ACKを返して、さらにデータをもらうために(4)に戻るか
NAKを返して、もうデータがいらないことを伝える
(6) ストップビットを送る

上の2つを組み合わせたパターンもあります。そのときは、受信時のスタートビットはリピーテッド・スタートと名前が変わります。また、上の手順ではエラーチェックをしていませんが、やたら細々とエラーチェックが必要になります。

ATMega88はTWIというI2Cのハードがついているので、レジスタをいじることでI2C通信ができます。全部ソフトで書くのよりは随分と楽になります。

実験している様子です。

上に見えているのがライター代わりの78K0付録基板(トラ技8月号)です。左側がRS232C通信用の秋月製FT232RL USBシリアル変換モジュールです。中央がAVR ATMega88で、右側が今回のLM73付録基板です。秋月で売っている小型温度計モジュール(通販番号M-01063)で温度を測っています。温度計の影になっていますが電源は3.3VのACアダプタです(実測3.5V)。
0.5秒毎に、LM73で測った温度データはI2CでATMega88に読み込まれてUSBシリアル変換モジュール経由でPCに送られます。

ソースです。<と>は全角になっています。
#include <avr/io.h>
#include <util/twi.h>
#include <util/delay.h>

typedef unsigned char byte;

// USART関連は省略

// 16進1桁出力
void puthex1(byte d)
{
    d += '0';
    if(d > '9') d += 'a' - '9' - 1;
    putch(d);
}

// 16進2桁出力
void puthex2(byte d)
{
    puthex1(d >> 4);
    puthex1(d & 0x0f);
}

// 10進2桁出力 (x < 100のみ可)
void putdec2(byte x)
{
    putch('0' + x / 10);
    putch('0' + x % 10);
}

// エラー
void i2c_error(void)
{
    putch('['); puthex2(TWSR); putch(']'); // TWSRの内容
    putch(0x0d); putch(0x0a); // 改行
    PORTB = 0x01; // LED点灯
    while(1) ;
}

// 通信速度の初期化
void i2c_init(void)
{
    TWSR = 0b00000000;  // 1分周
    TWBR = 32;          // 100k = 8MHz / (16 + 2 * TWBR * 1)
}

// master 1byte送信
void i2c_write(byte d)
{
    TWDR = d; // 送信データ
    TWCR = _BV(TWINT) | _BV(TWEN);
    while( !(TWCR & _BV(TWINT)) ) ; // データの送出完了待機
    if((TWSR & TW_STATUS_MASK) != TW_MT_DATA_ACK) i2c_error();
}

// master 1byte受信(ackを返す)
byte i2c_read_ack(void)
{
    TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWEA);
    while( !(TWCR & _BV(TWINT)) ) ; // 受信完了待ち
    if((TWSR & TW_STATUS_MASK) != TW_MR_DATA_ACK) i2c_error();
    return TWDR; // データを返す
}

// master 1byte受信(noackを返す)
byte i2c_read_nak(void)
{
    TWCR = _BV(TWINT) | _BV(TWEN);
    while( !(TWCR & _BV(TWINT)) ) ; // 受信完了待ち
    if((TWSR & TW_STATUS_MASK) != TW_MR_DATA_NACK) i2c_error();
    return TWDR; // データを返す
}

// master送信開始、IDはslave address << 1
void i2c_start(byte id)
{
    byte s;

    // 開始条件を送る
    TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
    while( !(TWCR & _BV(TWINT)) ) ; // 開始条件の送出完了待機
    s = TWSR & TW_STATUS_MASK;
    if(s != TW_START && s != TW_REP_START) i2c_error();

    // アドレスを送る
    TWDR = id;
    TWCR = _BV(TWINT) | _BV(TWEN);
    while( !(TWCR & _BV(TWINT)) ) ; // アドレスの送出完了待機
    s = TWSR & TW_STATUS_MASK;
    if(s != TW_MT_SLA_ACK && s != TW_MR_SLA_ACK) i2c_error();
}

// master送信終了
void i2c_stop(void)
{
    TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
    while( !(TWCR & _BV(TWSTO)) ) ;
    // statusはTW_NO_INFOになる
}


#define LM73 (0x4c << 1)    // LM73のslave address

int main()
{
    byte th, tl;

    DDRB  = 0x01;
    PORTB = 0x00;

    usart_init();
    i2c_init();

    // LM73設定
    i2c_start(LM73 | TW_WRITE);
    i2c_write(0x04); // register 4
    i2c_write(0x60); // 14bit resolution
    i2c_stop();

    // ポインタを0にしておく(readするだけで温度が読めるようになる)
    i2c_start(LM73 | TW_WRITE);
    i2c_write(0x00); // register 0
    i2c_stop();

    while(1){
        // 温度受信
        i2c_start(LM73 | TW_READ);
        th = i2c_read_ack(); // 上位読み込み
        tl = i2c_read_nak(); // 下位読み込み(最後はNAKを返す)
        i2c_stop();

        // 結果出力 (マイナスは考えない)
        puthex2(th);
        puthex2(tl);
        putch(' ');
        putdec2(th << 1 | tl >> 7); // 結果出力 整数部
        putch('.');
        putdec2(((tl & 0x7f) * 200) >> 8); // 結果出力 小数部
        putch(0x0d);    // 改行
        putch(0x0a);

        _delay_ms(500); // 0.5秒待つ
    }
}

USART関連(usart_init、getch、putch)は前回と同じなので省略しました。
i2c関係は以下です。
i2c_init(初期化)、
i2c_start(スタートビットを送る)、
i2c_stop(ストップビットを送る)、
i2c_write(1バイト、マスター→スレーブ通信)、
i2c_read_ack(マスター←スレーブ通信とack返答)、
i2c_read_nak(マスター←スレーブ通信とack返答)
エラーを見つけたらi2c_errorに飛んで無限ループになります。
i2c_startは厳密には4種類考えられます(R/Wとstart, repeat start)が、たいへんなので1つにまとめています。

TeraTermで受信している様子です。

左側が受け取った生データで右側が換算した値です。27℃くらいです。
受信データは、16ビット中最上位が符号ビット、8ビットが整数部、7ビットが小数部になっています。11ビット精度のときは、符号1 + 整数部8 + 小数部2です。14bitだと小数部が5ビットに伸びます。

I2Cは、今回初めて使いました。なかなか複雑でデバッグがたいへんでした。

AVRのUSARTを使ってみる

2008-09-23 16:12:13 | AVR
AVRでUSARTを使ってみました。
MAX232のようなレベル変換のICでなくて、秋月で売っているFT232RL USBシリアル変換を使っています(通販番号K-01977)。
FT232RLは3.3VのLDOを内蔵していて、外部に3.3Vを給電することができます。データシートを見ると(4.2)最大50mAを供給できるそうです。入出力の電圧はVCCIOというpinにいれる電圧で決まります。秋月モジュールではJ1を1-2ショートで5V、2-3ショートで3.3Vを選べます。VCCIOはCN2の4pinに出ているので、ジャンパを取り去って、外部から電圧を決めてやることもできます。

秋月のモジュールにはリセット用抵抗端子PU1, PU2というのがあります。PU2の電圧を10kΩ2個で分圧してPU1に出ています(PU2-10kΩ-PU1-10kΩ-GND)。PU1がPU2の半分の電圧になる回路になっています。ついてきた紙には、この回路の使い方が書いてありませんでした。FT232RLのデータシートを見ると、RESET#の説明に
Active low reset pin. This can be used by an external device to reset the FT232R. If not required can be left unconnected, or pulled up to VCC.
と書かれています。resetはオープンにするかプルアップでいいので、秋月のモジュールにあるリセット用回路は使う必要がないみたいです。何のためについている回路なんでしょうね?

秋月のモジュールは次の4本を接続するだけで使えるようになります。

1pin TXD PC→マイコンへのデータ伝送
5pin RXD マイコン→PCへのデータ伝送
7pin GND (24pin GND、内部でつながっている)
4pin VIO I/Oの電圧を外部から給電する(J1のジャンパは取り外す)

秋月モジュールから給電するときは、VIOのかわりに5VならVCC(15pin, 21pin)、3.3Vなら3V3(19pin)をつなぎます。

ATMega88側はRXD(2pin)を秋月モジュールのTXDに、TXD(3pin)を秋月モジュールのRXDにつなぎます。あべこべにつなぎます。お約束通り、最初はTXD同士、RXD同士つないで動かない理由が分かりませんでした。

AVRの初期設定は次の3つです。
(1) UBRR0でボーレートの設定(必要ならUCSR0AのU2X0も設定)
(2) UCSR0Cでパリティ、データビット長、ストップビットの設定
(3) UCSR0Bで送受信の許可

ソースです。
#include <avr/io.h>

typedef unsigned char byte;

byte getch(void)
{
    while(!(UCSR0A & _BV(RXC0))) ;
    return UDR0;
}

void putch(byte c)
{
    while(!(UCSR0A & _BV(UDRE0))) ;
    UDR0 = c;   
}

void usart_init(void)
{
#if 0
    UBRR0 = 51; // 9600bps @ 8MHz
#else
    UBRR0 = 25; // 38400bps @ 8MHz
    UCSR0A = _BV(U2X0);
#endif

    // 19.10.4 USART制御/状態レジスタC
    //         ++------ UMSEL01:UMSEL00 00 非同期動作
    //         ||++---- UPM01:UPM00     00 パリなし
    //         ||||+--- USBS0            0 ストップビット 1ビット
    //         |||||++- UCSZ01:UCSZ00   11 データビット 8ビット 
    //         |||||||+ UCPOL0           0 クロック極性立ち上がり
    UCSR0C = 0b00000110;

    // 19.10.3 USART制御/状態レジスタB
    //         +------- RXCIE0 0
    //         |+------ TXCIE0 0
    //         ||+----- UDRIE0 0
    //         |||+---- RXEN0  1 受信許可
    //         ||||+--- TXEN0  1 送信許可
    //         |||||+-- UCSZ02 0 データビット長
    //         ||||||+- RXB80  0 受信データビット8
    //         |||||||+ TXB80  0 送信データビット8
    UCSR0B = 0b00011000;
}

int main()
{
    // LED設定
    DDRB = 0x01;
    PORTB = 0x01;

    usart_init();

    while(1){
        putch(getch());
        PORTB ^= 0x01;
    }
}

送られてきたデータをエコーバックして、1文字毎にLEDを反転します。
送受信の関数名は最初getcとputcだったのですが、内部モジュールと名前がぶつかっているという警告が出たのでgetchとputchに名前を変えました。

とりあえず、外とお話しできるようになるとデバッグが楽になります。

AVRでタイマー割り込み

2008-09-20 16:57:04 | AVR
このところAVRで遊んでいます。タイマー割り込みを使ってみました。
タイマー割り込みを使うときは以下のことをします。

- avr/interrupt.hのinclude
- 割り込みハンドラを作る
- 割り込み許可レジスタの設定

割り込みハンドラはISR(ベクトル名)というマクロの直後に関数の中身を書きます。
割り込み許可レジスタはTIMSK1というレジスタに値を設定します。

動作確認はLEDチカチカです。14pin(PB0)にLEDと電流制限抵抗をつないでいます。

AVR Libcのページ割り込みのページを参考にさせていただきました。

ソースです。
#include <avr/io.h>
#include <avr/interrupt.h>

// 割り込み処理ハンドラ
ISR(TIMER1_COMPA_vect)
{
    PORTB ^= 0x01; // PB0反転
}

// タイマー初期化
void timer_init(unsigned t)
{
    // 15.11.5 タイマ/カウンタ1比較レジスタA
    OCR1A = t;

    // 15.11.1 タイマ/カウンタ1制御レジスタA (初期値は0x00なので必要ない)
    //         ++-------COM1A1:COM1A0 00 OC1A切断
    //         ||++---- COM1B1:COM1B0 00 OC1B切断
    //         ||||  ++ WGM11:WGM10   00 波形生成種別(4bitの下位2bit)
    TCCR1A = 0b00000000;

    // 15.11.2 タイマ/カウンタ1制御レジスタB
    //         +------- ICNC1          0
    //         |+------ ICES1          0
    //         || ++--- WGM13:WGM12    01  波形生成種別(4bitの上位2bit) CTC top=OCR1A
    //         || ||+++ CS12:CS11:CS10 101 1024分周
    TCCR1B = 0b00001101;

    // 15.11.8 タイマ/カウンタ1割り込みマスクレジスタ
    //           +----- ICIE1  0
    //           |  +-- OCIE1B 0
    //           |  |+- OCIE1A 1 タイマ/カウンタ1比較A割り込み許可
    //           |  ||+ TOIE1  0
    TIMSK1 = 0b00000010;

    sei(); // 割り込み許可
}

//
int main()
{
    DDRB  = 0x01;  // PB0(14pin) 出力
    PORTB = 0x01;

    timer_init(100); // 100 * 1024us毎に割り込み (約4.88Hz) @ 1MHz

    while(1) ; // 無限ループ
}

割り込み処理は特別なprologとepilogが必要になるので、なんらかの形でコンパイラに割り込みハンドラであることを教えてあげないといけません。指定方法はC言語の標準の範囲ではないので、CPU毎、コンパイラ毎に異なります。AVRのgccはマクロが用意されているので簡単です。

割り込みベクトルの名前は、ヘッダファイルiomx8.hから見つけました。TIMER1_COMPA_vectは_VECTOR(11)を#defineしたものです。

最初思っていたほど難しくなかったというのが感想です。

AVRでLEDダイナミック点灯

2008-09-19 01:09:41 | AVR
AVRでLEDホタル(3)の続きです。

秋月のフルカラーLEDを複数点灯しています。

ATMega88のPWM出力は最大6個なので、全部をPWMにつなげるわけにはいきません(RGBx4 = 12)。ダイナミック点灯で、左をちょっと光らせて、一つ右に移ってを繰り返しています。
このLEDはカソードコモンなのでNPNのトランジスタ(2SC1815)をカソード側につないで、点けるか消すかを制御しています。アノード側はPWMの出力を4つのLEDに分配しています。緑の配線がそれなんですが、痛々しいくらい高密度配線です。

携帯のカメラを一番暗くしてみました。


ソースコードです。
#include <avr/io.h>
#include <util/delay.h>

typedef unsigned char byte;

void pwminit(void)
{
    // MEGA88 タイマー関連ポート
    // OC0A/PD6 12pin 赤
    // OC0B/PD5 11pin 緑
    // OC1A/PB1 15pin
    // OC1B/PB2 16pin
    // OC2A/PB3 17pin ... MOSI
    // OC2B/PD3  5pin 青

    //       76543210
    DDRD |= 0b01101000; // PD6(12), PD5(11), PD3(5) 出力

    // 14.9.1 タイマ/カウンタ0制御レジスタA (p.64)
    //         ++--------COM0A1:COM0A0 10 上昇時一致でL下降時一致でH
    //         ||++------COM0B1:COM0B0 10 上昇時一致でL下降時一致でH
    //         ||||  ++--WGM01:WGM00   01 位相基準PWM動作
    TCCR0A = 0b10100001;

    // 17.11.1 タイマ/カウンタ2制御レジスタA (p.99)
    //         ++--------COM2A1:COM2A0 10 OCR2A停止
    //         ||++------COM2B1:COM2B0 00 上昇時一致でL下降時一致でH
    //         ||||  ++--WGM21:WGM20   01 位相基準PWM動作
    TCCR2A = 0b00100001;

    // 14.9.2 タイマ/カウンタ0制御レジスタB (p.65)
    //         ++--------FOC0A:FOC0B    00
    //         ||  +-----WGM2           0   TOP = 0xff
    //         ||  |+++--CS02:CS01:CS00 001 clkio/1
    TCCR0B = 0b00000001; // start timer

    // 17.11.2 タイマ/カウンタ0制御レジスタB (p.100)
    //         ++--------FOC2A:FOC2B    00
    //         ||  +-----WGM22          0   TOP = 0xff
    //         ||  |+++--CS22:CS21:CS20 001 clkio/1
    TCCR2B = 0b00000001; // start timer
}

int main()
{
    byte led[4][3] = {
        {0x80, 0x00, 0x00}, // PC3のR, G, B
        {0x00, 0x80, 0x00}, // PC2のR, G, B
        {0x00, 0x00, 0x80}, // PC1のR, G, B
        {0x80, 0x80, 0x00}, // PC0のR, G, B
    };
    byte p = 0;

    pwminit();

    //       76543210
    DDRC = 0b00001111; // PC3(26), PC2(25), PC1(24), PC0(23) 出力

    while(1){
        _delay_ms(4); // 4ミリ秒 250Hz
        PORTC = 0;
        OCR0A = led[p][0]; // duty比設定 赤
        OCR0B = led[p][1]; // duty比設定 緑
        OCR2B = led[p][2]; // duty比設定 青
        PORTC = 8 >> p;

        p = (p + 1) & 3; // p = 0~3の繰り返し
    }
}

PWMの初期化は毎回同じなので、次からは省略できるようにサブルーチンにしました。LEDの左から順にPC3, PC2, PC1, PC0につながっています。PC3に1を書くと一番左が点灯します。
ダイナミック点灯は結構高い周波数で切り替えないとちらつきます。今回は4ミリ秒毎に切り替えているので250Hzです。
本来ならダイナミック点灯の切り替えは割り込みを使ってやるぺきですが、割り込みの使い方を分かっていません。

今回わかったこととしては、LED毎に明るさのばらつきが微妙にあることです。同じ色を出しているつもりでも、4つが各々微妙にちがったりします。もうひとつはRGBでも明るさのカーブが違うことです。明るいときはうまくバランスしてても暗めにすると青みがかったりします。完璧を目指すならLED一つ一つについて、PWMのパラメータを変えたりしないといけないでしょうが、とても大変そうです。

とりあえずタイマー1が空いているので、次は割り込みに挑戦してみたいと思っています。


PICの周辺回路をCPLDで作るキット

2008-09-18 00:26:04 | FPGA
PICの周辺回路をCPLDで作るキット」というPICとCPLDを載せたキットが10月に秋月から発売になるそうです。開発元はやはり秋月で販売している「サーボモータ学習キット 」(通販番号K-1984)と同じ開発元のMAKE21さんです。
PICはPIC16F873A、CPLDはXilinxのXC9536VQ44です。コンフィギュレーション用の回路も搭載されています。おもしろいのは、写真中央のCPLD部分がとりはずし可能になっていることです。CPLD部分だけの販売はあるのでしょうか?


MAKE21さんの「JALAXY」もおもしろそうです。振動推進で動くロボットです。振動推進というと映画「ロボコン」を思い出します(東宝のオフィシャルサイトwiki)。ロボコンのことはあまり詳しくありませんが、公式ページを見ていると毎年競技が変わるようです。映画の競技は2002年第15回大会の「プロジェクトBOX」です。映画にも出てきたロボットの名前が入賞しています。また見たくなってきました。

AVRでLEDホタル(3)

2008-09-16 21:20:29 | AVR
AVRでLEDホタル(2)の続きです。

ELMさんというかchanさんのところで、フルカラーLEDを使って遊ぶ記事を見つけました。8ピンAVRの活用という記事の中の「LEDフラッシャー その2」です。赤→黄→緑→水色→青→紫→赤の順に色を変化させていくと「色相が回転」するのだそうです。途中をなめらかに変化させるために中間値をPWMで出力します。

chanさんの元のコードはアセンブラでしたが、Cにしちゃいました。たぶん、そんなに間違ってないと思います。
#include <avr/io.h>
#include <util/delay.h>

typedef unsigned char byte;

byte r, g, b;

void ledfunc(char rd, char gd, char bd)
{
    byte i;

    for(i = 0; i < 0xff; i++){
        _delay_ms(6);

        OCR0A = r; // duty比設定 赤
        OCR0B = g; // duty比設定 緑
        OCR2B = b; // duty比設定 青
        r += rd;
        g += gd;
        b += bd;
    }
}

int main()
{
    // MEGA88 タイマー関連ポート
    // OC0A/PD6 12pin 赤
    // OC0B/PD5 11pin 緑
    // OC1A/PB1 15pin
    // OC1B/PB2 16pin
    // OC2A/PB3 17pin ... MOSI
    // OC2B/PD3  5pin 青

    //       76543210
    DDRD = 0b01101000; // PD6, PD5, PD3出力

    // 14.9.1 タイマ/カウンタ0制御レジスタA (p.64)
    //         ++--------COM0A1:COM0A0 10 上昇時一致でL下降時一致でH
    //         ||++------COM0B1:COM0B0 10 上昇時一致でL下降時一致でH
    //         ||||  ++--WGM01:WGM00   01 位相基準PWM動作
    TCCR0A = 0b10100001;

    // 17.11.1 タイマ/カウンタ2制御レジスタA (p.99)
    //         ++--------COM2A1:COM2A0 10 OCR2A停止
    //         ||++------COM2B1:COM2B0 00 上昇時一致でL下降時一致でH
    //         ||||  ++--WGM21:WGM20   01 位相基準PWM動作
    TCCR2A = 0b00100001;

    // 14.9.2 タイマ/カウンタ0制御レジスタB (p.65)
    //         ++--------FOC0A:FOC0B    00
    //         ||  +-----WGM2           0   TOP = 0xff
    //         ||  |+++--CS02:CS01:CS00 001 clkio/1
    TCCR0B = 0b00000001; // start timer

    // 17.11.2 タイマ/カウンタ0制御レジスタB (p.100)
    //         ++--------FOC2A:FOC2B    00
    //         ||  +-----WGM22          0   TOP = 0xff
    //         ||  |+++--CS22:CS21:CS20 001 clkio/1
    TCCR2B = 0b00000001; // start timer

    r = 0xff;
    g = 0x00;
    b = 0x00;

    while(1){
        ledfunc( 0,  1,  0); // 赤→黄
        ledfunc(-1,  0,  0); // 黄→緑
        ledfunc( 0,  0,  1); // 緑→水色
        ledfunc( 0, -1,  0); // 水色→青
        ledfunc( 1,  0,  0); // 青→紫
        ledfunc( 0,  0, -1); // 紫→赤
    }
}




AVRでLEDホタル(2)

2008-09-14 03:02:55 | AVR
AVRでLEDホタルの続きです。

9/15 追記 動画を追加しました

秋月で売っているRGBフルカラーLED(通販番号I-02476)を光らせてみました。ATMEGA88はPWMを最大6出力できるので、そのうちの3つを使ってRGBを独立に設定できるようにしました。

最初、青でぼわっと点いてぼわっと消えます。次は赤で同じことをして、紫、緑、水色、黄色、白ときて、また青に戻ります。

電源電圧3.2Vでも一応点いていますが、青がちょい暗めです。青と緑に100Ω、赤に510Ωをつけています。配線は次のようにしています。
12pin(OCR0A) → 510Ω → LED(赤アノード)
11pin(OCR0B) → 100Ω → LED(緑アノード)
5pin(OCR2B) → 100Ω → LED(青アノード)
LED(カソード) →GND

一応、撮影してみましたが、実物と雰囲気がかなり違います。秋月のLEDキャップをかぶせています。どうやったら、うまく撮影できるんでしょうね。もっと暗い方がいいのかな。













水色








ソースコード
#include <avr/io.h>
#include <util/delay.h>

typedef unsigned char byte;

void ledfunc(byte g, byte r, byte b)
{
    byte duty = 0;
    char dir = 1;

    do {
        _delay_ms(5);

        OCR0A = duty & r; // duty比設定 赤
        OCR0B = duty & g; // duty比設定 緑
        OCR2B = duty & b; // duty比設定 青

        if(duty == 0xff) dir = -1;
        duty += dir;
    } while(duty != 0);
}

int main()
{
    // MEGA88 タイマー関連ポート
    // OC0A/PD6 12pin 赤
    // OC0B/PD5 11pin 緑
    // OC1A/PB1 15pin
    // OC1B/PB2 16pin
    // OC2A/PB3 17pin ... MOSI
    // OC2B/PD3  5pin 青

    //       76543210
    DDRD = 0b01101000; // PD6, PD5, PD3出力

    // 14.9.1 タイマ/カウンタ0制御レジスタA (p.64)
    //         ++--------COM0A1:COM0A0 10 上昇時一致でL下降時一致でH
    //         ||++------COM0B1:COM0B0 10 上昇時一致でL下降時一致でH
    //         ||||  ++--WGM01:WGM00   01 位相基準PWM動作
    TCCR0A = 0b10100001;

    // 17.11.1 タイマ/カウンタ2制御レジスタA (p.99)
    //         ++--------COM2A1:COM2A0 10 OCR2A停止
    //         ||++------COM2B1:COM2B0 00 上昇時一致でL下降時一致でH
    //         ||||  ++--WGM21:WGM20   01 位相基準PWM動作
    TCCR2A = 0b00100001;

    // 14.9.2 タイマ/カウンタ0制御レジスタB (p.65)
    //         ++--------FOC0A:FOC0B    00
    //         ||  +-----WGM2           0   TOP = 0xff
    //         ||  |+++--CS02:CS01:CS00 001 clkio/1
    TCCR0B = 0b00000001; // start timer

    // 17.11.2 タイマ/カウンタ0制御レジスタB (p.100)
    //         ++--------FOC2A:FOC2B    00
    //         ||  +-----WGM22          0   TOP = 0xff
    //         ||  |+++--CS22:CS21:CS20 001 clkio/1
    TCCR2B = 0b00000001; // start timer

    while(1){
        ledfunc(0x00, 0x00, 0xff);
        ledfunc(0x00, 0xff, 0x00);
        ledfunc(0x00, 0xff, 0xff);
        ledfunc(0xff, 0x00, 0x00);
        ledfunc(0xff, 0x00, 0xff);
        ledfunc(0xff, 0xff, 0x00);
        ledfunc(0xff, 0xff, 0xff);
    }
}

RGBでやっちゃったけど、もっと色々な中間色を出せます(2^24色)。カラーでぼわっとをしようとすると、HSVとかにしないといけないんでしょうね。

AVRでLEDホタル

2008-09-13 00:59:41 | AVR
すんさんの掲示板でAVRのPWMの話で盛り上がっていたので興味をもちました。いまいち理解が足りないですが、とりあえずコードを書いてみました。

回路は12pin → LED(A) → LED(K) → 100Ω抵抗 → GNDです。

AVRのPWMを使って、LEDホタルです。ほわっと明るくなって、ぼわっと暗くなってを繰り返します。
#include <avr/io.h>
#include <util/delay.h>

int main()
{
    unsigned char duty = 0;
    char dir;

    // MEGA88 タイマー関連ポート
    // OC0A/PD6 12pin
    // OC0B/PD5 11pin
    // OC1A/PB1 15pin
    // OC1B/PB2 16pin
    // OC2A/PB3 17pin ... MOSI
    // OC2B/PD3  5pin
    DDRD = 0x40; // PD6出力

    // 14.9.4 タイマ/カウンタ0 比較Aレジスタ (p.66)
    OCR0A = duty;

    // 14.9.1 タイマ/カウンタ0制御レジスタA (p.64)
    //         ++--------COM0A1:COM0A0 10 上昇時一致でL下降時一致でH
    //         ||++------COM0B1:COM0B0 00 OC0B切断
    //         ||||  ++--WGM1:WGM0     01 位相基準PWM動作
    TCCR0A = 0b10000001;

    // 14.9.2 タイマ/カウンタ0制御レジスタB (p.65)
    //         ++--------FOC0A:FOC0B    00
    //         ||  +-----WGM2           0   TOP = 0xff
    //         ||  |+++--CS02:CS01:CS00 001 clkio/1
    TCCR0B = 0b00000001; // start timer

    while(1){
        _delay_ms(4); // 4ミリ秒毎にduty比を変更 512*4で周期は2秒
        if(duty == 0x00) dir = 1;
        if(duty == 0xff) dir = -1;
        duty += dir;
        OCR0A = duty;
    }
}

AVRGCCではutil/delay.hをincludeすることで_delay_msと_delay_usという関数が使えるようになります。動作クロックはF_CPUをマクロ定義します。自分で#defineすることもできますが、AVR StudioだとProject→Configuration Optionsのfrequencyに入力してやることで指定することもできます。このとき、gccのオプションで-DF_CPU=1000000のように定数が定義されます(この場合は1MHz)。このdelayシリーズは周波数の計算とかしなくていいのでとても便利です。

PWM出力をするには、4つのレジスタを設定する必要があります。
(1) 対応するPORTを出力にする(DDRBとかDDRD)
(2) 比較レジスタの設定(OCR0A)
(3) 制御レジスタA (TCCR0A)
(4) 制御レジスタB (TCCR0B)
割り込みを使うときは、さらに色々な設定が必要です。

AVRではクロック元を、動作クロックを分周したものにできます。CS02, CS01, CS00で、停止、1/1、1/8, 1/64, 1/256, 1/1024の指定ができます。今回は1MHz動作で1/1でそのまま使っています。

今のところ分かったのはこのくらいです。あまり理解しないうちから、とりあえずコードを書いてしまいます(笑)。

アナログ電子回路のキホンのキホン

2008-09-12 22:44:38 | 電子工作
本屋さんで「回路シミュレータでスッキリわかる! アナログ電子回路のキホンのキホン」という本を見かけました。LTSpiceを使っています。シミュレータの使い方よりは、アナログ回路の説明の方が主の本です。本に載っている回路をダウンロードして実際に試すことができます。


図解&シム 電子回路の基礎のキソ 回路シミュレータで初めてでも簡単!」もLTSpiceを使った本でした。

1ヶ月遅れくらいで気づいたこと

2008-09-12 08:25:14 | その他
なぜか1ヶ月遅れくらいで気づいたことがいくつかありました。

エレキジャックにFPGA/CPLDのカテゴリーが増えていること(記事一覧へのリンク)
一番下にあったので気づいていませんでした。

STAPA VISION #005 電子工作キットに挑戦!!
みのり先生のリベンジです。

プロービングで失敗しないためのオシロスコープ応用講座という連載がはじまっていました。

一歩進んだ電子工作をやってみよう
も更新されています。

武蔵野電波のブレッドボーダーズも着々と更新を重ねています。

たしか、こんな感じです。もっとあったような気もします。