LED-Pong(テニスゲーム)の製作


 Arduino NANO、LED、ロータリーエンコーダーを使ってPongを製作

Arduino NANO、シフトレジスタ、LED、ロータリーエンコーダーを使ってLED-Pong(テニスゲーム)を製作。



 LEDの在庫が沢山あったので何か作れないかと思っていました。YouTubeにLEDを利用したPONG(テニスゲーム)が 掲載されていましたので、早速、Arduino NANOとシフトレジスタ74HC595を使って作成してみました。


  LED-Pong(テニスゲーム)の完成動画です。


 ボックスの左右に取り付けたロータリーエンコーダーを操作し、両サイドの赤と緑のLED3個(ラケット)を動かして ボールを跳ね返しています。3個のLEDの真ん中にボールが当たった時はまっすぐに跳ね返るようになっています。
 1ゲームが終了するとブザーが鳴り、次のゲームに移ります。その時ボールのスピードを少しだけですがランダムに 早くしています。



以下のように順次確認して作成しました。



  確認1:8個のLEDをひとつずつ順番に光らせる。


Arduino NANOとシフトレジスタ74HC595を1個使って、8個のLEDを順次点滅させました。

1.実験動画です。



2.回路図は次のようにしました。


3.スケッチプログラムについて
 スケッチプログラムの関数shiftOut()の使用方法は以下の通りです。
shiftOut(dataPin, clockPin, bitOrder, value)  (Arduino 日本語リファレンスより)
 1バイト分のデータを1ビットずつ「シフトアウト」します。最上位ビット(MSB)と最下位ビット(LSB)の どちらからもスタートできます。各ビットはまずdataPinに出力され、その後clockPinが反転して、 そのビットが有効になったことが示されます。

dataPin : 各ビットを出力するピン
clockPin : クロックを出力するピン。dataPinに正しい値がセットされたら、このピンが1回反転します
bitOrder : MSBFIRSTまたはLSBFIRSTを指定します。
MSBFIRST : Most Significant Bit Firstは最上位ビットから送ることを示します。
LSBFIRST : Least Significant Bit Firstは最下位ビットから送ることを示します。
value : 送信したいデータ (byte)

int dataPin = 8;  // 74HC595のDSピンへ
int latchPin = 9;  // 74HC595のST_CPピンへ
int clockPin = 10; // 74HC595のSH_CPピンへ

void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void loop() {
    for (int i = 0; i < 8; i++) {
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, 1 << i);
    digitalWrite(latchPin, HIGH);
    delay(300);
  }
}
						




  確認2:16個のLEDをひとつずつ順番に光らせる。


 2個のシフトレジスタ74HC595を使ってデイジーチェーン接続しています。(1個目のシフトレジスタの Q7端子を2個目のシフトレジスタのDS端子に接続しています。)
 LEDの点灯は、LED1→LED2→・・・・・→LED15→LED16→LED1→LED2→・・・・の順番で点灯します。 LED16が点灯したら、最初のLED1に戻ります。

1.実験動画です。



2.回路図です。


3.スケッチプログラムです。

int dataPin = 8;  // 74HC595のDSへ
int latchPin = 9; // 74HC595のST_CPへ
int clockPin = 10; // 74HC595のSH_CPへ

int shift_val = 1;
int first_shift_val = 0;
int second_shift_val = 0;

