パソコン・スマホ備忘録

パソコン、スマホ、マイコン、家電などの備忘録と日記。使えるところを簡潔に解説!

Arduino

Arduinoで7セグメントLED4桁を表示(ATmega328)

2019/07/25

Arduino(ATmega328)で7セグメントLED4桁を表示させてみました。数字がカウントされる様子はまるで時限爆弾のようです。どの色の線を切れば・・・という感じでしょうか。

プログラム通りにLEDが点灯するのは見ていて気持ちが良いです。これができれば後はプログラム次第で何でもできる感じがします。

使用したのはダイナミック接続4桁高輝度赤色7セグメントLED表示器 カソードコモン(カソード共通接続)です。

一桁を高速に切り替えて4桁分を表示するダイナミック点灯を使います。

Arduino Unoに接続するピンはアノード側に抵抗を8本(今回は120Ω)付け、カソードは直結です。後でATmega328を単体で動かすためのピン番号も併記しておきます。

Arduino ATmega328 接続 7seg Segment
2 4 120Ω 1 E
3 5 120Ω 2 D
4 6 120Ω 3 DP
5 11 120Ω 4 C
6 12 120Ω 5 G
7 13 直結 6 DIG4
8 14 120Ω 7 B
9 15 直結 8 DIG3
10 16 直結 9 DIG2
11 17 120Ω 10 F
12 18 120Ω 11 A
13 19 直結 12 DIG1

スケッチです。「0000」~「9999」を1づつカウントして繰り返します。

const int anode_pins[] = {12, 8, 5, 3, 2, 11, 6, 4}; // A B C D E F G DP
const int cathode_pins[] = {7, 9, 10, 13};  // DIG4 DIG3 DIG2 DIG1
const int number_of_anode_pins = sizeof(anode_pins) / sizeof(anode_pins[0]);
const int number_of_cathode_pins = sizeof(cathode_pins) / sizeof(cathode_pins[0]);
int numbers_to_display = 0; // LEDに表示する数字を保持する変数
 
const int digits[] = {
  0b00111111, // 0
  0b00000110, // 1
  0b01011011, // 2
  0b01001111, // 3
  0b01100110, // 4
  0b01101101, // 5
  0b01111101, // 6
  0b00100111, // 7
  0b01111111, // 8
  0b01101111, // 9
};
 
// 1桁の数字(n)を表示する
void display_number (int n) {
  for (int i = 0; i < number_of_anode_pins; i++) {
    digitalWrite(anode_pins[i], digits[n] & (1 << i) ? HIGH : LOW);
  }
}
 
// アノードをすべてLOWにする
void clear_segments() {
  for (int j = 0; j < number_of_anode_pins; j++) {
    digitalWrite(anode_pins[j], LOW);
  }
}
 
void display_numbers () {
  int n = numbers_to_display;  // number_to_displayの値を保持し変数にコピー
  for (int i = 0; i < number_of_cathode_pins; i++) {
    digitalWrite(cathode_pins[i], LOW);
    display_number(n % 10); // 最後の一桁を表示する
    delayMicroseconds(100);
    clear_segments();
    digitalWrite(cathode_pins[i], HIGH);
    n = n / 10; // 10で割る
  }
}
 
void set_numbers(int n) {
  numbers_to_display = n;
}
 
// 初期設定
void setup() {
  for (int i = 0; i < number_of_anode_pins; i++) {
    pinMode(anode_pins[i], OUTPUT);  // anode_pinsを出力モードに
  }
  for (int i = 0; i < number_of_cathode_pins; i++) {
    pinMode(cathode_pins[i], OUTPUT);  // cathode_pinを出力モードに
    digitalWrite(cathode_pins[i], HIGH);
  }
   
  // f = クロック周波数 / ( 2 * 分周比 * ( 1 + 比較レジスタの値))
  // 分周比=32, 比較レジスタの1値=255 -> f = 16000000 / (2 * 32 * 256) = 976 Hz
  OCR2A = 255; // 255クロックごとに割り込みをかける
  TCCR2B = 0b100; // 分周比を32に設定する
  bitWrite(TIMSK2, OCIE2A, 1); // TIMER2を許可する
}
 
void loop () {
  for (int i = 0; i < 10000; i++) {
    set_numbers(i);
    delay(1000);
  }
}
 
ISR(TIMER2_COMPA_vect) {
  display_numbers();
}

今回はトランジスタを使わなくてもOKみたいです。もう少し電流が必要な場合はトランジスタやLEDドライバで電源を補う必要がありそうです。

この回路やスケッチで問題なさそうなので、近いうちにATmega328内部クロック単独で動かしたいと思います。その際ATmega328を7セグメントLEDの下に配置し小型軽量化を試みたいと思います。

-Arduino