// ライブラリの実装 //
#import "@preview/codelst:2.0.1": sourcecode


//フォント設定//
#let gothic  = "YuMincho"

//本文フォント//
#set text(11pt, font: gothic, lang: "ja") 

//タイトル・見出しフォント//
#set heading(numbering: "1.1")
#let heading_font(body) = {
  show regex("[\p{scx: Han}\p{scx: Hira}\p{scx: Kana}]"): set text(font: gothic)
  body
}
#show heading: heading_font

// ページ設定 //
#set page(
    paper: "a4",
    margin: (x: 25mm, y: 25mm),
    columns: 1,
    //fill: 背景色,
    numbering: "1",
    number-align: center,
    header: [
        #set text(8pt)
    ]
)

// 数式の表示の仕方を表示 //
#set math.equation(numbering: "(1)")

//本文ここから//
= 演習の目的
実験を通して、LEDマトリクス TOM-1588BH-Bの使い方と仕組みの習得を目的とする。

= 演習の使用部品
== @LEDマトリクス の電子部品 ( LEDマトリクス TOM-1588BH-B) を次のような点から調べなさい。

#figure(
  image("./img/LEDマトリクス.png",width: 50%),
  caption: "LEDマトリクス"
)<LEDマトリクス>

=== どのような部品か

8列8行のドットマトリックスディスプレイで、赤色の発光ダイオードを64個搭載している。 
8列8行のLEDで構成されており、各LEDは各列で共通のアノードと各行で共通のカソードを持っている。
電光掲示板や電子時計などに使用される。

=== どのような仕組みか

TOM-1588BH-Bは廃盤となっており、データシートが見つからなかったため、代わりに後継機であるTOM-1588AMG-N について調査した。
@LEDマトリクス回路図 に示すように、各LEDはアノードとカソードに接続されており、アノードに正の電圧を加え、カソードに接地することでLEDを点灯させる @led_matix_oasistek_dataheet。
各LEDは行と列の交点に配置されており、行と列の交点に電圧を加えることで、特定のLEDのみを点灯させることができる。

#figure(
  image("./img/LEDマトリクス回路図.png",width: 50%),
  caption: "LEDマトリクス回路図"
)<LEDマトリクス回路図>

=== どのような入力を取り扱うのか

電圧を入力として取り扱う。各LEDに対してアノードに正の電圧を加え、カソードに接地することでLEDを点灯させる。

=== 入力に応じて出力がどう変化するのか (データシートや仕様書を参考に) 

一つ一つのLEDは独立して制御されるため、入力に応じて出力が変化する。各LEDに対してアノードに正の電圧を加え、カソードに接地することでLEDを点灯させる。

=== どのようなピンアサイン (各ピンの役割) か 

@LEDマトリクスピンアサイン に示すように、8列8行のLEDマトリクスには、各列に対してアノードが、各行に対してカソードが接続されている。
実際のピンアサインと光る位置は綺麗に並んでいる訳ではないため、ピンアサインを確認しながら接続する必要がある。

#figure(
  image("./img/LEDマトリクスピンアサイン.png",width: 90%),
  caption: "LEDマトリクスピンアサイン"
)<LEDマトリクスピンアサイン>

=== 正しい動作の条件、範囲は何か

- ピーク順⽅向電流（1/10 デューティ サイクル、0.1ms パルス幅）: 80mA
- ドットあたりの消費電⼒ : 75mW
- 連続順⽅向電流 : 20mA
- 推奨動作電流 : 12mA
- 逆電圧 : 5V
- 動作温度範囲 : -25°C 〜 +85°C
- 保管温度範囲 : -30°C 〜 +85°C
- 鉛フリーはんだ温度（座⾯下1/16インチ）: 260°C 3秒

#pagebreak() // ページを分ける

= 課題内容

== フルカラーLEDを光らせる

=== 実験その１ (動作確認)

LEDマトリクスをダイナミック点灯方式を使って動作させる。配線して、アノードコモン(row 側) を用いたプログラムを入力しArduinoでその動作を確認し考察しなさい。

*回路図* 

