2014年7月7日月曜日

Arduinoで4桁7セグメントLED

Arduinoで4桁7セグメントLED表示器をなんやかんやするやつの続きです。前回、I2Cで1バイト以上の数字を送るのどうするか的な案件が解決しました。以下、用意するものや配線は前回同様です。

用意するもの

・Arduino UNO 2個
・抵抗(4.7kΩ) 2個 I2C用
・抵抗 (330Ω) 8個
・抵抗(10kΩ) 12個
トランジスター2SC1815Y 12個
ダイナミック接続4桁高輝度青色7セグメントLED表示器 アノードコモン 1個

配線

Arduino側は全てデジタルピンの番号で、OSL40562-IBはLED表示器の型番です。

 Arduino Pin  OSL40562-IB 
1 12 (digit1)
29 (digit2)
38 (digit3)
46 (digit4)
511 (A)
67 (B)
74 (C)
82 (D)
91 (E)
1010 (F)
115 (G)
123 (DP)



スケッチ

I2C通信では1バイトごとしか送れないので、255がひとつのセットの限界です。
今回は4桁なので0~9999の数を送ることを考えます。

255以下ならば1回で済むのですがそれ以上の数を255ごと区切って送るのはとても効率が悪いので、上位ビットと下位ビットに分けてスレーブ側で元に戻すというやり方でいきます。

具体的にはまず、0~9999なので2バイトの符号なし整数(unsigned short int)の型を用意してそれぞれに元の数の上位ビットと下位ビットを入れます。
(2バイト符号なしなので、表示できないけど一応0~65535まで送れます。)
1
2
3
unsigned short int upper = num >> 8;
unsigned short int lower = num << 8;
lower = lower / 256;
これでupperとlowerに1バイト以下の数を入れることができました。
1
num = upper * 256 + lower;
後はこれを送信先で上位ビットの方を元に戻して足すだけなので、2つのデータを送るだけで済みます。

また、MsTimer2についてはリファレンスを→MsTimer2(ミリ秒単位で指定するタイマ)
ダウンロードはこちらからさせてもらいます。

以下はスケッチの例です。

「マスタ側」↓
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <Wire.h>
 
void setup()
{
    Wire.begin(); // マスターに設定
}
 
void loop()
{
    for(int i=0; i<10000; i++)
    {
        write_numbers(i);
        delay(500);
    }
}
 
void write_numbers(int numbers)
{
    unsigned short int upper = (unsigned short int)numbers >> 8;
    unsigned short int lower = (unsigned short int)numbers << 8;
    lower = lower / 256;
 
    Wire.beginTransmission(8);
    Wire.write(upper);
    Wire.write(lower);
    Wire.endTransmission();
}

「スレーブ側」↓
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <Wire.h>
#include <MsTimer2.h>
const int anode_pin[] = {1,2,3,4}; // digit number
const int cathode_pin[] = {5,6,7,8,9,10,11}; // A,B,C,D,E,F,G
#define DP 12
int numbers_to_display = 0; //LEDに表示する数字を保持
 
const int number[] =
{
    // GFEDCBA
    0b00111111, // 0
    0b00000110, // 1
    0b01011011, // 2
    0b01001111, // 3
    0b01100110, // 4
    0b01101101, // 5
    0b01111101, // 6
    0b00100111, // 7
    0b01111111, // 8
    0b01101111, // 9
    0b00000000  // clear segment
};
 
const int digit[] =
{
    0b1000, // 1
    0b0100, // 2
    0b0010, // 3
    0b0001, // 4
};
 
void setup()
{
    Wire.begin(8); // スレーブのアドレスを8に設定
    Wire.onReceive(set_numbers);
 
    for(int i=1; i<13; i++)
    {
        pinMode(i, OUTPUT);
    }
    MsTimer2::set(5,display_numbers);
    MsTimer2::start();
}
 
void loop()
{
    delay(100);
}
 
// anodeのピンをひとつだけHIGHにする
void digit_number (int n)
{
    for(int i=0; i<4; i++)
    {
        digitalWrite(anode_pin[i], digit[n] & (1 << i) ? HIGH:LOW);
    }
}
 
// 0~9の数字を表示する
void display_number (int n)
{
    for(int i=0; i<7; i++)
    {
        digitalWrite(cathode_pin[i], number[n] & (1 << i) ? HIGH:LOW);
    }
}
 
// numbers_to_display へ数字を入れる
// Wire.onReceive()で呼ばれる
void set_numbers(int byteNum) // 引数を与えないとエラー?
{
    unsigned short int bits[2];
 
    int i = 0;
    while(Wire.available())
    {
        bits[i] = Wire.read();
        i++;
    }
    numbers_to_display = (bits[0] * 256) + bits[1];
}
 
// numbers_to_display の数字を表示する
void display_numbers ()
{
    int num = numbers_to_display;
    for(int i=0; i<4; i++)
    {
        digit_number(i); //表示する桁数を選択
        display_number(num % 10); //numの1の位の数
        num = num/10; //次の桁へ(切り捨て)
        display_number(10); // clear segment 4桁目を消すため
        delay(1);
    }
}

結果


LED表示器の周りをまとめて、スレーブ側のスケッチを書き込んだATMEGA328Pをのせました。




上に映ってるのがマスタのArduinoです。
ちゃんと0~9999までの数字を送ることができました。




参考サイト
4桁7セグメントLEDで始めるArduino

0 件のコメント:

コメントを投稿