// 4桁7セグメントディスプレイ制御プログラム - スロットマシン版
//// 定数
int DIG_ON = LOW; // 桁点灯
int DIG_OFF = HIGH; // 桁消灯
// ピン定義
int P_SUBMIT = 2; // ラッチピン (ST_CP / RCLK)
int P_CLOCK = 3; // クロックピン (SH_CP / SRCLK)
int P_DATA = 4; // データピン (DS / SER)
int P_DIG1 = 5; // 桁1 (右端)
int P_DIG2 = 6; // 桁2
int P_DIG3 = 7; // 桁3
// int P_DIG4 = 8; // 桁4 (左端) - 4桁目は常に非表示にするため、このピン定義は使用しません。
// グローバル変数
// digitsToDisplay配列は4要素持つが、実際に表示に使うのは0,1,2番目の3桁のみ
// 4桁目 (digitsToDisplay[3]) は初期化の必要はありませんが、
// 配列の整合性のため0を保持させても問題ありません。
int digitsToDisplay[4] = {0, 0, 0, 0};
bool digitRunning[3] = {false, false, false}; // 各桁が動作中かどうか (3桁のみ)
bool hasStarted = false;
unsigned long lastUpdate = 0; // 最後の更新時間
const unsigned long updateInterval = 100; // 更新間隔 (速くしてスロットらしく)
// ボタンデバウンス用
unsigned long lastButtonPressTime = 0;
const unsigned long debounceDelay = 50; // デバウンス時間 (ミリ秒)
// ボタンピン定義
int P_START_BUTTON = 9;
int P_STOP_BUTTONS[3] = {10, 11, 12}; // 桁3 → 桁2 → 桁1 に対応
// 7セグメント表示用データ(共通陰極)
unsigned char digits[] = {
0b01111110, // 0
0b00110000, // 1
0b01101101, // 2
0b01111001, // 3
0b00110011, // 4
0b01011011, // 5
0b01011111, // 6
0b01110010, // 7
0b01111111, // 8
0b01111011 // 9
};
void setup() {
Serial.begin(9600);
randomSeed(analogRead(0)); // ランダムのシードを設定
// ピンモード設定
pinMode(P_SUBMIT, OUTPUT);
pinMode(P_CLOCK, OUTPUT);
pinMode(P_DATA, OUTPUT);
pinMode(P_DIG1, OUTPUT);
pinMode(P_DIG2, OUTPUT);
pinMode(P_DIG3, OUTPUT);
// pinMode(P_DIG4, OUTPUT); // 4桁目を非表示にするため、この行は削除またはコメントアウトします。
pinMode(P_START_BUTTON, INPUT_PULLUP);
for (int i = 0; i < 3; i++) {
pinMode(P_STOP_BUTTONS[i], INPUT_PULLUP);
}
// 初期表示(全桁0)
for(int i = 0; i < 3; i++) { // 3桁のみ初期化
digitsToDisplay[i] = 0;
}
}
void loop() {
// スタートボタン処理
if (digitalRead(P_START_BUTTON) == LOW && millis() - lastButtonPressTime > debounceDelay) {
lastButtonPressTime = millis();
if (!hasStarted) {
// ゲーム開始
hasStarted = true;
for (int i = 0; i < 3; i++) {
digitRunning[i] = true; // 全ての桁を動作状態に
}
Serial.println("--- GAME START ---");
} else {
// 全ての桁が停止している場合、リセット
bool allStopped = true;
for(int i = 0; i < 3; i++) {
if (digitRunning[i]) {
allStopped = false;
break;
}
}
if (allStopped) {
hasStarted = false;
for(int i = 0; i < 3; i++) {
digitsToDisplay[i] = 0; // 各桁を0に戻す
}
Serial.println("--- RESET ---");
}
}
}
// ストップボタン押下処理
if (hasStarted) {
for (int i = 0; i < 3; i++) {
if (digitRunning[i] && digitalRead(P_STOP_BUTTONS[i]) == LOW && millis() - lastButtonPressTime > debounceDelay) {
lastButtonPressTime = millis();
digitRunning[i] = false; // 該当桁を停止
Serial.print("STOP DIGIT ");
Serial.println(i + 1);
// 全ての桁が停止したかチェック
bool allStopped = true;
for(int j = 0; j < 3; j++) {
if (digitRunning[j]) {
allStopped = false;
break;
}
}
if (allStopped) {
Serial.println("--- ALL STOPPED ---");
// 揃ったか判定
if (digitsToDisplay[0] == digitsToDisplay[1] && digitsToDisplay[1] == digitsToDisplay[2]) {
Serial.println("!!! WIN !!!");
} else {
Serial.println("--- LOSE ---");
}
}
}
}
// 各桁のランダム数字更新
if (millis() - lastUpdate >= updateInterval) {
lastUpdate = millis();
for (int i = 0; i < 3; i++) { // 0, 1, 2番目の桁のみ
if (digitRunning[i]) {
digitsToDisplay[i] = random(0, 10); // 0〜9のランダムな数字を生成
}
}
}
}
// 全桁を表示
DisplayAllDigits();
}
void DisplayAllDigits() {
// 3桁のみを使用するため、P_DIG4はdigitPins配列に含めません。
int digitPins[] = {P_DIG1, P_DIG2, P_DIG3}; // 桁1〜桁3を指定 (右から左)
// 4桁目は配列から削除されているため、digitsToDisplayのインデックスはそのまま0,1,2を使用します。
// int displayIndices[] = {0, 1, 2}; // この行は冗長になりますが、残しても問題ありません。
for (int i = 0; i < 3; i++) { // 3桁のみをループして表示
digitalWrite(digitPins[i], DIG_ON); // 桁をオン
shiftOut(P_DATA, P_CLOCK, LSBFIRST, digits[digitsToDisplay[i]]); // digitsToDisplay[i] を直接使用
digitalWrite(P_SUBMIT, HIGH); // データをラッチ
digitalWrite(P_SUBMIT, LOW);
delay(5); // タイミング調整
digitalWrite(digitPins[i], DIG_OFF); // 桁をオフ
}
// 4桁目 (P_DIG4) はこの関数内で制御されません。
}