void setup() {
  Serial.begin(9600);
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void loop() {
  for (int i = 0; i < 16; i++) {
    first_shift_val = shift_val << i;
    second_shift_val = first_shift_val >> 8;
    
    digitalWrite(latchPin, LOW); 
    shiftOut(dataPin, clockPin, MSBFIRST, second_shift_val); 
    shiftOut(dataPin, clockPin, MSBFIRST, first_shift_val);
    digitalWrite(latchPin, HIGH);
    delay(300);
  }
  first_shift_val = 0;
  second_shift_val = 0;
}
						




  確認3:16個のLEDの点灯順を変更


 回路図は、上記「確認2」と同じです。LED1→LED2→・・・・・→LED15→LED16→LED15→LED14→・・・・LED2→LED1の 順番で点灯します。LED16が点灯したら、最初に戻らないで、逆方向にシフトしていきます。

1.実験動画です。



2.スケッチプログラムです。

int DataPin = 8;
int LatchPin = 9;
int ClockPin = 10;

int leds[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int mult[8] = {128,64,32,16,8,4,2,1};
int first_shift_val = 0;
int second_shift_val = 0;

int ball_update = 400;
int ball_location = 0;
int ball_Hdir = 1;
int loops = 0;

void setup() {
  Serial.begin(9600);
  pinMode(DataPin, OUTPUT);
  pinMode(ClockPin, OUTPUT);
  pinMode(LatchPin, OUTPUT);
}

void loop() {
  digitalWrite(LatchPin, LOW);
  shiftOut(DataPin,ClockPin,MSBFIRST,0);
  shiftOut(DataPin,ClockPin,MSBFIRST,0);
  digitalWrite(LatchPin, HIGH);

  for(int i = 0; i < 8; i++){
    first_shift_val += leds[i]*mult[7-i];
    second_shift_val += leds[15-i]*mult[i];
  }
  digitalWrite(LatchPin, LOW);
  shiftOut(DataPin,ClockPin,MSBFIRST,second_shift_val);
  shiftOut(DataPin,ClockPin,MSBFIRST,first_shift_val);
  digitalWrite(LatchPin, HIGH);
  first_shift_val = 0;
  second_shift_val = 0;
  
  if(loops % ball_update == 0){    
    if(loops == 0){
      leds[ball_location] = 1;
    } else {
      leds[ball_location] = 0;
      if(ball_location == 0){
        ball_Hdir *= -1;
        ball_location = 0;
      }
      if(ball_location == 15){
        ball_Hdir *= -1;
        ball_location = 15;
      }
      ball_location += ball_Hdir;
      leds[ball_location] = 1;
    }
  }
  loops++;  
}
						




  確認4:ボールが動く部分の作成


ボールの部分は、LED8×16個を行列にしてあります。
 使用するLEDについてですが、透明ケースのLEDは、光が拡散しないので横から見るとLEDの点滅が 見えにくいと思います。その点、不透明ケース(色付きのケース)の方は光が拡散して良く見えます。

1.実験動画です。



2.回路図です。

3.LEDの設置板の製作。
(1)3Dプリンターで次の3種類を作りました。

 (a) LEDを設置する表板(黒い部分)です。


 (b) 実験用のLED設置板の裏板(白い部分)です。


 (c) 完成版のLED設置板の裏板(白い部分)です。ラケット用のLEDを設置します。


(2)下図のようにLEDを一定方向にして設置表板(黒い部分)の穴に挿していきます。その際少量の 接着剤をつけて挿入します。
 注意:この場合は、LEDのプラスリード線は全て左側です。プラスとマイナスの方向を間違わないこと


(3)LEDのプラスの端子を根元から2mmくらいの所で折って、下図のように8個分のプラスの端子を半田付けします。
マイナスの端子は、そのまま真っすぐにしておきます。


(4)プラスの端子の半田付けを16列行い、16本のリード線を各列に半田付けします。その後、設置板の裏板(白い部分)の スリットから全てのマイナス端子を出して、下図のように横1列を半田付けし各行に8本のリード線を半田付けします。




4.スケッチプログラムです。

int DataPin = 8;
int LatchPin = 9;
int ClockPin = 10;

int leds[8][16] = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 
                 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                         
                 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                           
                 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                           
                 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},                          
                 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
                 
int mult[16] = {128,64,32,16,8,4,2,1};
int first_shift_val = 0;
int second_shift_val = 0;

int C_DataPin = 5;
int C_LatchPin = 6;
int C_ClockPin = 7;
int rowbase = 255;
int row = 0;

int ball_location[2] = {0,5};
int ball_Hdir = 1;
int ball_Vdir = 1;
int ball_update = 40;
int loops = 0;

void setup() {
  Serial.begin(9600);
  pinMode(DataPin, OUTPUT);
  pinMode(ClockPin, OUTPUT);
  pinMode(LatchPin, OUTPUT);
  pinMode(C_DataPin, OUTPUT);
  pinMode(C_ClockPin, OUTPUT);
  pinMode(C_LatchPin, OUTPUT);
}

void loop() {
  if(row > 7){
    row=0;
    loops++;
  }

  while (row < 8){ 
    digitalWrite(LatchPin, LOW);
    shiftOut(DataPin,ClockPin,MSBFIRST,0);
    shiftOut(DataPin,ClockPin,MSBFIRST,0);
    digitalWrite(LatchPin, HIGH);
    
    digitalWrite(C_LatchPin, LOW);
    shiftOut(C_DataPin,C_ClockPin,MSBFIRST,rowbase - mult[row]);
    digitalWrite(C_LatchPin, HIGH);
    
    for(int i = 0; i < 8; i++){
      first_shift_val += leds[row][i]*mult[7-i];
      second_shift_val += leds[row][15-i]*mult[i];
    }
    digitalWrite(LatchPin, LOW);
    shiftOut(DataPin,ClockPin,MSBFIRST,second_shift_val);
    shiftOut(DataPin,ClockPin,MSBFIRST,first_shift_val);
    digitalWrite(LatchPin, HIGH);
    first_shift_val = 0;
    second_shift_val = 0;

    row++;
  }

  if(loops % ball_update == 0){
    if(loops == 0){
      leds[ball_location[0]][ball_location[1]] = 1;
    }else{
      leds[ball_location[0]][ball_location[1]] = 0;
      if( ball_location[0]+ ball_Vdir == 8 || ball_location[0]+ ball_Vdir == -1){
        ball_Vdir *= -1;
      }
      
      if(ball_location[1]+ ball_Hdir == 16 || ball_location[1]+ ball_Hdir == -1){            
        ball_Hdir *= -1;
      }        
     
      ball_location[0 += ball_Vdir;
      ball_location[1] += ball_Hdir;
      leds[ball_location[0]][ball_location[1]] = 1;
    }
  }
}
						




  確認5:両サイドのラケット(3個のLED)を、エンコーダーを使用して作成


1.実験動画です。



2.ロータリーエンコーダーについて
 単純な3端子のロータリーエンコーダーを使用します。そのうちの 1 つを接地して、他の2 つのピンは 状態が変化し、常にハイまたはローのいずれかであるため、組み合わせは合計 4 つあります。00、01、10、および 11です。
 実際にできることは、値が変化するたびに、それがどの方向に回転移動したかを確認できることです。 また、開始してからどれだけ回転移動したかを追跡できます
 エンコーダーには、HIGH または LOW の 2 つのデジタル ピンがあります。ピンをバイナリとして扱う場合、 00、01、10、または 11 として読み取ります。
 時計回りに回転している間にエンコーダーが出力するシーケンスは、00、01、11、10 の繰り返しです。 したがって、読み取り値が 01 の場合、次の読み取り値は、ノブを回す方向に応じて 00 または 11 になります。
 以前にエンコードされた値を現在のエンコードされた値の先頭に追加することにより、8 つの可能な数字 (0001、 0010、0100、0111、1000、1011、1110 、1101) のうちの 1 つを取得します。
 1110、0111、0001、1000 はすべて反時計回りです。

3.回路図です。


なお、74HC595のdataPin、latchPin、clockPinは、Arduinoのアナログピンをデジタルピンとして利用しています。

4.スケッチプログラムです。

int DataPin = 14;
int LatchPin = 15;
int ClockPin = 16;

int leds[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int mult[8] = {128,64,32,16,8,4,2,1};
int R1_shift_val = 0;
int R2_shift_val = 0;

int racket1 = 0;
int r1encA = 2;
int r1encB = 3;
int r1encA_last;
int r1encA_now;
bool racket1change = false;
int racket2 = 0;
int r2encA = 11;
int r2encB = 12;
int r2encA_last;
int r2encA_now;
bool racket2change = false;

void setup() {
  pinMode(DataPin, OUTPUT);
  pinMode(ClockPin, OUTPUT);
  pinMode(LatchPin, OUTPUT);
  
  pinMode(r1encA,INPUT);
  pinMode(r1encB,INPUT);
  digitalWrite(r1encA,HIGH);
  digitalWrite(r1encB,HIGH);
  r1encA_last = digitalRead(r1encA);
  
  pinMode(r2encA,INPUT);
  pinMode(r2encB,INPUT);
  digitalWrite(r2encA,HIGH);
  digitalWrite(r2encB,HIGH);
  r2encA_last = digitalRead(r2encA);

void loop() {
  leds[racket1] = 1;
  leds[racket1+1] = 1;
  leds[racket1+2] = 1;
  
  leds[racket2+8] = 1;
  leds[racket2+9] = 1;
  leds[racket2+10] = 1;
 //******************************************
  digitalWrite(LatchPin, LOW);
  shiftOut(DataPin,ClockPin,MSBFIRST,0);
  shiftOut(DataPin,ClockPin,MSBFIRST,0);  
  digitalWrite(LatchPin, HIGH);
  
  for(int i = 0; i < 8; i++){
    R1_shift_val += leds[i]*mult[7-i];
    R2_shift_val += leds[15-i]*mult[i];
  }
  
  digitalWrite(LatchPin, LOW);
  shiftOut(DataPin,ClockPin,MSBFIRST,R2_shift_val);
  shiftOut(DataPin,ClockPin,MSBFIRST,R1_shift_val);
  digitalWrite(LatchPin, HIGH);
  R1_shift_val = 0;
  R2_shift_val = 0;
  //******************* racket control*********************************
  r1encA_now = digitalRead(r1encA);
  if((r1encA_last == HIGH) && (r1encA_now == LOW)){
    if(digitalRead(r1encB) == LOW){
      if(racket1 > 0){
        racket1--;
      }
    }else{
      if(racket1 < 5){
        racket1++;
      }
    }
    racket1change = true;
  }
  r1encA_last = r1encA_now;
  
  if(racket1change == true){
    leds[0] = 0;
    leds[1] = 0;
    leds[2] = 0;
    leds[3] = 0;
    leds[4] = 0;
    leds[5] = 0;
    leds[6] = 0;
    leds[7] = 0;
    racket1change = false;
  }
  
  r2encA_now = digitalRead(r2encA);
  if((r2encA_last == HIGH) && (r2encA_now == LOW)){
    if(digitalRead(r2encB) == LOW){
      if(racket2 > 0){
        racket2--;
      }
    }else{
      if(racket2 < 5){
        racket2++;
      }
    }
    racket2change = true;
  }
  r2encA_last = r2encA_now;

  if(racket2change == true){
    leds[8] = 0;
    leds[9] = 0;
    leds[10] = 0;
    leds[11] = 0;
    leds[12] = 0;
    leds[13] = 0;
    leds[14] = 0;
    leds[15] = 0;
    racket2change = false;
  }
}
						

なお、void setup()の
digitalWrite(r1encA,HIGH);
digitalWrite(r1encB,HIGH); は、プルアップ抵抗をオンにするためのものです。




  LED_Pongの完成


 LED設置板、ロータリーエンコーダー、回路基板、ブザー、電源プラグを木製の箱に設置し完成させました。

1.回路図です。


2.全スケッチプログラムです。

int DataPin = 8;
int LatchPin = 9;
int ClockPin = 10;

int leds[8][16] = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
int R_leds[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int mult[16] = {128,64,32,16,8,4,2,1};
int first_shift_val = 0;
int second_shift_val = 0;
int R1_shift_val = 0;
int R2_shift_val = 0;

int C_DataPin = 5;
int C_LatchPin = 6;
int C_ClockPin = 7;

int R_DataPin = 14;
int R_LatchPin = 15;
int R_ClockPin = 16;

int rowbase = 255;
int row = 0;

int ball_pos[2] = {0,5};
int ball_Hturn = 1;
int ball_Vturn = 1;
int ball_speed = 30;

int racket1 = 0;
int r1encA = 2;
int r1encB = 3;
int r1encA_last;
int r1encA_now;
bool racket1change = false;

int racket2 = 0;
int r2encA = 11;
int r2encB = 12;
int r2encA_last;
int r2encA_now;
bool racket2change = false;

int buzzer = 4;
int repeat = 0;
bool gameover = false;
int gameover_start_timer = 0;
int gameover_end_timer = 0;

void setup() {
  Serial.begin(9600);
  pinMode(DataPin, OUTPUT);
  pinMode(LatchPin, OUTPUT);
  pinMode(ClockPin, OUTPUT);
  pinMode(C_DataPin, OUTPUT);
  pinMode(C_LatchPin, OUTPUT);
  pinMode(C_ClockPin, OUTPUT);
    
  pinMode(R_DataPin, OUTPUT);
  pinMode(R_LatchPin, OUTPUT);
  pinMode(R_ClockPin, OUTPUT);
      
  pinMode(r1encA,INPUT);
  pinMode(r1encB,INPUT);
  digitalWrite(r1encA,HIGH);
  digitalWrite(r1encB,HIGH);
  r1encA_last = digitalRead(r1encA);
    
  pinMode(r2encA,INPUT);
  pinMode(r2encB,INPUT);
  digitalWrite(r2encA,HIGH);
  digitalWrite(r2encB,HIGH);
  r2encA_last = digitalRead(r2encA);
  
  pinMode(buzzer,OUTPUT);
  digitalWrite(buzzer,LOW);
}

void loop() {
  R_leds[racket1] = 1;
  R_leds[racket1 + 1] = 1;
  R_leds[racket1 + 2] = 1;
  
  R_leds[racket2 + 8] = 1;
  R_leds[racket2 + 9] = 1;
  R_leds[racket2 + 10] = 1;
  //**********R_RACKET LED****************
  digitalWrite(R_LatchPin, LOW);
  shiftOut(R_DataPin,R_ClockPin,MSBFIRST,0);
  shiftOut(R_DataPin,R_ClockPin,MSBFIRST,0);
  digitalWrite(R_LatchPin, HIGH);
  
  for(int i = 0; i < 8; i++){
    R1_shift_val += R_leds[i]*mult[7-i];
    R2_shift_val += R_leds[15-i]*mult[i];
  }
  
  digitalWrite(R_LatchPin, LOW);
  shiftOut(R_DataPin,R_ClockPin,MSBFIRST,R2_shift_val);
  shiftOut(R_DataPin,R_ClockPin,MSBFIRST,R1_shift_val);
  digitalWrite(R_LatchPin, HIGH);
  R1_shift_val = 0;
  R2_shift_val = 0;
  //**********Ball LED****************
  if(row > 7){
    row = 0;
    repeat++;
  }

  while (row < 8){
    digitalWrite(LatchPin, LOW);
    shiftOut(DataPin,ClockPin,MSBFIRST,0);
    shiftOut(DataPin,ClockPin,MSBFIRST,0);
    digitalWrite(LatchPin, HIGH);
    
    digitalWrite(C_LatchPin, LOW);
    shiftOut(C_DataPin,C_ClockPin,MSBFIRST,rowbase - mult[row]);
    digitalWrite(C_LatchPin, HIGH);
    
    for(int i = 0; i < 8; i++){
      first_shift_val += leds[row][i]*mult[7-i];
      second_shift_val += leds[row][15-i]*mult[i];
    }
    digitalWrite(LatchPin, LOW);
    shiftOut(DataPin,ClockPin,MSBFIRST,second_shift_val);
    shiftOut(DataPin,ClockPin,MSBFIRST,first_shift_val);
    digitalWrite(LatchPin, HIGH);
    first_shift_val = 0;
    second_shift_val = 0;

    row++;
  }
  //**********RACKET Control****************************
  if (gameover != true){
    r1encA_now = digitalRead(r1encA);
    if((r1encA_last == HIGH) && (r1encA_now == LOW)){
      if(digitalRead(r1encB) == LOW){
        if(racket1 > 0){
          racket1--;
        }
      }else{
        if(racket1 < 5){
          racket1++;
        }
      }
      racket1change = true;
    }
    r1encA_last = r1encA_now;
    if(racket1change == true){
      for(int i = 0; i < 8; i++){
        R_leds[i] = 0;
      }
      racket1change = false;
    }
  }
  if (gameover != true){
    r2encA_now = digitalRead(r2encA);
    if((r2encA_last == HIGH) && (r2encA_now == LOW)){
      if(digitalRead(r2encB) == LOW){
        if(racket2 > 0){
          racket2--;
        }
      }else{
        if(racket2 < 5){
          racket2++;
        }
      }
      racket2change = true;
    }
    r2encA_last = r2encA_now;
    if(racket2change == true){
      for(int i = 8; i < 16; i++){
        R_leds[i] = 0;
      }
      racket2change = false;
    }
  }
//*************Ball movement****************
  if(gameover != true){
    if(repeat % ball_speed == 0){
      if(repeat==0){
        leds[ball_pos[0]][ball_pos[1]] = 1;
      }else{
        leds[ball_pos[0]][ball_pos[1]] = 0;
        if( ball_pos[0] + ball_Vturn == 8 || ball_pos[0] + ball_Vturn == -1){
          ball_Vturn *= -1;
        }
            
        if(ball_pos[1] == 0){
          if(ball_pos[0] == racket1){
            ball_Hturn *= -1;
            ball_Vturn = 1;
          }else if(ball_pos[0] == (racket1 + 1)){
            ball_Hturn *= -1;
            ball_Vturn = 0;
          }else if(ball_pos[0] == (racket1 + 2)){
            ball_Hturn *= -1;
            ball_Vturn = -1;
          }else{
            gameover = true;
            digitalWrite(buzzer,HIGH);
            delay(500);
            digitalWrite(buzzer,LOW);
            ball_pos[0] = 0;
            ball_pos[1] = 5;
            ball_Hturn = 1;
            ball_Vturn = 1;
            ball_speed = random(15,31);
            repeat = 0;
          }
        }

        if(ball_pos[1] == 15){
          if(ball_pos[0] == racket2){
            ball_Hturn *= -1;
            ball_Vturn = 1;
          }else if(ball_pos[0] == (racket2 + 1)){
            ball_Hturn *= -1;
            ball_Vturn = 0;
          }else if(ball_pos[0] == (racket2 + 2)){
            ball_Hturn *= -1;
            ball_Vturn = -1;
          }else{
            gameover = true;
            digitalWrite(buzzer,HIGH);
            delay(500);
          digitalWrite(buzzer,LOW);
            ball_pos[0] = 7;
            ball_pos[1] = 11;
            ball_Hturn *= -1;
            ball_Vturn = -1;
            ball_speed = random(15,31);
            repeat = 0;
          }
        }
        if(gameover != true){
          ball_pos[0] += ball_Vturn;
          ball_pos[1] += ball_Hturn;
        } 
        leds[ball_pos[0]][ball_pos[1]] = 1;
      }
    }
  }
  if(gameover == true){
    if (gameover_start_timer == 0 ){
      gameover_start_timer = repeat;
      gameover_end_timer = repeat + 1000;
    }else if(repeat >= gameover_end_timer){
      gameover = false;
      gameover_start_timer = 0;
    }
  }
}
						




  3Dプリンタ―用 stlファイルのダウンロード


LED設置板3種類のSTLファイル「LED_PONG1」、「LED_PONG2」、「LED_PONG3」のダウンロードです。
なお、「LED_PONG3」は実験用のもので、完成版は「LED_PONG1」、「LED_PONG2」を使用します。

Download