@実験その1回路図_1 , @実験その1回路図_2 は、実験 1 の回路図を示す。 複数の出力ポートをまとめてコントロールし、LEDマトリクスに図を表示させる回路である。

#figure(
  image("./img/実験その1回路図1.png",width: 160%),
  caption: "実験その1回路図_1"
)<実験その1回路図_1>

#figure(
  image("./img/実験その1回路図2.png",width: 150%),
  caption: "実験その1回路図_2"
)<実験その1回路図_2>

#pagebreak() // ページを分ける

*プログラム*

@LEDマトリクスをアノードコモンで光らせるプログラム は、実験1 で使用したプログラムを示す。

#figure(
  sourcecode[```c
int ANODEPIN[] = {2, 3, 4, 5, 6, 7, 8, 9};
int CATHODEPIN[] = {10, 11, 12, 14, 15, 16, 17, 18};
int mat_A[8][8] = {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 1, 1, 0, 0, 0, 0, 0},
    {1, 1, 1, 0, 0, 0, 1, 0},
    {0, 0, 1, 1, 1, 0, 0, 1},
    {0, 0, 1, 1, 1, 1, 1, 0},
    {0, 0, 1, 1, 1, 1, 1, 0},
    {0, 1, 0, 0, 0, 0, 1, 0},
    {1, 0, 0, 0, 0, 0, 0, 1}};
int mat_B[8][8] = {
    {0, 1, 1, 0, 0, 0, 1, 0},
    {1, 1, 1, 0, 0, 0, 0, 1},
    {0, 0, 1, 1, 1, 0, 0, 1},
    {0, 0, 1, 1, 1, 1, 1, 0},
    {0, 0, 1, 1, 1, 1, 1, 0},
    {0, 0, 0, 1, 0, 0, 1, 0},
    {0, 0, 0, 0, 1, 1, 0, 0},
    {0, 0, 0, 1, 0, 0, 0, 0}};
void setup(){
    delay(1000); // 初期化処理待ち
    for (int ano = 0; ano < 8; ano++){
        pinMode(ANODEPIN[ano], OUTPUT);
        digitalWrite(ANODEPIN[ano], LOW);
    }
    for (int cat = 0; cat < 8; cat++){
        pinMode(CATHODEPIN[cat], OUTPUT);
        digitalWrite(CATHODEPIN[cat], HIGH);
    }
}
void loop(){
    unsigned long ms = millis();
    if ((ms / 1000) % 2 == 1){
        showMatrix(mat_A);
    }else{
        showMatrix(mat_B);
    }
}
void showMatrix(int matrix[8][8]){
    for (int ano = 0; ano < 8; ano++){
        for (int cat = 0; cat < 8; cat++){
            digitalWrite(CATHODEPIN[cat], (matrix[ano][cat] == 0 ? 1 : 0));
        }
        // 三項演算子を他の式でもできる
        digitalWrite(ANODEPIN[ano], HIGH);
        delay(500);
        digitalWrite(ANODEPIN[ano], LOW);
    }
}
    ```],
  caption: "LEDマトリクスをアノードコモンで光らせるプログラム"
)<LEDマトリクスをアノードコモンで光らせるプログラム>

- プログラムの概要
LEDマトリクスをダイナミック点灯方式を用いてアノードコモンで光らせるプログラムである
- プログラムの説明
  - 1–31 行目: 設定
    - 1,2行目はアノードとカソードのピンを設定している。
    - 3–20行目は、LEDマトリクスの点灯パターンを設定している。
    - 21–31行目は、pinMode関数を用いて、各ピンを出力に設定している。
  - 32–39 行目：プログラムの動作
    - 33行目で現在の時間を取得している。
    - 34–38行目で、時間に応じて、点灯パターンを切り替えている。
  - 40–49 行目 : showMatrix関数
    - 40–48行目で、各行のLEDを点灯させている。

*実験結果*

アノードのときは行ごとに制御できる。 
アノードの時、 HIGTからLOWへの切り替えるdeleyを3以下にするとチラつきがなくなる。 
アノードの時は同じアノードの行のなかで光るLEDの数が多い時は光が薄く、 LEDの数が少ない時は光が濃くなる。 
テキスト上のコードのままだとチラつきが発生した。 
行ごとに点灯消灯を管理している 

