В этом уроке мы создадим простую игру «Крестики-нолики» на базе Arduino UNO с использованием:
OLED SSD1306 (I2C):
Джойстик HW-504:

Перед компиляцией нужно установить:
Обе библиотеки устанавливаются через Arduino IDE:
Скетч → Подключить библиотеку → Управлять библиотеками…
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ---------- Настройки OLED ----------
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_ADDR 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// ---------- Джойстик ----------
#define JOY_X A0
#define JOY_Y A1
#define JOY_SW 2
int JOY_X_CENTER = 512, JOY_Y_CENTER = 512;
const int DEADZONE = 180; // «Мертвая зона», чтобы убрать дрожание джойстика
int cursorX = 0, cursorY = 0; // позиция курсора
char board[3][3]; // игровое поле
bool playerTurn = true; // true = X (игрок), false = O (второй игрок)
// ---------- Сброс игры ----------
void resetBoard() {
for (int y = 0; y < 3; y++) {
for (int x = 0; x < 3; x++) {
board[y][x] = ' ';
}
}
cursorX = 0;
cursorY = 0;
playerTurn = true;
}
// ---------- Рисуем поле ----------
void drawBoard() {
display.clearDisplay();
// сетка
display.drawLine(42, 0, 42, 64, WHITE);
display.drawLine(85, 0, 85, 64, WHITE);
display.drawLine(0, 21, 128, 21, WHITE);
display.drawLine(0, 43, 128, 43, WHITE);
// крестики и нолики
for (int y = 0; y < 3; y++) {
for (int x = 0; x < 3; x++) {
int cx = 21 + x * 43;
int cy = 11 + y * 21;
if (board[y][x] == 'X') {
display.drawLine(cx - 8, cy - 8, cx + 8, cy + 8, WHITE);
display.drawLine(cx - 8, cy + 8, cx + 8, cy - 8, WHITE);
} else if (board[y][x] == 'O') {
display.drawCircle(cx, cy, 9, WHITE);
}
}
}
// курсор (рамка)
int cx = cursorX * 43 + 1;
int cy = cursorY * 21 + 1;
display.drawRect(cx, cy, 40, 19, WHITE);
display.display();
}
// ---------- Проверка победы ----------
char checkWin() {
for (int i = 0; i < 3; i++) {
if (board[i][0] != ' ' &&
board[i][0] == board[i][1] &&
board[i][1] == board[i][2]) return board[i][0];
if (board[0][i] != ' ' &&
board[0][i] == board[1][i] &&
board[1][i] == board[2][i]) return board[0][i];
}
if (board[0][0] != ' ' &&
board[0][0] == board[1][1] &&
board[1][1] == board[2][2]) return board[0][0];
if (board[0][2] != ' ' &&
board[0][2] == board[1][1] &&
board[1][1] == board[2][0]) return board[0][2];
return ' ';
}
// ---------- Инициализация ----------
void setup() {
pinMode(JOY_SW, INPUT_PULLUP);
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
for (;;); // если дисплей не найден — зависаем
}
resetBoard();
drawBoard();
}
// ---------- Основной цикл ----------
void loop() {
int x = analogRead(JOY_X);
int y = analogRead(JOY_Y);
bool sw = !digitalRead(JOY_SW);
// движение по полю
if (x < JOY_X_CENTER - DEADZONE) { cursorX = max(0, cursorX - 1); delay(200); }
if (x > JOY_X_CENTER + DEADZONE) { cursorX = min(2, cursorX + 1); delay(200); }
if (y < JOY_Y_CENTER - DEADZONE) { cursorY = max(0, cursorY - 1); delay(200); }
if (y > JOY_Y_CENTER + DEADZONE) { cursorY = min(2, cursorY + 1); delay(200); }
// выбор клетки
if (sw) {
if (board[cursorY][cursorX] == ' ') {
board[cursorY][cursorX] = playerTurn ? 'X' : 'O';
playerTurn = !playerTurn;
}
delay(250);
}
// проверка победы
char winner = checkWin();
if (winner != ' ') {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(20, 25);
display.print(winner);
display.print(" wins!");
display.display();
delay(2000);
resetBoard();
}
drawBoard();
}
👉 В следующей части урока мы добавим режим игры против компьютера.