ESP8266—01S_联网五子棋创作

在嵌入式开发领域,WiFi 技术的应用越来越广泛,而 ESP8266 正是一款强大且易于使用的 WiFi 模块。它不仅价格亲民,而且功能丰富,能够轻松实现设备联网、数据传输以及远程控制等功能。无论是物联网(IoT)项目、智能家居,还是创意小玩意儿,ESP8266 都能为你提供强大的支持。

本教程是我基于ESP8266实现的简单Web服务器,并通过浏览器与其交互。这个项目不仅展示了 ESP8266 的联网能力,还结合了 HTML、CSS 和 JavaScript 等前端技术,实现简易的嵌入式开发与Web开发的结合。

一、硬件需求

1.ESP-01S模块

ESP-01S 是一款性价比极高的 WiFi 模块,基于 ESP8266 芯片,内置 Tensilica L106 32 位微处理器,主频可达 80 MHz,甚至可超频至 160 MHz。它支持 802.11 b/g/n 协议,能够轻松连接到家庭或办公室的 WiFi 网络,提供稳定的无线通信能力。

ESP-01S 支持多种开发环境,包括 Arduino IDENodeMCU 和 MicroPython,开发者可以根据自己的喜好选择合适的工具。此外,ESP-01S 拥有强大的社区支持,网上有大量的开源项目、教程和解决方案,帮助开发者快速上手和解决问题。

ESP-01S 支持多种低功耗模式,包括 Modem-sleep 和 Deep-sleep,非常适合电池供电的物联网设备。通过合理配置低功耗模式,可以显著延长设备的续航时间,满足远程传感器、智能家居等场景的需求。

 引脚图及接线如下:

脚序名称功能
1GND接地即可
2IO2GPIO2/UART1_TXD
3IO0GPIO0,外部拉高即为下载模式;悬空或外部拉高即为运行模式
4RXUART0_RXD/GPIO3
5TXUART0_TXD/GPIO1
6EN芯片使能,高电平有效
7RST复位引脚
83V33.3V供电;外部供电电源输出电流建议在500mA以上

 2.USB转TTL模块

将 USB 转 TTL 模块 (CH340C)与 ESP-01S 的对应引脚相连(注意:TX 接 RX,RX 接 TX,千万不要接反!供电电压为 3.3V,切勿接成 5V,否则可能损坏模块)。连接完成后,即可实现电脑与 ESP-01S 的通信,并完成代码的烧写。

、软件需求

编辑与下载代码可以使用 Arduino IDE 完成。我使用的是 2.3.4 版本,只要是 1.8 版本以上 的 Arduino IDE 均可支持。

1.下载 Arduino IDE

访问 Arduino 官网:Software | Arduino。在下图指定位置选择适合你操作系统的版本(我使用的是 Windows 版本)。

2.配置 Arduino IDE

打开 Arduino IDE,点击 文件 -> 首选项,在 附加开发板管理器网址 中添加以下链接:

http://arduino.esp8266.com/stable/package_esp8266com_index.json

点击 工具 -> 开发板 -> 开发板管理器,搜索 esp8266 并安装最新版本。

点击 工具 -> 开发板,选择 Generic ESP8266 Module

接下来配置工具栏内的内容,跟着下图我配置好的内容更改即可。

其中的port指的是端口,这跟据你的USB转TTL模块接的电脑哪个端口而定,具体可以打开电脑的设备管理器查找对应端口。我电脑上连的是COM3,如下图。

三、代码内容 

1.引入库与宏定义

引入ESP8266 WiFi库,用于实现WiFi连接和网络通信;定义GPIO0引脚,用于烧录模式控制。

#include <ESP8266WiFi.h>
#define RELAY 0 

2.WIFI配置

配置与你电脑现在连接的同一个WiFi,并创建一个TC 服务器,监听 80 端口(HTTP默认端口)。记得将代码中111改成WiFi名称,将222改成该WiFi的密码。

const char *ssid = "111";    
const char *password = "222";  
WiFiServer server(80); 

3.setup( )函数

初始化串口通信后,配置 GPIO0 为输出模式并置高电平,接着连接 WiFi 并在连接过程中打印状态,连接成功后启动 TCP 服务器并打印本地 IP 地址。

