PR

ArduinoのDOでLED8×8マトリックスを操作する

組み込みエンジニア
本記事はプロモーションが含まれています。

こんにちは、ENGかぴです。

LED8×8マトリックスはLED8個を行と列にそれぞれ配置してアノードとカソードを共通に接続したモジュールです。ArduinoのDOを16本使用するとLED8×8マトリックスを操作することができます。任意の点灯パターンで動作させる例をまとめました。

LED8×8マトリックスはスターターキットに付属していたOSL641501-BXを使用しています。Arduinoのライブラリを使用して動作確認したことをまとめています。

Arduinoで学べるマイコンのソフト開発と標準ライブラリの使い方

以下ではLED8×8マトリックスをLEDマトリックス、Arduino UNOをArduinoと表記します。

LEDマトリックスを操作する

引用:1..5 Inch Siixty-Four (8x8) Dot Matriix OSL641501-XX VER A.1.2
引用:1..5 Inch Siixty-Four (8×8) Dot Matriix OSL641501-XX VER A.1.2

LEDはアノードからカソードに向けて電流を流すと点灯します。LEDマトリックスは行の8個のLEDのアノードを共通接続し、列の8個のLEDのカソードを共通接続したモジュールです。LEDの向きが引用と逆の場合はHIGHとLOWを逆に読み替えてください。

LEDを点灯は行(ROW)をHIGH、列(COL)をLOWにします。例えばROW1のCOL3のLEDを点灯させる場合はROW1(PIN NO.9)をHIGH、COL3(PIN NO.4)をLOWにします。行と列の両方がHIGHまたは両方ともLOWの場合、LEDには電流が流れないためLEDは点灯しません。

LEDマトリックスでLEDを点灯させる場合、電流を制限するために抵抗を実装する必要があります。抵抗がない場合は過負荷となりDOの出力電流が大きくなることで発熱して故障の原因になります。

LEDマトリックスは行列の対する制御となるため複雑な記号の表示などはできません。例えばLEDマトリックス上に×を表示することはできません。

下記リンクにArduinoでの制御方法の説明があります。

Control an 8×8 matrix of LEDs. | Arduino Documentation

以下ではLEDマトリクスの点灯パターンを作る方法を説明しています。

広告

LEDマトリックスとArduinoの配線

Arduino UNOとLEDマトリックスの配線
Arduino UNOとLEDマトリックスの配線

ArduinoとLEDマトリックスの配線例を示しています。配線が少し煩雑になっているように見えますが、LEDのアノード側に1kΩの抵抗を実装しています。以下の表に従って配線しています。

LEDマトリックスのPIN番号Arduinoのピン番号
9(ROW1)2
14(ROW2)3
8(ROW3)4
12(ROW4)5
1(ROW5)6
7(ROW6)7
2(ROW7)8
5(ROW8)9
13(COL1)10
3(COL2)11
4(COL3)12
10(COL4)13
6(COL5)16(A2)
11(COL6)17(A3)
15(COL7)18(A4)
16(COL8)19(A5)
LEDマトリクスとArduinoのピンの対応表

ROW1からROW8までをArduinoの2ピンから順に配線しています。0ピンと1ピンはシリアルピンなので接続していません。COL1~COL8までは10~13、A2~A5の順で配線しています。

スポンサーリンク

DOでLEDマトリックスを初期化する

const uint8_t col[8]={10, 11, 12, 13, A2, A3, A4, A5}; //列
const uint8_t row[8]={2, 3, 4, 5, 6, 7, 8, 9}; //行

void setup() {

  for(uint8_t i=0;i < 8; i++){ //行の初期設定
    pinMode(row[i],OUTPUT);
    digitalWrite(row[i], LOW);
  } 

  for(uint8_t i=0;i < 8; i++){ //列の初期設定
    pinMode(col[i],OUTPUT);
    digitalWrite(col[i], LOW);
  }
}

row[]配列に行(ROW)で使用するDOのピン番号を定数で宣言しています。col[]配列は列(COL)で使用するDOのピン番号を定数で宣言しています。

pinMode()関数で行で使用するDIOピンの設定を行います。第1引数はピン番号、第2引数はDIOの種別を指定します。DIとして使用する場合はINPUTやINPUT_PULLUPを指定します。DOとして使用する場合はOUTPUTを指定します。

digitalWrite()関数でDOの出力の設定を行います。第1引数はピン番号、第2引数はDOの出力レベルをHIGHやLOWで指定します。