*考察*
+ LEDはダイナミック点灯を利用して、1つ1つは別のタイミングで光っているものでも、目の残像を利用して同時に光っているように錯覚させていた。 
+ アノードコモンでLEDを光らせる場合、アノードからくる5Vの電圧を分圧してカソード側に流すため並列接続の関係で電圧が分圧してしまうため、LEDが暗く写ってしまう。 
+ 三項演算子を用いて、アノードコモンでプログラムを書いているときにmat_A配列の値を逆にして、カソードの選択を行っていた。 
+ アノードコモンを用いるときは41–49行目で二重for文でマトリクスの光り方を制御している。41行目の第一for文では行を見ていて、42行目の第二for文でその行の各列を1つずつ見ている。 
+ 列を最後まで見た後入出力を切り替えて光らないようにして、次の行を見ていくので行ごとに描写されている。 




=== 実験その２ (カソードコモンを用いた動作の確認)

配線して、カソードコモン(col 側) を用いたプログラムを入力しArduinoで動作を確認し考察しなさい。

*回路図・プログラム* 

回路図は実験その1 と同じものを使用する。 
プログラムは実験その1 のプログラムをカソードコモンに変更する。
@LEDマトリクスをカソードコモンで光らせるプログラム は、実験その2 で使用したプログラムを示す。

#figure(
  sourcecode[```c
void showMatrix(int matrix[8][8]){
    for (int cat = 0; cat < 8; cat++){
        for (int ano = 0; ano < 8; ano++){
            digitalWrite(ANODEPIN[ano], matrix[ano][cat]);
        }
        // 三項演算子を他の式でもできる
        digitalWrite(CATHODEPIN[cat], LOW);
        delay(500);
        digitalWrite(CATHODEPIN[cat], HIGH);
    }
}
    ```],
  caption: "LEDマトリクスをカソードコモンで光らせるプログラム"
)<LEDマトリクスをカソードコモンで光らせるプログラム>

- プログラムの概要
LEDマトリクスをダイナミック点灯方式を用いてカソードコモンで光らせるプログラムの一部である
- プログラムの説明
  - 1–11 行目: showMatrix関数
    - 1–9行目で、各列のLEDを点灯させている。
    - HighとLowの値を逆にしている。

*実験結果*

カソードのときは列ごとに制御できる。 
アノードより、カソードの方が明るく光った。 
カソードの時はLOWからHIGHへの切り替えるdelayを1にしないとチラつきがなくならなかった。 
テキスト上のコードのままだとチラつきが発生した。 
列ごとに点灯消灯を管理している。

*考察*

+ LEDはダイナミック点灯を利用して、1つ1つは別のタイミングで光っているものでも、目の残像を利用して同時に光っているように錯覚させていた。 
+ カソードコモンでLEDを光らせる場合、アノードからくる5Vの電圧をLEDごとに使用できるため、LEDを明るく表示できた。 
+ カソードコモンを用いるときは二重for文でマトリクスの光り方を制御している。第一for文では列を見ていて、第二for文でその列の各行を1つずつ見ている。 
+ 行を最後まで見た後入出力を切り替えて光らないようにして、次の列を見ていくので列ごとに描写されている。 


=== 発展その１ (センサによる識別を用いたLED 制御)

LED マトリクスと加速度センサを組み合わせ、センサが反応している4 方向をLED マトリクス上に矢印の図(図5.6) で表せるようにしなさい。境界値・不感帯は、各自で判断すること。

#figure(
  image("./img/矢印の図.png",width: 50%),
  caption: "矢印の図"
)<矢印の図>

#pagebreak() // ページを分ける

*回路図* 

@発展その1回路図_1 , @発展その1回路図_2 は、発展その1の回路図を示す。 複数の出力ポートをまとめてコントロールし、LEDマトリクスに図を表示させる回路である。
また、加速度センサを用いて、センサが反応している4 方向をLED マトリクス上に矢印の図で表す。

#figure(
  image("./img/発展その1回路図1.png",width: 140%),
  caption: "発展その1回路図_1"
)<発展その1回路図_1>