void setup()
{
    Serial.begin(115200);
    pinMode(RELAY, OUTPUT);    // Set GPIO0 to output mode.
    digitalWrite(RELAY, HIGH); // Set the GPIO0 output level to high.

    /* Connect to the WiFi network. */
    Serial.println("");
    Serial.print("Connecting to ");
    Serial.println(ssid);
    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {     // If the connection to WiFi fails, retry every 500 milliseconds.
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected.");

    /* Start the Server. */
    server.begin();
    Serial.println("Server started.");

    /* Output of the IP address. */
    Serial.print("Use this URL to connect: ");
    Serial.print("http://");
    Serial.print(WiFi.localIP());
    Serial.println("/");
}

4.loop( )函数

检查客户端连接,等待并读取其发送的 HTTP 请求首行,然后清空缓冲区以备后续通信。

void loop()
{
    /* Check whether a user has established a connection. */
    WiFiClient client = server.available();
    if (!client)
        return;

    /* Wait until the user sends data. */
    Serial.println("new client.");
    while (!client.available())
        delay(1);

    /* Reading the first line of the request. */
    String request = client.readStringUntil('\r');
    Serial.println(request);
    client.flush();

5.生成并返回 HTML 页面

返回HTTP成功响应,生成带15x15棋盘的 HTML 页面,定义样式并通过 onclick 实现落子功能。

    /* Return the answer. */
    client.println("HTTP/1.1 200 OK");
    client.println("Content-Type: text/html");
    client.println("");
    client.println("<!DOCTYPE HTML>");
    client.println("<html>");
    client.println("<meta charset='UTF-8'>"); // 添加字符编码声明
    client.println("<meta name='viewport' content='width=device-width, initial-scale=1'>");
    client.println("<head><title>ESP8266 五子棋游戏</title></head>");
    client.println("<style>");
    client.println("* { margin: 0; padding: 0; box-sizing: border-box; }");
    client.println("body { font-family: 'Arial', sans-serif; background-color: #f0f0f0; color: #333; display: flex; justify-content: center; align-items: center; height: 100vh; }");
    client.println(".container { text-align: center; }");
    client.println(".board { display: grid; grid-template-columns: repeat(15, 30px); grid-template-rows: repeat(15, 30px); gap: 1px; margin: 20px auto; }");
    client.println(".cell { width: 30px; height: 30px; background-color: #fff; border: 1px solid #ccc; display: flex; justify-content: center; align-items: center; cursor: pointer; }");
    client.println(".cell.black { background-color: #000; }");
    client.println(".cell.white { background-color: #fff; border: 1px solid #000; }");
    client.println(".title { font-size: 2rem; margin-bottom: 20px; }");
    client.println(".button { display: inline-block; padding: 10px 20px; font-size: 1rem; color: #fff; background-color: #333; text-decoration: none; border-radius: 5px; transition: all 0.3s ease; }");
    client.println(".button:hover { background-color: #555; }");
    client.println(".footer { margin-top: 30px; font-size: 1rem; }");
    client.println(".footer .bold-text { font-weight: bold; }");
    client.println(".message { font-size: 1.5rem; margin: 20px 0; color: red; }");
    client.println("</style>");
    client.println("<body>");
    client.println("<div class='container'>");
    client.println("<div class='title'>Eddie Wang五子棋</div>");
    client.println("<div class='message' id='message'></div>");
    client.println("<div class='board'>");
    for (int i = 0; i < 15; i++) {
        for (int j = 0; j < 15; j++) {
            client.println("<div class='cell' id='cell_" + String(i) + "_" + String(j) + "' onclick='makeMove(" + String(i) + ", " + String(j) + ")'></div>");
        }
    }
    client.println("</div>");
    client.println("<a href=\"/RESET\" class='button'>重置游戏</a>");
    client.println("<div class='footer'>");
    client.println("<p>Created by <span class='bold-text'>Eddie Wang</span>.</p>");
    client.println("</div>");
    client.println("</div>");
    client.println("</body>");
    client.println("</html>");
    client.println("");
}

6.JavaScript逻辑 

处理玩家落子逻辑,切换玩家并检查是否形成五子连珠以判定胜利。

let currentPlayer = 'black';
let gameOver = false;
const boardSize = 15;
const board = Array.from({ length: boardSize }, () => Array(boardSize).fill(null));

function makeMove(row, col) {
    if (gameOver || board[row][col]) return;
    const cell = document.getElementById('cell_' + row + '_' + col);
    cell.classList.add(currentPlayer);
    board[row][col] = currentPlayer;
    if (checkWin(row, col)) {
        document.getElementById('message').innerText = `玩家 ${currentPlayer.toUpperCase()} 胜利!`;
        gameOver = true;
        return;
    }
    currentPlayer = currentPlayer === 'black' ? 'white' : 'black';
}

function checkWin(row, col) {
    const directions = [
        [1, 0],  // 水平
        [0, 1],  // 垂直
        [1, 1],  // 对角线(右下)
        [1, -1]  // 对角线(左下)
    ];
    for (const [dx, dy] of directions) {
        let count = 1;
        for (let i = 1; i <= 4; i++) {
            const x = row + dx * i;
            const y = col + dy * i;
            if (x < 0 || x >= boardSize || y < 0 || y >= boardSize || board[x][y] !== currentPlayer) break;
            count++;
        }
        for (let i = 1; i <= 4; i++) {
            const x = row - dx * i;
            const y = col - dy * i;
            if (x < 0 || x >= boardSize || y < 0 || y >= boardSize || board[x][y] !== currentPlayer) break;
            count++;
        }
        if (count >= 5) return true;
    }
    return false;
}

7.完整代码

#include <ESP8266WiFi.h>
#define RELAY 0 

const char *ssid = "111";    
const char *password = "222";   

WiFiServer server(80);

void setup()
{
    Serial.begin(115200);
    pinMode(RELAY, OUTPUT);    // Set GPIO0 to output mode.
    digitalWrite(RELAY, HIGH); // Set the GPIO0 output level to high.

    /* Connect to the WiFi network. */
    Serial.println("");
    Serial.print("Connecting to ");
    Serial.println(ssid);
    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {     // If the connection to WiFi fails, retry every 500 milliseconds.
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected.");

    /* Start the Server. */
    server.begin();
    Serial.println("Server started.");

    /* Output of the IP address. */
    Serial.print("Use this URL to connect: ");
    Serial.print("http://");
    Serial.print(WiFi.localIP());
    Serial.println("/");
}

void loop()
{
    /* Check whether a user has established a connection. */
    WiFiClient client = server.available();
    if (!client)
        return;

    /* Wait until the user sends data. */
    Serial.println("new client.");
    while (!client.available())
        delay(1);

    /* Reading the first line of the request. */
    String request = client.readStringUntil('\r');
    Serial.println(request);
    client.flush();

    /* Return the answer. */
    client.println("HTTP/1.1 200 OK");
    client.println("Content-Type: text/html");
    client.println("");
    client.println("<!DOCTYPE HTML>");
    client.println("<html>");
    client.println("<meta charset='UTF-8'>"); // 添加字符编码声明
    client.println("<meta name='viewport' content='width=device-width, initial-scale=1'>");
    client.println("<head><title>ESP8266 五子棋</title></head>");
    client.println("<style>");
    client.println("* { margin: 0; padding: 0; box-sizing: border-box; }");
    client.println("body { font-family: 'Arial', sans-serif; background-color: #f0f0f0; color: #333; display: flex; justify-content: center; align-items: center; height: 100vh; }");
    client.println(".container { text-align: center; }");
    client.println(".board { display: grid; grid-template-columns: repeat(15, 30px); grid-template-rows: repeat(15, 30px); gap: 1px; margin: 20px auto; }");
    client.println(".cell { width: 30px; height: 30px; background-color: #fff; border: 1px solid #ccc; display: flex; justify-content: center; align-items: center; cursor: pointer; }");
    client.println(".cell.black { background-color: #000; }");
    client.println(".cell.white { background-color: #fff; border: 1px solid #000; }");
    client.println(".title { font-size: 2rem; margin-bottom: 20px; }");
    client.println(".button { display: inline-block; padding: 10px 20px; font-size: 1rem; color: #fff; background-color: #333; text-decoration: none; border-radius: 5px; transition: all 0.3s ease; }");
    client.println(".button:hover { background-color: #555; }");
    client.println(".footer { margin-top: 30px; font-size: 1rem; }");
    client.println(".footer .bold-text { font-weight: bold; }");
    client.println(".message { font-size: 1.5rem; margin: 20px 0; color: red; }");
    client.println("</style>");
    client.println("<body>");
    client.println("<div class='container'>");
    client.println("<div class='title'>Eddie Wang五子棋</div>");
    client.println("<div class='message' id='message'></div>");
    client.println("<div class='board'>");
    for (int i = 0; i < 15; i++) {
        for (int j = 0; j < 15; j++) {
            client.println("<div class='cell' id='cell_" + String(i) + "_" + String(j) + "' onclick='makeMove(" + String(i) + ", " + String(j) + ")'></div>");
        }
    }
    client.println("</div>");
    client.println("<a href=\"/RESET\" class='button'>重置游戏</a>");
    client.println("<div class='footer'>");
    client.println("<p>Created by <span class='bold-text'>Eddie Wang</span>.</p>");
    client.println("</div>");
    client.println("</div>");
    client.println("<script>");
    client.println("let currentPlayer = 'black';");
    client.println("let gameOver = false;");
    client.println("const boardSize = 15;");
    client.println("const board = Array.from({ length: boardSize }, () => Array(boardSize).fill(null));");
    client.println("function makeMove(row, col) {");
    client.println("    if (gameOver || board[row][col]) return;");
    client.println("    const cell = document.getElementById('cell_' + row + '_' + col);");
    client.println("    cell.classList.add(currentPlayer);");
    client.println("    board[row][col] = currentPlayer;");
    client.println("    if (checkWin(row, col)) {");
    client.println("        document.getElementById('message').innerText = `玩家 ${currentPlayer.toUpperCase()} 胜利!`;");
    client.println("        gameOver = true;");
    client.println("        return;");
    client.println("    }");
    client.println("    currentPlayer = currentPlayer === 'black' ? 'white' : 'black';");
    client.println("}");
    client.println("function checkWin(row, col) {");
    client.println("    const directions = [");
    client.println("        [1, 0],  // 水平");
    client.println("        [0, 1],  // 垂直");
    client.println("        [1, 1],  // 对角线(右下)");
    client.println("        [1, -1]  // 对角线(左下)");
    client.println("    ];");
    client.println("    for (const [dx, dy] of directions) {");
    client.println("        let count = 1;");
    client.println("        for (let i = 1; i <= 4; i++) {");
    client.println("            const x = row + dx * i;");
    client.println("            const y = col + dy * i;");
    client.println("            if (x < 0 || x >= boardSize || y < 0 || y >= boardSize || board[x][y] !== currentPlayer) break;");
    client.println("            count++;");
    client.println("        }");
    client.println("        for (let i = 1; i <= 4; i++) {");
    client.println("            const x = row - dx * i;");
    client.println("            const y = col - dy * i;");
    client.println("            if (x < 0 || x >= boardSize || y < 0 || y >= boardSize || board[x][y] !== currentPlayer) break;");
    client.println("            count++;");
    client.println("        }");
    client.println("        if (count >= 5) return true;");
    client.println("    }");
    client.println("    return false;");
    client.println("}");
    client.println("</script>");
    client.println("</body>");
    client.println("</html>");
    client.println("");
}

四、硬件配置与烧录

1.引脚具体接线

ESP-01S引脚接线去处
3V33.3V
RST不接即可
EN3.3V
TXTTL上的RXD
RXTTL上的TXD
IO0GND
IO2不接即可
GNDGND

我的实物接线如下图。其中我3V3借助STM32F103系统板来供电。 

2. 烧录

确保接入电脑,电脑端口识别到CH340了后,即可点击烧录。

 烧录结束后的输出提示,代表烧录完成。

接下来,打开 Arduino IDE 的串口监视器(Serial Monitor),这一步至关重要!!!

确保所有引脚连接稳固,没有松动或断开。然后,将 ESP-01S 上连接 IO0 的杜邦线拔下,并快速插入 RST 引脚后立即拔出(即对 ESP-01S 进行复位操作)。此时,仔细观察串口监视器的输出,最后一行显示的网址即为 ESP-01S 的 IP 地址,通过该地址即可在浏览器中访问五子棋游戏页面。

下图为复位后串口监视器发出的消息,方框即为IP地址。

只要确保手机或电脑与ESP01S连接的是同一个WIFI就可通过浏览器访问该IP地址,进入五子棋页面。下图是电脑浏览器进入的界面。

还有手机进入的界面以及操作视频。 每次操作落子,串口监视器都会有消息接收。

Eddie66

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值