8ピン分まとめて設定を行うためfor分で繰り返してROW1~ROW8で使用するDOピンの設定を行っています。DOピンの初期値をHIGHにすると電流が流れないためLEDが点灯しません。

列についても同様にpinMode()関数とdigitalWrite()関数でDOピンの設定を行います。DOピンの初期値をLOWにすると電流が流れないためLEDが点灯しません。

PR:受講者20万人超!スマホで学べる人気のオンライン資格講座【STUDYing(スタディング)】

LEDマトリックスの点灯パターンを作る

void Led8Set(uint8_t r, uint8_t c){

  digitalWrite(row[r],HIGH); //行をセット
  digitalWrite(col[c],LOW); //列をセット
}

Let8Set()関数は引数で指定した行と列に対応するLEDを点灯する自作の関数です。第1引数に行番号を0~7で指定します。第2引数に列番号を0~7で指定します。1行目の列目のLEDを点灯する場合は第1引数に0、第2引数に2を指定します。

void Led8Clr(void){

  for(uint8_t i=0; i < 8; i++){
    digitalWrite(row[i],LOW); //行
    digitalWrite(col[i],HIGH); //列
  }
}

Led8Clr()関数は行をLOW、列をHIGHにしてすべてのLEDを消灯する自作の関数です。LEDの点灯パターンを変更する前のDOが残らないようにするためLEDを初期化します。

if(timLed8 == TIME_UP){
  timLed8 = LED8_WAIT;
  Led8Clr();
  Led8Set(r_cnt,c_cnt);

  if(++c_cnt >= 8){
    c_cnt = 0;
    if(++r_cnt >=8){
      r_cnt = 0;
    }
  }
}

LEDマトリックスの点灯パターンの例を説明します。タイマで一定周期でLEDマトリックスを操作します。最初にLed8Clr()でLEDの初期化を行います。次にLedSet()関数で行列の番号を指定して点灯します。

c_cntは列の番号を管理する変数、r_cntは行を管理する変数とします。c_cntを+1ずつ更新しながらLed8Clr()とLed8Set()を処理すると1列目、2列目と移動するようにLEDを点灯させることができます。c_cntを8回更新するとc_cntをクリアしてr_cntを更新します。

r_cntを+1するとLEDの点灯箇所が1行下がります。この状態でc_cntを更新すると2行列の1列目から8列目まで移動するようにLEDを点灯させることができます。r_cntの更新を8回繰り返し8行目の8列目のLEDを点灯させると最初の位置の戻ります。

PR:テックジム-将来のためにプログラミングを学ぶ

LEDの輝度が低くなる例

LEDを複数点灯したとき回路説明

行に対して列のLEDを複数点灯させると電流がLED分だけ電流が分流するためLED1つあたりの輝度が低くなります。

LEDを複数点灯させたときの等価回路はLEDが並列に接続されるイメージです。

DOの電圧はHIGHであれば5V程度になりますが、LEDを点灯させるとLEDの順方向電圧によって2V程度電圧降下します。R1に流れる電流I0はI0=(5-2)/1000≒3mAになります。この3mAがLEDの分だけ分流(I1~I8)するためLED1つあたりの輝度が低下します。

LEDに流れる電流が分流してLEDの輝度が低下する例
LEDに流れる電流が分流してLEDの輝度が低下する例

左図のLEDの点灯(分流)のように列のLEDをすべて点灯させるとDOの出力電流が分流するためLED1つあたりの輝度が低下していることが分かります。右図のLEDの点灯(分流無し)のように列を固定した場合はDOの出力電流が分流しないため輝度が保てています。

スポンサーリンク

動作確認

電源を入れるとパターン1~パターン4までを繰り返します。ROW1、COW1を1行目1列目としてパターンの動作の確認を行います。

パターン1とパターン2のLEDの点灯
パターン1とパターン2のLEDの点灯

パターン1:左から右に列を更新しながらLEDを点灯し、8列目まで行くと行を更新して1列目から8列目までLEDを点灯します。8行目の8列目まで動作するとパターン2に遷移します。

パターン2:上から下に行を更新しながらLEDを点灯し、8行目まで行くと列を変更して1行目から8行目までLEDを点灯します。8行目の8列目まで動作するとパターン3に遷移します。

パターン3とパターン4のLEDの点灯
パターン3とパターン4のLEDの点灯