#figure(
  image("./img/発展その1回路図2.png",width: 160%),
  caption: "発展その1回路図_2"
)<発展その1回路図_2>

#pagebreak() // ページを分ける

*プログラム*

@LEDマトリクスを加速度センサーで操作するプログラム1 , @LEDマトリクスを加速度センサーで操作するプログラム2 , @LEDマトリクスを加速度センサーで操作するプログラム3 は、加速度センサーでLEDマトリクスを操作するプログラムのである。
加速度と初期値の誤差を取得し、閾値を設定して、加速度センサーの値によって、LEDマトリクスを操作するプログラムである。
ブレッドボードの傾きにより、LEDマトリクスの矢印の向きが変わる。

#figure(
  sourcecode[```c
// chap5.1.1ex
int ANODEPIN[] = {2, 3, 4, 5, 6, 7, 8, 9};
int CATHODEPIN[] = {10, 11, 12, 14, 15, 16, 17, 18};
int right[8][8] = {
    {0, 0, 0, 0, 1, 0, 0, 0},
    {0, 0, 0, 0, 0, 1, 0, 0},
    {0, 0, 0, 0, 0, 0, 1, 0},
    {1, 1, 1, 1, 1, 1, 1, 1},
    {1, 1, 1, 1, 1, 1, 1, 1},
    {0, 0, 0, 0, 0, 0, 1, 0},
    {0, 0, 0, 0, 0, 1, 0, 0},
    {0, 0, 0, 0, 1, 0, 0, 0}};
int left[8][8] = {
    {0, 0, 0, 1, 0, 0, 0, 0},
    {0, 0, 1, 0, 0, 0, 0, 0},
    {0, 1, 0, 0, 0, 0, 0, 0},
    {1, 1, 1, 1, 1, 1, 1, 1},
    {1, 1, 1, 1, 1, 1, 1, 1},
    {0, 1, 0, 0, 0, 0, 0, 0},
    {0, 0, 1, 0, 0, 0, 0, 0},
    {0, 0, 0, 1, 0, 0, 0, 0}};
int up[8][8] = {
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 1, 0, 1, 1, 0, 1, 0},
    {1, 0, 0, 1, 1, 0, 0, 1},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0}};
int down[8][8] = {
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {1, 0, 0, 1, 1, 0, 0, 1},
    {0, 1, 0, 1, 1, 0, 1, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0}};
int normal[8][8] = {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0}};
    
    ```],
  caption: "LEDマトリクスを加速度センサーで操作するプログラム1/3"
)<LEDマトリクスを加速度センサーで操作するプログラム1>
#figure(
  sourcecode[```c
int xPin = 19;
int yPin = 20;
int zPin = 21;

// x,y,zの初期値保存用
int initialx, initialy, initialz;

// 初期値と入力値の誤差保存用
int inx, iny, inz;
int THRESHOLD = 50;
    ```],
  caption: "LEDマトリクスを加速度センサーで操作するプログラム2/3"
)<LEDマトリクスを加速度センサーで操作するプログラム2>

#figure(
  sourcecode[```c
void setup()
{
    pinMode(xPin, INPUT);
    pinMode(yPin, INPUT);
    pinMode(zPin, INPUT);
    Serial.begin(9600);
    delay(1000); // 初期化処理待ち
    for (int ano = 0; ano < 8; ano++)
    {
        pinMode(ANODEPIN[ano], OUTPUT);
        digitalWrite(ANODEPIN[ano], LOW);
    }
    for (int cat = 0; cat < 8; cat++)
    {
        pinMode(CATHODEPIN[cat], OUTPUT);
        digitalWrite(CATHODEPIN[cat], HIGH);
    }
    // 初期化
    initialx = analogRead(xPin);
    initialy = analogRead(yPin);
    initialz = analogRead(zPin);
}

void loop()
{
    inx = analogRead(xPin) - initialx;
    iny = analogRead(yPin) - initialy;
    inz = analogRead(zPin) - initialz;
    if (inx > THRESHOLD)
    {
        showMatrix(left);
    }
    else if (inx < -THRESHOLD)
    {
        showMatrix(right);
    }
    else if (iny > THRESHOLD)
    {
        showMatrix(down);
    }
    else if (iny < -THRESHOLD)
    {
        showMatrix(up);
    }
    else
    {
        showMatrix(normal);
    }
}
void showMatrix(int matrix[8][8])
{
    for (int cat = 0; cat < 8; cat++)
    {
        for (int ano = 0; ano < 8; ano++)
        {
            digitalWrite(ANODEPIN[ano], matrix[ano][cat]);
        }
        // 三項演算子を他の式でもできる
        digitalWrite(CATHODEPIN[cat], LOW);
        delay(1);
        digitalWrite(CATHODEPIN[cat], HIGH);
    }
}
    ```],
  caption: "LEDマトリクスを加速度センサーで操作するプログラム3/3"
)<LEDマトリクスを加速度センサーで操作するプログラム3>

