310浏览
查看: 310|回复: 0

[入门教程] Arduino入门教程20--反应速度测试「DFR0100」

[复制链接]
本帖最后由 zoey不种土豆 于 2024-11-21 20:30 编辑

在这个项目中我们将用Arduino制作一个反应速度测试游戏。通过点亮LED灯并快速按下对应按钮来得分,游戏持续一分钟。准备挑战你的反应极限了吗?让我们开始吧!

元件清单
Arduino入门教程20--反应速度测试「DFR0100」图1

硬件连接
在这个项目中,我们使用到的LED灯和按键模块,都是在之前的项目中出现过的。不同的一点是之前项目【交通信号灯】中给按键外加了一个下拉电阻,在这个项目中,我们使用Arduino芯片内部的上拉电阻,详见本项目的硬件回顾。请按照下图将硬件连接正确。
Arduino入门教程20--反应速度测试「DFR0100」图2
1 反应速度测试连线图
示例代码
样例代码:
  1. //项目 - 反应速度测试
  2. // 定义LED灯和按钮的引脚
  3. const int LEDS[] = {3, 5, 7};
  4. const int BUTTONS[] = {2, 4, 6};
  5. int score = 0; // 玩家的得分
  6. bool gameStarted = false; // 游戏是否开始的标志
  7. unsigned long gameStartTime; // 记录游戏开始的时间戳
  8. const unsigned long gameDuration = 60000;
  9. // 游戏持续时间,单位为毫秒(1分钟)
  10. void setup() {
  11.   Serial.begin(9600); // 初始串口通信
  12.   // 设置LED灯和按钮的引脚模式
  13.   for (int i = 0; i < 3; i++) {
  14.     pinMode(LEDS[i], OUTPUT);
  15.     pinMode(BUTTONS[i], INPUT_PULLUP);
  16.   }
  17. }
  18. void loop() {
  19.   // 检查是否同时按下了所有三个按钮来开始游戏
  20.   if (!gameStarted && digitalRead(BUTTONS[0]) == LOW && digitalRead(BUTTONS[1]) == LOW && digitalRead(BUTTONS[2]) == LOW) {
  21.     Serial.println("游戏开始");
  22.     gameStarted = true;
  23.     score = 0; // 重置得分
  24.     gameStartTime = millis(); // 记录游戏开始的时间
  25.     delay(1000); // 等待一秒后开始游戏
  26.   }
  27.   // 如果游戏已经开始,检查游戏是否超时
  28.   if (gameStarted && millis() - gameStartTime < gameDuration) {
  29.     int led = random(0, 3); // 随机选择一个LED
  30.     digitalWrite(LEDS[led], HIGH); // 点亮这个LED
  31.     long startTime = millis(); // 记录点亮LED的时间
  32.     bool buttonPressed = false; // 初始化按钮状态(未被按下)
  33.    
  34.     // 给玩家一定时间来按按钮
  35.     while (millis() - startTime < 1000) {
  36.       if (digitalRead(BUTTONS[led]) == LOW) {
  37. // 检查是否按下了对应的按钮
  38.         buttonPressed = true;
  39.         break; // 如果按下了按钮,跳出循环
  40.       }
  41.     }
  42.     digitalWrite(LEDS[led], LOW); // 熄灭LED
  43.     if (buttonPressed) {
  44.       score++; // 如果按下了按钮,增加得分
  45.       Serial.println("得分 +1");
  46.     }
  47.     delay(200); // 等待一段时间再继续下一轮
  48.   } else if (gameStarted) {
  49.     // 如果游戏时间超过一分钟或玩家没有在时间内按下按钮,游戏结束
  50.     gameStarted = false;
  51.     Serial.print("游戏结束! 你的得分: ");
  52.     Serial.println(score); // 通过串口输出得分
  53.     delay(3000); // 等待3秒后可以重新开始游戏
  54.   }
  55. }
复制代码
上传代码后,打开串口监视器,同时按下三个按键开始游戏,串口监视器上出现游戏开始字样。一旦游戏开始,系统将随机点亮一个LED灯,并给玩家一秒钟的时间来按下对应的按钮,便可获得1分。当游戏时间到达1分钟时,串口监视器出现游戏结束并告知你的游戏得分。
代码回顾
变量声明部分不做过多解释了,这个部分用于定义LED和按钮的引脚数组,以及用于跟踪得分、游戏状态和游戏时间的变量。
  1. const int LEDS[] = {3, 5, 7};
  2. const int BUTTONS[] = {2, 4, 6};
  3. int score = 0;
  4. bool gameStarted = false;
  5. unsigned long gameStartTime;
  6. const unsigned long gameDuration = 60000;
复制代码
gameDuration是一个非负长整型的常数,用于定义游戏的持续时间。在这里,它被设置为60000毫秒,即1分钟,以确保游戏持续一分钟。
在setup()函数中,初始化串口通信,并使用一个for循环设置LED和按钮的引脚模式。
在loop()函数中,流程如下:
  1. // 游戏开始前的检查  
  2.   if (!gameStarted && digitalRead(BUTTONS[0]) == LOW && digitalRead(BUTTONS[1]) == LOW && digitalRead(BUTTONS[2]) == LOW
  3. ) {  
  4. // 游戏初始化
  5. gameStarted = true;
  6.   }  
  7.   
  8. // 游戏被激活后  
  9.   if (gameStarted && millis() - gameStartTime < gameDuration) {  
  10.     // 游戏进行中
  11.   } else if (gameStarted) {  
  12.     // 游戏结束
  13.   }
  14. // 返回游戏开始前的检查