パターン3:列のLEDをすべて点灯させた状態で行を更新します。8行目まで動作するとパターン4に遷移します。

パターン4:行のすべてのLEDを点灯させた状態で列を更新します。8列目まで動作するとパターン1に戻ります。

パターン1~パターン4のLEDの点灯のパターンの切り替えは50ms毎に行うようにしています。ゆっくり変更させる場合はソースコード全体のLED8_WAIT 5の値を変更します。

パターン3とパターン4ではLEDの輝度の違いが分かります。輝度の違いが気になる場合はLEDの電流が可能な限り分流しないようにパターンを作る必要があります。

広告

ソースコード全体

以下のソースコードはコンパイルして動作確認をしております。コメントなど細かな部分で間違っていたりやライブラリの更新などにより動作しなくなったりする可能性があります。参考としてお使いいただければと思います。

#include <MsTimer2.h>

#define TIME_UP 0
#define TIME_OFF -1
#define LED8_WAIT 5

//→→→→→→→ ROW 1~8(行)
//↓
//↓
//↓
//COL 1~8(列)

const uint8_t col[8]={10, 11, 12, 13, A2, A3, A4, A5}; //列
const uint8_t row[8]={2, 3, 4, 5, 6, 7, 8, 9}; //行
uint8_t c_cnt;
uint8_t r_cnt;
uint8_t patnMode;
int16_t timLed8;

/* Local function prototypes */
void mainTimer(void);
void mainApp(void);
void Led8Set(uint8_t r, uint8_t c);
void Led8Clr(void);

void setup() {

  for(uint8_t i=0;i < 8; i++){ //行の初期設定
    pinMode(row[i],OUTPUT);
    digitalWrite(row[i], LOW);
  }  

  for(uint8_t i=0;i < 8; i++){ //列の初期設定
    pinMode(col[i],OUTPUT);
    digitalWrite(col[i], HIGH);
  }  

  MsTimer2::set(10, mainTimer); // 10ms period
  MsTimer2::start();
}

void loop() {
  
  mainApp();
}
/* タイマ管理 */
void mainTimer(void){

  if( timLed8 > TIME_UP ){
    --timLed8;
  }
}
/* メイン関数 */
void mainApp(void){
  uint8_t i;

  if(timLed8 == TIME_UP){
    switch(patnMode){
      case 0:
        timLed8 = LED8_WAIT;
        Led8Clr();
        Led8Set(r_cnt, c_cnt);

        if(++c_cnt >= 8){
          c_cnt = 0;
          if(++r_cnt >=8){
            r_cnt = 0;
            patnMode = 1;
          }
        }
        break;
      case 1:
        timLed8 = LED8_WAIT;
        Led8Clr();
        Led8Set(r_cnt,c_cnt);

        if(++r_cnt >= 8){
          r_cnt = 0;
          if(++c_cnt >=8){
            c_cnt = 0;
            patnMode = 2;
          }
        }
        break;
      case 2:
        timLed8 = LED8_WAIT;
        Led8Clr();

        for(i=0; i < 8; i++){
          Led8Set(r_cnt,i);
        }
        if(++r_cnt >=8){
          r_cnt = 0;
          patnMode = 3;
        }
        break;
      case 3:
        timLed8 = LED8_WAIT;
        Led8Clr();

        for(i=0; i < 8; i++){
          Led8Set(i,c_cnt);
        }
        if(++c_cnt >=8){
          c_cnt = 0;
          patnMode = 0;
        }
        break;
    }
  }
}
/* LEDを座標でON/OFFする */
void Led8Set(uint8_t r, uint8_t c){

  digitalWrite(row[r],HIGH); //行をセット
  digitalWrite(col[c],LOW); //列をセット
}
/* LEDをリセットする*/
void Led8Clr(void){

  for(uint8_t i=0; i < 8; i++){
    digitalWrite(row[i],LOW); //行
    digitalWrite(col[i],HIGH); //列
  }
}

関連リンク

Arduinoのライブラリを使って動作確認を行ったことを下記リンクにまとめています。

Arduinoで学べるマイコンのソフト開発と標準ライブラリの使い方

Seeeduino XIAOで学べるソフト開発と標準ライブラリの使い方

ESP32-WROOM-32Eで学べるソフト開発と標準ライブラリの使い方

PR:(即戦力のスキルを身に着ける:DMM WEBCAMP 学習コース(はじめてのプログラミングコース))

最後まで、読んでいただきありがとうございました。

タイトルとURLをコピーしました