ESP32-C5 FireBeetle 2 搭建离线版的课堂交互网页
ESP32-C5FireBeetle 2 搭建离线版的课堂交互网页注:此文参考卓尔大佬的文章,谢谢!1.1 产品简介FireBeetle 2 ESP32-C5 IO套装包括两部分:Firebeetle 2 ESP32-C5 开发板和其专用的IO扩展底板。IO扩展板方便快速连接各种传感器外设,让Firebeetle 2 ESP32-C5开发板到手即用,无需焊接。FireBeetle 2 ESP32-C5 是一款搭载乐鑫 ESP32-C5 模组的低功耗 IoT 开发板,面向智能家居和广泛物联网场景,集高性能计算、多协议支持与智能电源管理于一体,为各种部署需求提供高可靠性、高灵活性与长续航的解决方案。支持 2.4 & 5 GHz 双频 Wi-Fi 6ESP32-C5 是乐鑫首款支持2.4 G和5 G 双频Wi-Fi 6的芯片。相较于 2.4GHz 频段,5GHz 具备更高传输速率、更低延迟及更少干扰特性,可提供更稳定、更低延迟的无线连接。同时,Wi-Fi 6 技术通过 OFDMA 频分复用 和目标唤醒时间(TWT,Target Wake Time) 机制,显著提升网络容量并降低设备功耗,延长电池使用时间,让设备长久续航。FireBeetle 2 ESP32-C5 凭借双频 Wi-Fi 6 支持,可满足智能家居、物联网等场景对高吞吐与低功耗的双重需求。多协议融合,扩展无线连接性开发板支持 Wi-Fi、Thread、BLE、Zigbee 协议,可构建 Matter Wi-Fi/Thread 终端设备,实现跨平台智能家居设备互联。结合外部 MCU,还可作为 Thread 边界路由器、Matter 网关 或 Zigbee 网桥,覆盖复杂场景需求。高效电源管理,部署更灵活FireBeetle 2 ESP32-C5提供了高效和易用的电源管理,为各种部署需求提供可靠、灵活的供电解决方案。[*]多元供电方式:支持 Type-C、5V DC 及太阳能输入对锂电池充电,解决无电源场景(如屋顶、阳台)的部署难题。
[*]太阳能优化PMIC(电源管理集成电路):采用太阳能电源管理模块 5V@1A同款太阳能电源管理芯片,最大限度的利用输入电源的电流输出能力,可最大化不同光照下的发电效率。
[*]智能监测与节能:集成电池电量监测功能,支持低电量预警;提供一组可控 3.3V 电源输出,可切断外接传感器供电以进一步降低功耗。
搭配专用IO扩展底板,无需焊接Firebeetle 2 ESP32-C5开发板推出专属的IO扩展板,其IO引脚全部引出,并且精心做了功能分区,方便直接快速连接各种传感器外设,真正让开发板做到了到手即用,无需焊接。2.1 打开arduino,配置环境环境配置参考:请点击下方链接查看添加板卡的详细步骤:https://wiki.dfrobot.com.cn/Add_ESP32_board_to_Arduino_IDE注意:仅esp32板卡环境 3.3.0-alpha1分支版本才支持ESP32-C5。2.2 输入代码#include <WiFi.h>
#include <WebServer.h>
// 手机热点配置(替换为您的热点SSID和密码)
const char* ssid = "jzai"; // 替换为手机热点的SSID
const char* password = "88998899"; // 替换为手机热点的密码
// 创建Web服务器对象,监听80端口(HTTP协议)
WebServer server(80);
// HTML内容(主题,保持与原代码一致)
const char* htmlContent = R"rawliteral(
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>打地鼠小游戏</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Arial Rounded MT Bold', 'Arial', sans-serif;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
padding: 20px;
}
.game-container {
width: 100%;
max-width: 600px;
background-color: rgba(255, 255, 255, 0.9);
border-radius: 20px;
padding: 25px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
text-align: center;
}
h1 {
color: #333;
margin-bottom: 20px;
font-size: 2.5rem;
text-shadow: 2px 2px 0 #ffcc00;
}
.game-info {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
font-size: 1.2rem;
font-weight: bold;
}
.score, .timer {
background-color: #ffcc00;
padding: 10px 20px;
border-radius: 10px;
box-shadow: 0 4px 0 #e6b800;
}
.game-board {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
margin-bottom: 25px;
}
.hole {
width: 100%;
aspect-ratio: 1;
background-color: #8B4513;
border-radius: 50%;
position: relative;
overflow: hidden;
box-shadow: inset 0 10px 0 rgba(0, 0, 0, 0.3);
cursor: pointer;
}
.mole {
width: 80%;
height: 80%;
background-color: #8B4513;
border-radius: 50%;
position: absolute;
bottom: -80%;
left: 10%;
transition: bottom 0.3s;
cursor: pointer;
}
.mole::before {
content: '';
position: absolute;
width: 40%;
height: 40%;
background-color: #333;
border-radius: 50%;
top: 20%;
left: 30%;
}
.mole::after {
content: '';
position: absolute;
width: 60%;
height: 30%;
background-color: #ff6666;
border-radius: 50%;
bottom: 10%;
left: 20%;
}
.mole.up {
bottom: 10%;
}
.controls {
margin-top: 20px;
}
button {
background-color: #4CAF50;
color: white;
border: none;
padding: 12px 30px;
font-size: 1.2rem;
border-radius: 10px;
cursor: pointer;
transition: all 0.3s;
box-shadow: 0 4px 0 #3d8b40;
}
button:hover {
background-color: #45a049;
transform: translateY(2px);
box-shadow: 0 2px 0 #3d8b40;
}
button:active {
transform: translateY(4px);
box-shadow: 0 0 0 #3d8b40;
}
.game-over {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
justify-content: center;
align-items: center;
z-index: 10;
}
.game-over-content {
background-color: white;
padding: 30px;
border-radius: 15px;
text-align: center;
max-width: 400px;
width: 90%;
}
.game-over h2 {
color: #ff3333;
margin-bottom: 20px;
font-size: 2rem;
}
.final-score {
font-size: 1.5rem;
margin-bottom: 20px;
}
@media (max-width: 500px) {
.game-board {
grid-template-columns: repeat(2, 1fr);
}
h1 {
font-size: 2rem;
}
}
</style>
</head>
<body>
<div class="game-container">
<h1>打地鼠小游戏</h1>
<div class="game-info">
<div class="score">得分: <span id="score">0</span></div>
<div class="timer">时间: <span id="time">30</span>秒</div>
</div>
<div class="game-board" id="gameBoard">
<!-- 地鼠洞将通过JavaScript生成 -->
</div>
<div class="controls">
<button id="startBtn">开始游戏</button>
</div>
</div>
<div class="game-over" id="gameOver">
<div class="game-over-content">
<h2>游戏结束!</h2>
<p class="final-score">你的得分: <span id="finalScore">0</span></p>
<button id="restartBtn">再玩一次</button>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 游戏元素
const gameBoard = document.getElementById('gameBoard');
const scoreDisplay = document.getElementById('score');
const timeDisplay = document.getElementById('time');
const startBtn = document.getElementById('startBtn');
const gameOverScreen = document.getElementById('gameOver');
const finalScoreDisplay = document.getElementById('finalScore');
const restartBtn = document.getElementById('restartBtn');
// 游戏变量
let score = 0;
let timeLeft = 30;
let gameActive = false;
let timer;
let moleTimer;
// 创建地鼠洞
for (let i = 0; i < 9; i++) {
const hole = document.createElement('div');
hole.className = 'hole';
const mole = document.createElement('div');
mole.className = 'mole';
mole.dataset.id = i;
hole.appendChild(mole);
gameBoard.appendChild(hole);
// 添加点击事件
mole.addEventListener('click', hitMole);
}
const moles = document.querySelectorAll('.mole');
// 开始游戏
startBtn.addEventListener('click', startGame);
// 重新开始游戏
restartBtn.addEventListener('click', function() {
gameOverScreen.style.display = 'none';
startGame();
});
function startGame() {
// 重置游戏状态
score = 0;
timeLeft = 30;
gameActive = true;
scoreDisplay.textContent = score;
timeDisplay.textContent = timeLeft;
startBtn.disabled = true;
// 清除所有活动的地鼠
moles.forEach(mole => {
mole.classList.remove('up');
});
// 开始计时
timer = setInterval(function() {
timeLeft--;
timeDisplay.textContent = timeLeft;
if (timeLeft <= 0) {
endGame();
}
}, 1000);
// 开始地鼠出现
showRandomMole();
}
function showRandomMole() {
if (!gameActive) return;
// 随机选择一个地鼠
const randomIndex = Math.floor(Math.random() * moles.length);
const mole = moles;
// 显示地鼠
mole.classList.add('up');
// 设置地鼠消失的时间(0.5-2秒之间随机)
const hideTime = Math.random() * 1500 + 500;
setTimeout(() => {
mole.classList.remove('up');
// 如果游戏还在进行中,继续显示下一个地鼠
if (gameActive) {
showRandomMole();
}
}, hideTime);
}
function hitMole(e) {
if (!gameActive) return;
// 确保点击的是地鼠而不是洞
if (e.target.classList.contains('up')) {
// 增加分数
score++;
scoreDisplay.textContent = score;
// 播放点击效果
e.target.style.backgroundColor = '#ff3333';
setTimeout(() => {
e.target.style.backgroundColor = '#8B4513';
}, 200);
// 立即隐藏被点击的地鼠
e.target.classList.remove('up');
}
}
function endGame() {
gameActive = false;
clearInterval(timer);
startBtn.disabled = false;
// 显示游戏结束画面
finalScoreDisplay.textContent = score;
gameOverScreen.style.display = 'flex';
}
});
</script>
</body>
</html>
)rawliteral";
void handleRoot() {
// 发送HTTP响应,状态码200,内容类型为text/html
server.send(200, "text/html", htmlContent);
}
void setup() {
// 初始化串口,用于调试
Serial.begin(115200);
Serial.println("Starting ESP32-C5 Web Server...");
// 设置ESP32为STA模式,连接手机热点
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi: ");
Serial.println(ssid);
// 等待连接,最多尝试20秒
int timeout = 20;
while (WiFi.status() != WL_CONNECTED && timeout > 0) {
delay(1000);
Serial.print(".");
timeout--;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi Connected");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP()); // 打印STA模式的IP地址
} else {
Serial.println("\nFailed to connect to WiFi. Check SSID/password or signal strength.");
return; // 连接失败,停止后续操作
}
// 设置Web服务器路由
server.on("/", handleRoot);
server.onNotFound([]() {
server.send(404, "text/plain", "404: Page Not Found");
});
// 启动服务器
server.begin();
Serial.println("HTTP Server Started");
}
void loop() {
// 处理客户端HTTP请求
server.handleClient();
delay(10); // 短暂延时以确保稳定性
}3.1 查看效果无论是电脑还是手机只要接入同一个热点网络,那么它就可以通过查看串口监视中的IP进行连接游玩。https://lsky.555555.press:16666/i/2025/10/25/68fc26e750afd.pnghttps://lsky.555555.press:16666/i/2025/10/25/68fc26949d835.png4 接下来的方向我觉得可以搭建一个离线的小型服务器,这样学生的数据可以收集起来,方便老师统计。比如学生的答题,只要学生提交数据,老师这边就可以得到学生反馈。这有点类似学习平板的同步反馈。或者做个本地游戏。多人竞技游戏,支持2-4个玩家同时游戏,每个玩家连接自己的设备,实时显示玩家排名。这应该也是一个不错的方法。
页:
[1]