复制代码
如果用流程图,表示如下:
Arduino入门教程20--反应速度测试「DFR0100」图3
第一个部分是游戏开始前的检查。
用来判断游戏是否被激活,激活指的是从游戏的非激活状态(即未开始也未在进行中)转换到准备开始的状态。
  1. if (!gameStarted && digitalRead(BUTTONS[0]) == LOW && digitalRead(BUTTONS[1]) == LOW && digitalRead(BUTTONS[2]) == LOW)
复制代码
所以在第一个判断中,既要判断三个按键是否被同时按下,又要判断当时游戏是否处于未激活状态。
游戏被激活后进行游戏的初始化:
  1. Serial.println("游戏开始");
  2.     gameStarted = true;
  3.     score = 0; // 重置得分
  4.     gameStartTime = millis(); // 记录游戏开始的时间
  5.     delay(1000); // 等待一秒后开始游戏
复制代码
通过串口输出“游戏开始”,将gameStarted设置为true以标记游戏已经开始,重置得分score为0,记录游戏开始的时间gameStartTime为当前毫秒数(使用millis()函数获取),然后暂停1秒以给用户一个视觉或心理上的准备时间。
第二部分是游戏激活后的逻辑结构。
  1. if(gameStarted && millis() - gameStartTime < gameDuration) {  
  2.     // 游戏进行中
  3.   } else if (gameStarted) {  
  4.     // 游戏结束  
  5.   }
复制代码
当游戏已经开始且游戏时间未超过设定的持续时间gameDuration时,执行游戏进行中的逻辑。如果游戏已经开始但游戏时间超过了设定的持续时间gameDuration,执行游戏结束的逻辑。接下来是对于游戏进行中的逻辑和游戏结束的逻辑的详解。

游戏进行中:
一旦游戏开始,系统将随机点亮一个LED灯,并给玩家一秒钟的时间来按下对应的按钮。
  1. int led = random(0, 3); // 随机选择一个LED
  2. digitalWrite(LEDS[led], HIGH); // 点亮这个LED
  3. long startTime = millis();
  4. bool buttonPressed = false;  // 初始化按钮状态(未被按下)
复制代码
同时记录下点亮LED的时间startTime,并且把buttonpressed的状态设为fasle(初始化),之后进入一个while循环,等待玩家在1秒内按下对应的按钮。
  1. while (millis() - startTime < 1000) {
  2.       if (digitalRead(BUTTONS[led]) == LOW) {
  3. // 检查是否按下了对应的按钮
  4.         buttonPressed = true;
  5.         break; // 如果按下了按钮,跳出循环
  6.       }
复制代码
如果玩家在1秒内按下了对应的按钮(通过检查BUTTONS[led]是否被按下),则标记buttonPressed为true并跳出循环。
while循环结束后,无论是否按下了按钮,都会熄灭LED。
  1. if (buttonPressed) {
  2.       score++; // 如果按下了按钮,增加得分
  3.       Serial.println("得分 +1");
  4.     }
  5.     delay(200);
复制代码
如果buttonPressed为true,则增加得分并输出得分增加的消息。
最后,使用delay(200)等待200毫秒后继续下一轮游戏。

游戏结束:
  1. else if (gameStarted) {
  2.     // 如果游戏时间超过一分钟,游戏结束
  3.     gameStarted = false;
  4.     Serial.print("游戏结束! 你的得分: ");
  5.     Serial.println(score); // 通过串口输出得分
  6.     delay(3000); // 等待3秒后可以重新开始游戏
  7.   }
复制代码
否则如果游戏已经开始但游戏时间超过了设定的持续时间gameDuration,则执行游戏结束的逻辑。
将gameStarted设置为false以标记游戏结束,通过串口输出游戏结束的消息和玩家的最终得分,然后暂停3秒,给用户一个重新开始游戏前的缓冲时间。

硬件回顾
上拉电阻
通常,如果没有输入,将输入引脚引导至已知状态非常有用。这可以通过在输入端添加一个上拉电阻(至+5V)或一个下拉电阻(接地电阻)来实现。这个项目中使用的按键,由于没有内置上拉电阻,则需要在代码中设置引脚为INPUT_PULLUP或使用外部电阻。
Arduino的ATmega 芯片内置了 20K 上拉电阻器,可通过软件访问。这些内置上拉电阻可通过将 pinMode() 设置为 INPUT_PULLUP 来访问。这有效地反转了 INPUT 模式的行为,其中 HIGH 表示传感器关闭,LOW 表示传感器打开。

课后练习
尝试用现有的硬件,做一个颜色记忆游戏,实现一个简化版的记忆翻牌游戏,使用两个LED(代表两张牌)和一个按钮。游戏开始时,两个LED随机亮起(模拟翻牌),然后熄灭。玩家需要记住这两个LED的亮起状态,并通过按钮输入来“翻牌”(实际上是重新点亮LED),尝试匹配之前的亮起状态。根据结果配合串口输出“恭喜,你赢了!”;否则,输出“很遗憾,你输了!”。还有更多的玩法等待着你发现。
示例代码

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail