数学对于很多人来说可能像魔法一样神奇,但对另一些人来说却可能显得枯燥无味。因此,打算使用Arduino来改变一些人对数学的看法,通过制作一个小游戏来实现这一点。这个游戏将包含一系列从0到9的数字,所有数字都会显示在屏幕上。玩家需要快速地将这些数字相加。在数字显示后,玩家将使用按钮输入答案。有两个按钮,一个用于输入答案,另一个用于提交答案。当按下第一个按钮时,答案中的数字将增加1。玩家必须按下第一个按钮以得到正确的数字作为答案,并依次提交这些数字。如果答案正确/错误,绿色/红色LED灯将会亮起。数字的数量和每个数字显示的持续时间都可以在代码中调整。
例如:屏幕将显示一系列10个随机数字,每个数字显示1秒钟:5, 6, 1, 3, 7, 8, 9, 1, 2, 4。如果玩家按下46,绿色LED灯将会亮起。如果不是,红色LED灯将会亮起,因为本系列数字的正确答案是46(5 + 6 + 1 + 3 + 7 + 8 + 9 + 1 + 2 + 4 = 46)。玩家需要按下第一个按钮得到数字4,然后按下提交按钮,然后玩家需要按下那个按钮得到数字6,然后按下提交按钮。他就会赢。
需要一些容易找到且便宜的组件,如下所示:
在开始之前,想让一些初学者对这种显示器有一个清晰的认识。7段显示器有两种类型,但它们并不是太不同。让看看下面的插图。首先,会发现它们彼此相似。事实上,它们各自有不同的使用方式。
7段显示器/LED有两种类型:
为了清楚起见,准备了一个简短的代码来测试显示器是公共阴极还是公共阳极。以下是测试代码的摘录。
#define sA 7
#define sB 6
#define sC 11
#define sD 12
#define sE 13
#define sF 8
#define sG 9
#define DP 10
int number = 0;
void setup() {
for(int i = 4; i <= 13; i++) {
pinMode(i, OUTPUT);
}
Serial.begin(9600);
}
void loop() {
number = (number + 1) % 10;
displayNum(number);
if(number % 2 == 0) {
digitalWrite(DP, 1);
} else {
digitalWrite(DP, 0);
}
delay(1000);
}
void displayNum(int num) {
clearAll();
switch(num) {
case 0:
digitalWrite(sA, 1);
digitalWrite(sB, 1);
digitalWrite(sC, 1);
digitalWrite(sD, 1);
digitalWrite(sE, 1);
digitalWrite(sF, 1);
break;
case 1:
digitalWrite(sB, 1);
digitalWrite(sC, 1);
break;
// ... 更多的case
}
}
可以在这里下载完整的源代码。它显示从0到9的数字。显示器是公共阴极,所以如果这个代码不适用于显示器,请将代码中的LED打开行改为关闭,反之亦然。下面的图片是代码的电路图。
在这个项目中,使用中断来处理两个按钮,以使程序更加整洁。中断是系统生成事件时自动调用的函数。这些事件由微控制器制造商使用硬件设置,并在软件中使用固定名称进行配置。由于中断是独立且在配置时自行生成的,主程序将更简单。中断的一个典型例子是millis()函数。这个函数随着程序的运行自动运行,并返回随时间递增的数字,尽管没有安装它。millis()函数的设置用于中断,并在Arduino程序代码中自动配置。
中断使程序更加整洁和快速。例如,当检查按钮是否被按下时,通常需要在loop()程序中使用digitalRead()函数来检查按钮状态。使用中断时,只需将按钮连接到支持中断的正确引脚,然后中断设置将在开关状态从LOW变为HIGH或反之亦定时生成。添加一个函数名来调用生成中断时。也就是说,中断程序中的变量将告诉按钮的状态。
中断引脚的数量取决于每个微控制器。ArduinoUno只有2个中断引脚,Mega 2560有6个中断引脚,Leonardo有5个中断引脚。在这里了解更多。
完成这个简单的电路,开始编程。可能需要消抖按钮。
不会再次提到显示功能,因为可以在上面的部分找到它。
找出中断引脚
当玩家按下按钮时,inputNum()和submit()函数将被调用。使用RISING,因为只在按下时调用这些函数一次。按下输入按钮时,将调用inputNum()函数,将变量增加1。将在下一个代码中解释提交答案时会发生什么。
void setup() {
pinMode(INPUT_BUTTON, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(INPUT_BUTTON), inputNum, RISING);
pinMode(SUBMIT_BUTTON, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(SUBMIT_BUTTON), submit, RISING);
Serial.begin(9600);
}
//此函数在按下输入按钮时将当前数字增加1
void inputNum() {
if(gameStatus == 2) {
currentNum = (currentNum + 1) % 10;
//确保数字在0到9的范围内
}
}
void submit() {
if(gameStatus == 2) {
String temp = String(currentNum);
answer += temp;
if(answer.length() - 1 == sResult.length()) {
if(answer == sResult) {
digitalWrite(GREEN_LED, 1);
delay(1000);
digitalWrite(GREEN_LED, 0);
} else {
digitalWrite(RED_LED, 1);
delay(1000);
digitalWrite(RED_LED, 0);
}
answer = "";
result = 0;
gameStatus = 1;
currentNum = 0;
}
}
}
可以很容易地通过两个变量quantity和delayTime来改变数字的数量和每个数字显示的时间。delayTime用作毫秒,1000毫秒=1秒。result变量用于累加所有随机数字,并用作关键答案。currentNum是包含玩家输入的数字的变量。如果按下输入按钮,currentNum变量将增加1。将整数转换为字符串以比较结果和玩家提交的答案。当答案的长度等于关键答案的长度时,它将检查玩家输入的所有数字是否与结果匹配。
int quantity = 10;
int delayTime = 1000;
int gameStatus = 1;
//1:显示随机数字,
//2:显示当前数字并等待提交
int result, currentNum = 0;
String answer = "", sResult;
void loop() {
switch(gameStatus) {
case 1:
//显示随机数字
result = 0;
for(int i = 1; i <= quantity; i++) {
int a = random(0, 10);
//a变量将是
//0到9之间的随机数字
displayNum(a);
result += a;
delay(delayTime);
}
finishDisplaying();
gameStatus = 2;
sResult = String(result);
break;
case 2:
//提交答案
displayNum(currentNum);
delay(200);
break;
}
}
可以在这里下载完整的源代码。将它们连接起来并上传以了解更多。
将其上传到合适的板子上,看看它是如何工作的。按顺序按下数字。例如,答案如果是46。必须按下左边的按钮得到数字4,然后按下右边的按钮提交数字4,然后以相同的方式继续提交数字6。让看看下面的插图。它显示了如何按下以获得需要的数字。
在测试期间,可能会发现它运行出乎意料。按下按钮一次,但数字增加了2或3而不是1。看起来按钮被按下了两次,但实际上只按了一次。在这种情况下,应该在这里了解更多关于消抖的信息。
有两种方法可以解决这个问题。可以通过添加几行代码或在电路中使用额外的电容器来消抖按钮。