フォト
無料ブログはココログ

MyList

« 採用基準 | トップページ | USB DAC (2) »

2013年1月11日 (金)

CharlieplexingでBinary Clock

 Charlieplexingの話(2012/12/28)でマイコンの3つのポートで12個のLEDを駆動する方法について書いたので、Chipiplexing 方式を使ったバイナリクロックを作ってみた。
バイナリクロックは時刻を2進数で表示する時計で、例えば10:39分は

   
 
 

のように表示する。

 LEDで表示しようとすると12個のLEDが必要である。これをATTiny45でCharlieplexで3つのI/Oを使って実現しようというもの。

 回路図はこんな感じ
Binclock

 最初にAVRでI/Oポートを3つ持つ品種AT90S2323を使おうと考えたが、AT90Sシリーズのデータシートを見るとソース(電流吐出し)とシンク(電流吸込み)のドライブ能力が対象でない。と
いうことでATTiny45を使うことにした。

 ATTiny45はRESET#、XTAL1,XTAL2をI/Oポートとして使用できるのだが、
RESET#はドライブ能力がかなり低いのでピークで10数mAの出力が必要な今回のような用途には使えないし、外部X'talを使うのでXTAL1、XTAL2も使えないということでI/O
ポートは3つである

(水晶発振器出力を#2PIN (CLKI)に入れて#3PIN(XTAL2)をI/Oに使えば、い~じゃん。というツッコミは無しである!)

 R1、R2、R3にマイコンの出力ポートの内部抵抗が使えないかと思い、ATTiny45の内部抵抗をデータシートで確認すると30数Ωくらい
だったので、R4=R6=510Ω、R5=5.6kΩで作ったら、P0=H、P1=LにしたときD1、D8、D9が点灯してしまう。

 SPICEで確認してみたら
Binclk_spice

SPICEさんはD1点灯(緑)のときD3(青)には200uA流れるとおっしゃる。200uAでは明々とは点灯しないような気がするのだけれど...

 D1、D8、D9に関係する部分だけ抜き出してVcc=3.3V、D1,D8,D9のVf=2V、Q1,Q2のVbe=0.7として計算した各ポイントの電圧は↓のとおりである。
Binclock_d1d8d9

 D1のアノード電圧=2.65V、Q2のエミッタ電圧=0.95Vだから、D9のA-K間の電圧=1.7Vである。これはD9のVfより小さいのでD9は点灯しないはずだ。(D8も同様)

 2日くらい考えたところ、
昔のLEDは10m以上流さないと点灯しなかったが、最近のLEDは高輝度と謳っていなくても1mAも流すと点灯する。物によっては0.1mAでも点灯する。

 !よく考えたら、Vf=2VはおおよそIf=20mAの場合のVfである。(D1のA-K間は2V)
ところがD8,D9に少ない電流が流れているとすると当然Vfも小さい値になる。
普通の赤色LEDで電流が流れ始める電圧は1.7V付近だから点灯するくらいの電流が流れているのではないか。

 D8、D9が完全にOFFになるようにQ1のエミッタ電圧を下げ、Q2のエミッタ電圧を上げることにした。

 アルカリ電池×2を使った場合を考えてVcc=3.4V、D8、D9が完全にOFFになる電圧を1.5Vとして計算すると、R4=R5=1.2kにしたときに1.49VになるのでD8,D9は完全に消えるだろう。

 出力ポートの内部抵抗をあてにすると、I/Oピン入出力電流の絶対最大規格40mAに引っ掛かる恐れがあるのだけれど、R1、R2を大きくするとD8、D9を単独で点灯したときの電流が減るので痛し痒しだ。

 D1~D8を点灯した時とD9~D12を点灯したときの電流の差があるのでLEDによって明暗の差が出てしまう。明らかに分かるようならPWMで補正しよう。

 LED表示のソースはこんな感じ

/* bit ON/OFF */
#define ON 1
#define OFF 0

/*
* DDRB PORTD
* xxxx xxxxx : 出力データ
*/
#define DDR(d) ((d)<<4)
#define PD(d) ((d)&0x0F)

/* ポートの状態 */
#define HI PD(ON)|DDR(ON)
#define LOW PD(ON)|DDR(OFF)
#define HIZ PD(OFF)|DDR(OFF)

/* PB0,PB1,PB2の状態
*  xxxx xxxx
*   ||| |||+--- PORTB(0)
*   ||| ||+---- PORTB(1)
*   ||| |+----- PORTB(2)
*   ||+-------- DDRB(0)
*   |+--------- DDRB(1)
*   +---------- DDRB(2)
*/
#define P0H HI
#define P0L LOW
#define P0Z HIZ
#define P1H (HI<<1)
#define P1L (LOW<<1)
#define P1Z (HIZ<<1)
#define P2H (HI<<2)
#define P2L (LOW<<2)
#define P2Z (HIZ<<2)

/**/
#define MIN1_1 P2Z | P1Z | P0L
#define MIN1_2 P2Z | P1Z | P0H
#define MIN1_4 P2Z | P1H | P0L
#define MIN1_8 P2Z | P1L | P0H
#define MIN10_1 P2Z | P1L | P0Z
#define MIN10_2 P2Z | P1H | P0Z
#define MIN10_4 P2H | P1L | P0Z
#define HOUR1_1 P2L | P1Z | P0Z
#define HOUR1_2 P2H | P1Z | P0Z
#define HOUR1_4 P2L | P1Z | P0H
#define HOUR1_8 P2H | P1Z | P0L
#define HOUR10_1 P2L | P1H | P0Z
#define ALL_OFF   0x00

 

#define LED_OFF() PORTB = DDRB = 0x00
#define LED_ON(d) do { register uint8_t pd, dd; \
dd = pd = (d); \
dd &= 0x0F; \
pd >>= 4; \
} while(0)

 