- プログラムの概要
LEDマトリクスを加速度センサーで制御してダイナミック点灯方式を用いてカソードコモンで光らせるプログラムである。
加速度センサーの傾きを利用して、センサが反応している方向を表示するプログラムである。
- プログラムの説明
  - 1–59 行目: 設定
    - 1,2行目はアノードとカソードのピンを設定している。
    - 3–48行目は、LEDマトリクスの点灯パターンを設定している。
    - 50–59行目は、加速度センサーのpinを設定している。
    - 55–58行目は、加速度の値を変数に保存している。
    - 59行目は、閾値を設定している。
  - 61–82行目: Setup
    - 63–77行目で、各ピンを出力に設定している。
    - 79–82行目で、初期値を設定している。
  - 84–109行目 : loop関数
    - 86–88行目で、加速度の値を取得している。
    - 89–108行目で、加速度の値に応じて、点灯パターンを切り替えている。
  - 110–123 行目 : showMatrix関数
    - 112–123行目で、各列のLEDを点灯させている。

*実験結果*

今回の実験の軸の定義としては @加速度センサの軸 のように定義する。
1番ピンを右下にして4番ピンを右上にして、X軸、Y軸を図のように定義する。
Z軸については、図に対して垂直な方向をZ軸とする。
軸の定義は、データシートをもとにしている。
左に傾けた時は、ｘ軸方向に正の向きに傾けた時と定義をする。
手前に傾けた時は、ｙ軸方向に正の向きに傾けた時と定義をする。

#figure(
  image("./img/加速度センサの軸.png",width: 50%),
  caption: "加速度センサの軸"
)<加速度センサの軸>

X軸・Y軸に対してプラス軸方向、マイナス軸方向両方に約30度傾けたときに矢印をその軸の方向に表示するように制御を行なった。 
その時の境界値の値は50とした。 
中央値とアナログ入力値の差が絶対値50付近の時にばたつきが起きてしまう。 
初期値を取るときに平らな場所に置いていないと、意図した動作を起こさない。 

*考察*

ばたつきが起きた原因は境界値のみしか利用をしていないため。 
不感帯を利用するとばたつきを抑えられると考えられる。 
初期値を取るときに平らな場所に置いていないと、意図した動作を起こさない原因は、中央値を取るときに、最初の値を利用するためだと考えられる。 
最初の値を中央値と置き、そこからのセンサーの値との差を利用して傾きを検知した。 
差の閾値は50とする。 
加速度のX軸が正に傾いている時は 中央値とアナログ入力値の差 が -50よりも小さくなっている時に右矢印を表示する. 
X軸が負に傾いている時は逆の動作を行なう。
加速度のY軸が正に傾いている時は 中央値とアナログ入力値の差 が -50よりも小さくなっている時に上矢印を表示する. 
Y軸が負に傾いている時は逆の動作を行なう 

=== 発展その2(センサとスイッチを用いたLED 制御)

タクトスイッチを使って2 つのモード（A, B）の切替を導入し、発展その1 を拡張する。
モードA はシステム動作停止モードとし、モードB はシステム動作可能モードとする。初期モー
ドは「B. システム動作可能モード」とし、タクトスイッチの長押しで「A. システム動作停止モー
ド」に移行するようにしなさい。
またA ⇒ B のモード切り替え時に「起動」を意味するアニメーション、B ⇒ A の切り替え時には
「停止」を意味するアニメーションを再生する必要がある。このアニメーションは視覚的に充分確
認できる必要がある。なお「長押し」とは約2 秒程度タクトスイッチを押した状態が続く状態とす
る。モードの概要図とアニメーション図をそれぞれ @モードの概要図 、 @アニメーション図 に示す。

