AVR 7セグメントLEDを使ってみる

7セグメントLEDは視認性もよく、LCDのクールな表示とは違った趣きがあります。
デバイスもそこそこ安く簡易なモニタとしていろいろ利用価値があると思います。

7seg01
7セグメントLEDにはアノードコモン、カソードコモンがありまたドライブトランジスタの有無など条件の違いもあります。配線もほかのデバイスに比べやや多くなってしまいます。
たまに使おうとすると暖気運転に時間がかかってしまいます。
ユニバーサル基板に組んだ時などはハード側の間違いか、プログラム上の問題かの切り分けも悩むときがあり、慣れないと少し使いにくいデバイスとも思います。

ほかの用途にも使えるように7SEGテストボードを組んでみました。
また使いまわしができるように7SEGプログラムの雛形も書いてみたいと思います。

7SEGテストボード
7seg03
使用する7SEGは秋月の
OSL40562-IR アノードコモン
OSL40562-LR カソードコモン

7seg04
MCUはATMega88/168をベースに考えています。
特に88Vは現在@150と2313と比べると同じ価格になっており使い勝手はかなり良くなります。
7SEGはピンソケットに直接差し込みます。若干緩めですがテスト用なのでヨシとします。

7seg02
アノード(カソード)共通接続になっているので配線は楽になります。
AE-ATMega基板からArduino用ユニバーサル基板に差し込んで利用します。
ATMega基板からは電源、USPaspからのISP接続を利用しています。

7seg00
回路図
1セグメントあたりの電流を計って見ました。
VCC   3.3V  5V
330Ω  4mA  9mA
470Ω  3mA  7mA
AVRの出力ピンは割と強力で1セグメントあたり20mAまでは大丈夫と言われています。(但し桁数が増えた場合などでは電源ピンで制限がかかると思います)
3mAでも問題なく使用できますので今回のボードでは470Ωを選択しています。

7seg01
テストはしていませんが高輝度タイプならば8桁でもいけると思います。
基本はドライブトランジスタ有りで、電流を制限していれば省略も可と考えれば良さそうです。

ドライブトランジスタ回路図
上 アノードコモン
下 カソードコモン

7seg05
ドライブトランジスタアダプタを作ってみました。
光量は電流制限抵抗で決まってしまうのでなんら変わりませんがトランジスタを設けることによって出力が反転しますのでプログラムのポート設定を変更する必要があります。

アノード汎用テスト

/*
*    Anode
*    ATmega88V RC 8MHz
*    avrdude -p m88 -u -U lfuse:w:0xe2:m
*/

#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include u<til/delay.h>

const   uint8_t     SEG[] = {
//  0bABCDEFGP
    0b00000011,     // 0     0
    0b10011111,     // 1     1
    0b00100101,     // 2     2
    0b00001101,     // 3     3
    0b10011001,     // 4     4
    0b01001001,     // 5     5
    0b01000001,     // 6     6
    0b00011111,     // 7     7
    0b00000001,     // 8     8
    0b00001001,     // 9     9
    0b11111101,     // -    10
    0b11111110,     // dot  11
    0b00010001,     // A    12
    0b00000101,     // a    13
    0b11000001,     // b    14
    0b11100101,     // c    15
    0b01100011,     // C    16
    0b10000101,     // d    17
    0b01100001,     // E    18
    0b01110001,     // F    19
    0b01000011,     // G    20
    0b11010001,     // h    21
    0b10010001,     // H    22
    0b11011111,     // i    23
    0b10000111,     // J    24
    0b11100011,     // L    25
    0b11010101,     // n    26
    0b11000101,     // o    27
    0b00110001,     // P    28
    0b00011001,     // q    29
    0b11110101,     // r    30
    0b11000111,     // u    31
    0b10000011,     // U    32
    0b10001001,     // y    33
    0b00000000,     // all  34
    0b11111111      // null 35
};

uint8_t digit,led_dig[8];
uint8_t c0,c1,c2,c3,c4,c5,c6,c7;
uint8_t dp,m;
uint16_t a;  // 65535 < uint32_t

// --------------------(7SEG)-------------------------
void scan(void) {       // 7SEG-scan

    PORTD = led_dig[digit];
    DDRB = 1 << digit;
    digit = (digit + 1) % 4;

        // 桁取得
        c0 = (a % 10); a /= 10;
        c1 = (a % 10); a /= 10;
        c2 = (a % 10); a /= 10;
        c3 = (a % 10); a /= 10;

        // 表示(右詰め)
        led_dig[0] = SEG[c0];    
        led_dig[1] = SEG[c1];
        led_dig[2] = SEG[c2];   
        led_dig[3] = SEG[c3];
        // DOT
        if (dp==1) led_dig[3] &= SEG[11];  // and(anode)
}

// --------------------(Timer0)-------------------------
ISR(TIMER0_OVF_vect) {  // Timer0 オーバーフロー割り込み
    TCNT0  = 131;

    scan();

    a = 1234;
    dp = 0; 
    m = 0;
}

// --------------------(Timer1)-------------------------
ISR(TIMER1_OVF_vect) {   // Timer1 オーバーフロー割り込み
    TCNT1 = 53036;

}

// ---------------------(main)------------------------
int main(void) {

    DDRB    = 0xFF;             // PORTB
    DDRC    = 0x00;             // PORTC
    DDRD    = 0xFF;             // PORTD
    PORTB   = 0xFF;             // PORTB DriveTR = 0x00
    PORTC   = 0xFF;             // PORTC
    PORTD   = 0xFF;             // PORTD
    TCCR0B  = 0x03;             // Prescaler 1/64
    TCNT0   = 131;              // (1/8)x64x(256-131)=1ms
    TCCR1B  = 0x03;             // Prescaler 1/64
    TCNT1   = 53036;            // (1/8)x64x(65536-53036)=100ms
    TIMSK0  |= _BV(TOIE0);      // Timer0
    TIMSK1  |= _BV(TOIE1);      // Timer1
    sei();                      // 割り込み許可

    set_sleep_mode(SLEEP_MODE_IDLE);

    while (1) {

        sleep_mode();
    }
}

コンパイル、書込をします。

$ avr-gcc -mmcu=atmega88 -Wall -Os anode.c
$ avr-objcopy -O ihex -R .eeprom a.out anode.hex
$ avrdude -c usbasp -p m88 -U flash:w:anode.hex

7seg06
上記のソース
変数 a に 1234 を代入しています。

アノード anode.txt
カソード cathode.txt

7seg07
変数 a に 123 を代入

7seg08
変数 a に 12345 を代入

7seg09
4桁目に P 3桁目に DOT を表示

led_dig[3] = SEG[m];

a = 123;
dp = 1;
m = 28;

以上から桁数の変更や記号の挿入はすぐわかると思います。
今回は7SEGの表示テストということでtimer0の項に値を直打ちをしていますがプログラム上から期待する数値などを変数に代入します。
timer1は100msに設定しています。スイッチの入力や時間稼ぎなどに使えると思います。
空きピンの設定は適宜変更します。
参考 AVRWIKI I/Oレジスタ、入出力ポートの使い方
組み上げた7SEGハードのチェックや簡単なセンサからの入力をカウントする用途には応用できると思います。
これで少しだけスタートダッシュが効きます。ゴールは・・・・わかりません。