/* output data */
const uint8_t port_data[] =
{
ALL_OFF,
    MIN1_1,  MIN1_2,  MIN1_4,  MIN1_8,
MIN10_1, MIN10_2, MIN10_4,
HOUR1_1, HOUR1_2, HOUR1_4, HOUR1_8,
HOUR10_1
};

 

/* display LED
* 指定したLEDを時刻に応じてON/OFFする
* void disp(uint8_t pos)
*  arg : uint8_t pos : LED number
*        uint8_t data : 0: off, 1: on
*  ret : void
*  global: uint8_t min, hour : 時分BCD
*/
void disp(uint8_t pos, uint8_t data)
uint8_t  p;

 

/* all off */
LED_OFF();
if (pos < 4) { /* 分 */
if (BCD_L(min) & _BV(pos))
p = port_data[pos+1];
} else
if (pos < 7) { /* 10分 */
if (BCD_H(min) & _BV(pos-4))
p = port_data[pos+1];
} else
if (pos < 11) { /* 時 */
if (BCD_L(hour) & _BV(pos-7))
p = port_data[pos+1];
} else
if (pos < 12) { /* 10時 */
if (BCD_H(hour) & _BV(pos-11))
p = port_data[pos+1];
}
LED_ON(p);
}

 

ポート(PB(x))をHにするときはDDR(x)←1、PORTB(x)←1
ポート(PB(x))をLにするときはDDR(x)←1、PORTB(x)←0
ポート(PB(x))をHizにするときはDDR(x)←0、PORTB(x)←0
このデータをLED0-LED11毎にテーブルで用意しておいて、表示するLED番号で出力データを検索して、上位4bitをDDRBに、下位4bitをPORTBに出力する。

 そうしているうちに完成
Binaryclock Binalyclock2
↑11:54を表示
後ろは学研のArduino、もっぱらISPに使っている。

動いているところ

Binaryclock20267 ←リンク先にAVI

 リセット時には、全てのLEDが右下から順に点灯し、11:40からカウントが始まる。
時分しか表示できないので撮影用に1秒毎にカウントアップするようにしている。

 まあ動いたから良しとしよう。
 I/Oポートがもう一個あって4個あるなら普通にCharlieplexingで駆動するのが簡単だと思う。

 本当に時計として使うならC3をトリマに変えて発振周波数を合わせる必要がある。

« 採用基準 | トップページ | USB DAC (2) »

日記・コラム・つぶやき」カテゴリの記事

AVR」カテゴリの記事

コメント

コメントを書く

コメントは記事投稿者が公開するまで表示されません。

(ウェブ上には掲載しません)

トラックバック


この記事へのトラックバック一覧です: CharlieplexingでBinary Clock:

« 採用基準 | トップページ | USB DAC (2) »