#figure(
  image("./img/モードの概要図.png",width: 90%),
  caption: "モードの概要図"
)<モードの概要図>

#figure(
  image("./img/アニメーション図.png",width: 90%),
  caption: "アニメーション図"
)<アニメーション図>

#pagebreak() // ページを分ける

*回路図* 

@発展その2回路図_1 , @発展その2回路図_2 は、発展その2の回路図を示す。 複数の出力ポートをまとめてコントロールし、LEDマトリクスに図を表示させる回路である。
また、加速度センサとタクトスイッチを用いて、センサが反応している方向を表示し、モードにより動作をさせるか変更を行う。

#figure(
  image("./img/発展その2回路図1.png",width: 140%),
  caption: "発展その2回路図_1"
)<発展その2回路図_1>

#figure(
  image("./img/発展その2回路図2.png",width: 160%),
  caption: "発展その2回路図_2"
)<発展その2回路図_2>

#pagebreak() // ページを分ける

*プログラム*

@LEDマトリクスをタクトスイッチを用いて状態を切り替えるプログラム1 , @LEDマトリクスをタクトスイッチを用いて状態を切り替えるプログラム2 , @LEDマトリクスをタクトスイッチを用いて状態を切り替えるプログラム3 ,@LEDマトリクスをタクトスイッチを用いて状態を切り替えるプログラム4 は、加速度センサーとタクトスイッチでLEDマトリクスを操作するプログラムのである。
加速度センサーの傾きを利用して、センサが反応している方向を表示し、モードにより動作をさせるか変更を行うプログラムである。

#figure(
  sourcecode[```c
// 使用するピンを定義
const int ANODEPIN[] = {2, 3, 4, 5, 6, 7, 8, 9};
const int CATHODEPIN[] = {10, 11, 12, 14, 15, 16, 17, 18};

// 各方向のパターンマトリックスを定義
const int modo_1[8][8] = {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 0, 1, 0, 0, 1, 0, 0},
    {0, 0, 1, 0, 0, 1, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0}};
const int modo_2[8][8] = {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 1, 1, 1, 1, 1, 1, 0},
    {0, 1, 0, 0, 0, 0, 1, 0},
    {0, 1, 0, 0, 0, 0, 1, 0},
    {0, 1, 0, 0, 0, 0, 1, 0},
    {0, 1, 0, 0, 0, 0, 1, 0},
    {0, 1, 1, 1, 1, 1, 1, 0},
    {0, 0, 0, 0, 0, 0, 0, 0}};
const int modo_3[8][8] = {
    {1, 1, 1, 1, 1, 1, 1, 1},
    {1, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 0, 0, 0, 0, 0, 1},
    {1, 0, 0, 0, 0, 0, 0, 1},
    {1, 1, 1, 1, 1, 1, 1, 1}};
const int right[8][8] = {
    {0, 0, 0, 0, 1, 0, 0, 0},
    {0, 0, 0, 0, 0, 1, 0, 0},
    {0, 0, 0, 0, 0, 0, 1, 0},
    {1, 1, 1, 1, 1, 1, 1, 1},
    {1, 1, 1, 1, 1, 1, 1, 1},
    {0, 0, 0, 0, 0, 0, 1, 0},
    {0, 0, 0, 0, 0, 1, 0, 0},
    {0, 0, 0, 0, 1, 0, 0, 0}};
const int left[8][8] = {
    {0, 0, 0, 1, 0, 0, 0, 0},
    {0, 0, 1, 0, 0, 0, 0, 0},
    {0, 1, 0, 0, 0, 0, 0, 0},
    {1, 1, 1, 1, 1, 1, 1, 1},
    {1, 1, 1, 1, 1, 1, 1, 1},
    {0, 1, 0, 0, 0, 0, 0, 0},
    {0, 0, 1, 0, 0, 0, 0, 0},
    {0, 0, 0, 1, 0, 0, 0, 0}};

    ```],
  caption: "LEDマトリクスをタクトスイッチを用いて状態を切り替えるプログラム1/4"
)<LEDマトリクスをタクトスイッチを用いて状態を切り替えるプログラム1>

