Charlieplexingという方法を知ったので試してみた。
詳しい解説はWikipediaにあるので、それを参照してもらうことにして、
LEDを点灯するにはアノードをHIGH,カソードをLOWにすればよく、逆では点灯しないという単純なことが原理です。
マイコンの2本のピン1,2それぞれにLED1,2を並列に逆向きで接続したとします。(図はwikipediaから拝借)
PIN1,2をOUTPUTにしたとき、それぞれの状態によって
PIN2 | PIN1 | LED1 | LED2 |
---|---|---|---|
LOW | LOW | OFF | OFF |
LOW | HIGH | ON | OFF |
HIGH | LOW | OFF | ON |
HIGH | HIGH | OFF | OFF |
となることがわかります。
3本以上使う場合も一度に点灯するLEDは1つとして、使わない他のピンは接続しないというのがミソです。
これはAVRではDDRxを0(入力)にして、PORTxを1にするとHigh-Zで実現できます。
信号が3本の場合は3本のうち2本を選び、向きが正逆の2通りなので6個のLEDが点灯でき、
更にN本に一般化すれば、N個から2個取る組み合わせの2倍でN*(N-1)本のLEDを点灯できることがわかります。
ATtiny13では通常5本のピンが使えるので20個のLEDをドライブできることになりますが、
配線が面倒なのと原理さえわかればいいので、トリビアルでない最小のN=3の場合をやってみます。
LED1を点灯するにはPin1=H, Pin2=L, Pin3=High-Zとすればよく、
PIN1,2,3をそれぞれPB0,PB1,PB2に接続した場合は
DDRB=0b00000011;
PORTB=0b00000101;
とすればよいわけです。そこでナイトライダー的な点灯コードを書いてみました。
/* charlieplexing LED controling 6LEDs with 3 pins ATtiny13A */ #include <avr/io.h> #include <util/delay.h> int pat[10] = {0,1,2,3,4,5,4,3,2,1}; uint8_t ddrb[6] = { 0b00000011, 0b00000011, 0b00000110, 0b00000110, 0b00000101, 0b00000101, }; uint8_t portb[6] = { 0b00000101, 0b00000110, 0b00000011, 0b00000101, 0b00000110, 0b00000011, }; int main(void) { int i; while(1){ for (i=0; i<10; i++) { DDRB = ddrb[pat[i]]; PORTB = portb[pat[i]]; _delay_ms(50); } } return 0; }
コメントを残す