#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Định nghĩa màn hình OLED
#define SCREEN_WIDTH 128 // Độ rộng màn hình OLED, tính bằng pixel
#define SCREEN_HEIGHT 64 // Chiều cao màn hình OLED, tính bằng pixel
#define OLED_RESET -1 // Chân Reset (hoặc -1 nếu chia sẻ chân Reset với Arduino)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Định nghĩa các chân cho màn hình LED 7 đoạn (dùng common cathode)
const int segPins[7] = {2, 4, 5, 18, 19, 16, 17}; // a,b,c,d,e,f,g
const int digitPins[4] = {14, 12, 13, 15}; // 4 digits
// Định nghĩa các chân cho nút nhấn
#define BTN_A 25 // Nút nhấn tăng điểm đội A
#define BTN_B 26 // Nút nhấn tăng điểm đội B
#define BTN_END_MATCH 27 // Nút nhấn kết thúc trận đấu
// Biến lưu điểm số
int matchScores[] = {0, 0};
int totalScores[] = {0, 0, 0, 0}; // Điểm tổng của 4 đội A, B, C, D
// Lịch thi đấu vòng tròn
char teams[] = {'A', 'B', 'C', 'D'};
int matches[6][2] = {
{0, 1}, // A vs B
{2, 3}, // C vs D
{0, 2}, // A vs C
{1, 3}, // B vs D
{0, 3}, // A vs D
{1, 2} // B vs C
};
int currentMatchIndex = 0;
int totalMatches = 6;
// Biến trạng thái nút nhấn (để chống dội)
bool lastBtnAState = LOW;
bool lastBtnBState = LOW;
bool lastBtnEndState = LOW;
// map số ra mã 7-seg
const byte segMap[10] = {
B1111110, //0
B0110000, //1
B1101101, //2
B1111001, //3
B0110011, //4
B1011011, //5
B1011111, //6
B1110000, //7
B1111111, //8
B1111011 //9
};
// Hàm hiển thị số trên màn hình 7 đoạn
void showNumber(int num) {
int digits[4];
for (int i = 3; i >= 0; i--) {
digits[i] = num % 10;
num /= 10;
}
for (int d = 0; d < 4; d++) {
//digitalWrite(digitPins[d], LOW);
for (int s = 0; s < 7; s++) {
bool on = segMap[digits[d]] & (1 << (6 - s));
digitalWrite(segPins[s], on); // ? HIGH : LOW);
}
//delayMicroseconds(50); // Multiplexing delay
digitalWrite(digitPins[d], LOW);
digitalWrite(digitPins[d], HIGH);
}
}
// Hàm cập nhật màn hình OLED
void updateOLED() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
// Hiển thị tên đội và điểm số
display.setCursor(0, 0);
display.print("Tran Dau ");
display.print(currentMatchIndex + 1);
display.print("/");
display.println(totalMatches);
display.setTextSize(2);
display.setCursor(0, 16);
display.print("Doi ");
display.print(teams[matches[currentMatchIndex][0]]);
display.print(" vs ");
display.println(teams[matches[currentMatchIndex][1]]);
// Hiển thị điểm số trận đấu
display.setTextSize(4);
display.setCursor(15, 36);
display.print(matchScores[0]);
display.setCursor(85, 36);
display.println(matchScores[1]);
display.display();
}
// Hàm kết thúc trận đấu và tính điểm tổng
void endMatch() {
int team1Index = matches[currentMatchIndex][0];
int team2Index = matches[currentMatchIndex][1];
// Xác định đội thắng cuộc dựa trên quy tắc cầu lông:
// Thắng khi đạt 21 điểm và hơn đối thủ ít nhất 2 điểm.
// Hoặc thắng khi đạt 30 điểm (đối với trường hợp 29-29)
int score1 = matchScores[0];
int score2 = matchScores[1];
if ((score1 >= 21 && score1 - score2 >= 2) || score1 == 30) {
totalScores[team1Index]++;
Serial.print("Doi "); Serial.print(teams[team1Index]); Serial.println(" thang cuoc!");
} else if ((score2 >= 21 && score2 - score1 >= 2) || score2 == 30) {
totalScores[team2Index]++;
Serial.print("Doi "); Serial.print(teams[team2Index]); Serial.println(" thang cuoc!");
} else {
Serial.println("Chua du dieu kien thang cuoc. Hay tiep tuc choi.");
return; // Thoát hàm nếu chưa có đội thắng
}
// Đặt lại điểm số trận
matchScores[0] = 0;
matchScores[1] = 0;
// Chuyển sang trận đấu tiếp theo
currentMatchIndex++;
if (currentMatchIndex >= totalMatches) {
currentMatchIndex = 0; // Vòng lặp lại giải đấu
Serial.println("Giai dau da ket thuc! He thong se khoi dong lai.");
// Ghi điểm tổng ra Serial
for (int i = 0; i < 4; i++) {
Serial.print("Diem tong Doi ");
Serial.print(teams[i]);
Serial.print(": ");
Serial.println(totalScores[i]);
}
}
// Cập nhật màn hình
updateOLED();
}
void setup() {
Serial.begin(115200);
// Khởi tạo màn hình OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
display.display();
delay(2000);
display.clearDisplay();
// Khởi tạo các chân nút nhấn
pinMode(BTN_A, INPUT_PULLUP);
pinMode(BTN_B, INPUT_PULLUP);
pinMode(BTN_END_MATCH, INPUT_PULLUP);
// Khởi tạo các chân màn hình 7 đoạn
for (int i = 0; i < 7; i++) pinMode(segPins[i], OUTPUT);
for (int i = 0; i < 4; i++) pinMode(digitPins[i], OUTPUT);
// Bắt đầu hiển thị
updateOLED();
}
void loop() {
// Đọc trạng thái nút nhấn
bool btnAState = digitalRead(BTN_A);
bool btnBState = digitalRead(BTN_B);
bool btnEndState = digitalRead(BTN_END_MATCH);
// Xử lý nút nhấn đội A
if (btnAState == LOW && lastBtnAState == HIGH) {
matchScores[0]++;
updateOLED();
}
// Xử lý nút nhấn đội B
if (btnBState == LOW && lastBtnBState == HIGH) {
matchScores[1]++;
updateOLED();
}
// Xử lý nút nhấn kết thúc trận đấu
if (btnEndState == LOW && lastBtnEndState == HIGH) {
endMatch();
}
// Lưu trạng thái nút hiện tại để so sánh ở lần lặp tiếp theo
lastBtnAState = btnAState;
lastBtnBState = btnBState;
lastBtnEndState = btnEndState;
// Hiển thị 7-seg: ghép score A và B thành 4 số
int displayNum = matchScores[0] * 100 + matchScores[1];
showNumber(displayNum);
//showNumber(1234); // for display test
}