#figure(
  sourcecode[```c
const int up[8][8] = {
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 1, 0, 1, 1, 0, 1, 0},
    {1, 0, 0, 1, 1, 0, 0, 1},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0}};
const int down[8][8] = {
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0},
    {1, 0, 0, 1, 1, 0, 0, 1},
    {0, 1, 0, 1, 1, 0, 1, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 0, 0, 1, 1, 0, 0, 0}};
const int normal[8][8] = {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 0, 1, 1, 1, 1, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0}};
// タクトスイッチ用ピンを定義
const int switch_Pin = 13;

// タクトスイッチの状態を保持する変数
int switch_in;
int preStatus = HIGH;

// 起動状態を保持する変数
bool boot_status = true;

// ボタンを押したタイミングの時間を保持する変数
unsigned long startSecond = 0;
unsigned long count = 0;

// x, y, z の初期値と閾値を定義
int initialx, initialy, initialz;
const int xPin = 19;
const int yPin = 20;
const int zPin = 21;
const int THRESHOLD = 50;

// 初期化関数
void setup(){
    pinMode(switch_Pin, INPUT_PULLUP);
    pinMode(xPin, INPUT);
    pinMode(yPin, INPUT);
    pinMode(zPin, INPUT);
    Serial.begin(9600);
    delay(1000);

    setupPins(); // ピンの初期化を行う関数

    // 初期値を取得
    initialx = analogRead(xPin);
    initialy = analogRead(yPin);
    initialz = analogRead(zPin);
}
    ```],
  caption: "LEDマトリクスをタクトスイッチを用いて状態を切り替えるプログラム2/4"
)<LEDマトリクスをタクトスイッチを用いて状態を切り替えるプログラム2>

#figure(
  sourcecode[```c
// ループ関数
void loop()
{
    handleButtonPress(); // ボタンの状態を処理する関数

    if (boot_status)
    {
        showArrow();
    }
}

// ピンの初期化を行う関数
void setupPins()
{
    for (int ano = 0; ano < 8; ano++)
    {
        pinMode(ANODEPIN[ano], OUTPUT);
        digitalWrite(ANODEPIN[ano], LOW);
    }
    for (int cat = 0; cat < 8; cat++)
    {
        pinMode(CATHODEPIN[cat], OUTPUT);
        digitalWrite(CATHODEPIN[cat], HIGH);
    }
}
// ボタンの状態を処理する関数
void handleButtonPress()
{
    switch_in = digitalRead(switch_Pin);
    Serial.println("switch_in");
    Serial.println(switch_in);

    if (switch_in == HIGH && preStatus == LOW)
    {
        startSecond = millis();
        count = 0;
    }
    else if (switch_in == LOW && preStatus == HIGH)
    {
        count = (millis() - startSecond) / 1000;
        Serial.print(count);
        Serial.println("秒");

        if (count >= 2)
        {
            if (!boot_status)
            {
                Serial.println("起動");
                showStartupAnimation();
                boot_status = true;
            }
            else
            {
                Serial.println("終了");
                showShutdownAnimation();
                boot_status = false;
            }
            count = 0;
        }
    }
    preStatus = switch_in;
}


    ```],
  caption: "LEDマトリクスをタクトスイッチを用いて状態を切り替えるプログラム3/4"
)<LEDマトリクスをタクトスイッチを用いて状態を切り替えるプログラム3>
#figure(
  sourcecode[```c
// 起動アニメーションを表示する関数
void showStartupAnimation()
{
    showMatrix(modo_1);
    showMatrix(modo_2);
    showMatrix(modo_3);
}

// 終了アニメーションを表示する関数
void showShutdownAnimation()
{
    showMatrix(modo_3);
    showMatrix(modo_2);
    showMatrix(modo_1);
}

// 矢印を表示する関数
void showArrow()
{
    int inx = analogRead(xPin) - initialx;
    int iny = analogRead(yPin) - initialy;
    int inz = analogRead(zPin) - initialz;
    Serial.print("x:");
    Serial.print(inx);
    Serial.print(" y:");
    Serial.print(iny);
    Serial.print(" z:");
    Serial.println(inz);

    if (inx > THRESHOLD)
    {
        showMatrix(left);
    }
    else if (inx < -THRESHOLD)
    {
        showMatrix(right);
    }
    else if (iny > THRESHOLD)
    {
        showMatrix(down);
    }
    else if (iny < -THRESHOLD)
    {
        showMatrix(up);
    }else{
        showMatrix(normal);
    }
}

// マトリックスを表示する関数
void showMatrix(const int matrix[8][8]){
    for (int i = 0; i < 30; i++){
        for (int cat = 0; cat < 8; cat++){
            for (int ano = 0; ano < 8; ano++){
                digitalWrite(ANODEPIN[ano], matrix[ano][cat]);
            }
            digitalWrite(CATHODEPIN[cat], LOW);
            delay(1);
            digitalWrite(CATHODEPIN[cat], HIGH);
        }
    }
}

    ```],
  caption: "LEDマトリクスをタクトスイッチを用いて状態を切り替えるプログラム4/4"
)<LEDマトリクスをタクトスイッチを用いて状態を切り替えるプログラム4>

- プログラムの概要
LEDマトリクスを加速度センサーで制御してダイナミック点灯方式を用いてカソードコモンで光らせるプログラムである。
加速度センサーの傾きを利用して、センサが反応している方向を表示するプログラムである。
- プログラムの説明
  - 1–98 行目: 設定
    - 1,2行目はアノードとカソードのピンを設定している。
    - 3–77行目は、LEDマトリクスの点灯パターンを設定している。
    - 80行目は、スイッチのpinを設定している。
    - 83,84行目は、スイッチの状態を保存する変数を設定している。
    - 87行目は、起動状態を保存する変数を設定している。
    - 90,91行目はボタンを押した時間を保存する変数を設定している。
    - 94–98行目は加速度関係の変数を設定している。
  - 101–116行目: Setup
    - 103–110行目で、各ピンを出力に設定している。
    - 113–115行目で、初期値を設定している。
  - 119–127行目 : loop関数
    - ボタンの処理とボタンの状態によって、起動状態を切り替える処理を行なっている。
  - 130–144 行目 : setupPins関数
    - 各ピンのpinModeを設定している。
  - 145–180 行目 : ボタンの状態を推定する関数
    - ボタンの状態を推定する関数を作成している。
    - ボタンが押された状態か、ボタンが離された状態かを判断している。
    - ボタンの過去の状態と現在の状態を比べ、ボタンが押された状態か、ボタンが離された状態かを判断している。
    - また、時間を取得して、ボタンが押された時間と現在の時間の差を取り、2秒間ボタンが押された状態かを判断している。
  - 183–196行目 : アニメーションを行う関数
    - 起動と終了をアニメーションで表示する関数を作成している。
  - 199–230行目 : 矢印を表示する関数
    - 加速度センサーの値によって、矢印を表示する関数を作成している。
  - 233–246行目 : showMatrix関数
    - 235–246行目で、各列のLEDを点灯させている。


*実験結果・考察*

起動状態と終了状態を分けるために変数を用いた。 
2秒間ボタンが押された状態を把握するために、 millis()を用いてボタンが押された前と後の秒数の差を取り長押しを判断した。 
switch_in preStatus を用いて、ボタンが押されたタイミングか、ボタンを離されたタイミングかを判断して、それによって2秒間のカウントを開始するか終了するかを判断した。 
関数に機能を分割してわかりやすいコードを心がけた 
起動中のアニメーションは発展１を参考にした。 


=== まとめ

LEDマトリクスをアノードコモン、カソードコモンを用いて光らせるプログラムを作成し、実験を行った。
マトリクスはアノードコモンの方が暗く、カソードコモンの方が明るく光ることがわかった。
また、ダイナミック点灯方式を用いて、複数個のLEDを制御ができる。



#pagebreak() // ページを分ける

// bibファイルの指定 //
#bibliography("./bibliography.bib")

