导读:stem -游戏平台课程计划-设备与软件开发课程
这是一个完整的初级水平的课程,强调STEM元素,围绕软件开发的LED条显示游戏和小应用程序运行在Arduino设备。
在Arduino 'C'软件的实现,以及相关的基于硬件的微控制器的构建中,制造商将获得计算机科学、Arduino技术、电子、工程和数学以及逻辑和功能设计方面的一些有价值的知识。
学生(制作者)可以很快看到他们的编程在现实世界中的结果;不仅仅是电脑屏幕上的数字和文字。有可靠反馈的动手互动是最好的学习工具之一。
在课程结束时,年轻人和新手应该能够创建自己的功能,包括LED显示游戏和迷你应用程序。
如果本文档中有您不确定其定义的词,请将其定义。
这个Instructable被分解成课程,在教育课程格式中使用,同时也非常适合个人自学和技能建设。
在正式的课堂环境下,你可能想要解析材料,这样学生就不会过早地接触到解决方案。在课程中,在一些指示之后,你经常会看到一行只有“…在上面。这是学生要去完成课程目标的地方。
这里有14节课。如果需要,可以从作为选修或作为课程的(b)部分给出的部分中形成更正式的课程。如果需要的课程较少,那么可以先把这些部分略过,然后再继续上下一课。有些课花的时间比较长,可以分开上课。
供应:
为了完成第一和第二课,你需要这些部分:
- 无焊面包板,
- 大多数LED,
- 100-1000欧姆的限流电阻,
- 一个按钮,我使用6x5x3.5mm面板Mini PCB按钮DIP如下:https://www.ebay.com/itm/233172815770或者你可以使用(注意插脚有不同的间距):https://www.ebay.com/itm/233172815770
- 和一个被动压电测深器。(9毫米dia)。https://www.ebay.com/itm/263837521428
为了完成第二课之后的课程,你需要一个迷你STEM/游戏平台,就像在教学表中构建的那样:mini_STEM_Arduino LED游戏平台
为了服务STEM教育的目标,最好是你(学生)自己建立一个。其中列出了相关的必需部件。
第一步:第一课——从简单开始
我们将从一个Nano MCU模块的简单组合开始(通过一个原型无焊料面包板)连接到一个按钮和一个LED。
按照图示将这些组件组合在一起,并准备在即将到来的软件中使用它。
我们需要在Arduino“草图”项目中进行一些软件编程。
参考这个Arduino开发链接:https://www.arduino.cc/en/Guide/ArduinoNano
首先,让我们检查一下我们将要使用的软件的基本最低所需代码段。
头部分根据需要有概述信息、配置数据和全局程序数据定义。
// ================================================================ // 项目1:最小Arduino ' C '计划/ /使用微控制器,一个领导和一个按钮 // ---------------- 硬件相关的部分 ------------------ // 常量不会改变。它们在这里被用来设置pin码://引脚连接到LED,连接到arduino引脚2," D2 " const int BTN_INPUT = 18;//按钮输入引脚,连接arduino引脚18," A4 " const int PSUDOGND = 15;//用作按钮的Ground
接下来是“设置”例程:
//================================================================= // 安装程序在启动或运行一次当你按下复位:无效的设置(){pinMode (LED_OUT、输出);digitalWrite (LED_OUT、高);//启动w/ led关闭pinMode(BTN_INPUT, INPUT);//按钮引脚为输入digitalWrite(BTN_INPUT, HIGH);//启用内部上拉;按钮启动位置高;LOW pinMode(PSUDOGND, OUTPUT);//为按键digitalWrite(PSUDOGND, LOW)提供Ground (-V);}
然后是循环代码:
//================================================================= // 一遍又一遍地循环程序运行永远在无效循环(){digitalWrite (LED_OUT、低);延迟(750);digitalWrite(LED_OUT, HIGH);延迟(750);//创建一个关闭周期}
如需研究本软件的各要素,请参阅:
https://www.arduino.cc/reference/en/
上面使用的新元素:
C语言< br元素Arduino特定功能 >-------------------- -------------------------- // 一个注释行pinMode()变量类型声明如:int btn_cnt;digitalWrite()函数调用,例如:void my_func()…Setup()语句为变量赋值:btn_cnt=8;循环()代码块,例如:{btn_cnt=8;延迟(x);……}
在代码中使用新的C编程元素时,指导老师应该介绍它们。在自学的情况下,请充分阅读它们,使你感到你可以利用它们。注意:像使用其他语言一样,你不需要完全了解C编程语言来使用它;只需要您将要使用的元素和结构。
上面的三段代码组成了一个有效的Arduino草图。把它们放到名为“Lesson_1”的文件中。在o” and that in a folder named “Lesson_1” which is located where your Arduino IDE looks for sketches. Alternately within the Arduino IDE use 'File – New', cut and paste in the sections of code above, then 'Save As …' with the filename “Lesson_1.ino”.
如有需要,请参考:https://www.arduino.cc/en/Guide/Environment
编译并执行草图。它应该下载到你的硬件设备,你会看到LED闪烁。
第二步:1B课-让我们使用按钮输入
现在让我们用按钮来停止LED闪烁。我们将通过'while'语句来实现这一点。谁的格式是:
While(条件)语句;
为此,在“循环”代码的末尾添加以下代码行。
while (digitalRead(BTN_INPUT) == LOW);//按下按钮时待在这里
当条件为true时,在其语句的表达式子句中不需要执行任何代码。因此,在'while()'之后,我们有一个do nothing语句,只包含必要的";"。这个while语句除了不断地检查条件,直到发现它为false之外,什么也不做。然后它允许程序继续执行。
实现并测试它。
……
让我们改进我们的“循环”代码,使按钮可以在LED打开或关闭时被检测到,然后暂停该状态。为此,我们将添加一个局部变量'ledON'和一个'while(true)'块,以便保持在'loop'例程的作用域内。
添加" while(true){} "块的原因将在后面的课程中更好地解释。
下面是新的循环例程:
void loop() {bool ledON=LOW;while(true){//永远执行此代码块digitalWrite(LED_OUT, ledON);ledON = !一同出席;//切换状态延迟(750);//允许led显示其状态(digitalRead(BTN_INPUT) == LOW);//当按下按钮时留在这里}}
尝试此编码并验证其行为是否符合我们的预期。
第三步:第二课-现在来一个小游戏
现在我们将把我们所拥有的变成一个小游戏。为LED保持亮或灭的时间添加一个变量。当按下按钮且LED亮时,这个时间就会减少,但当LED灭时按下按钮时,这个时间就会重置。
所以这个游戏的目标可能是看看在一个角色中你能让LED闪快多少次。
研究所有的新代码,包括新变量(' onmssec '和'btnPush')以及'break'语句的操作定义。
void loop() {// Lesson 2a bool ledON=LOW;bool btnPush;int onMSecs;onMSecs = 400;while(true) {ledON = !一同出席;//切换状态digitalWrite(LED_OUT, ledON);延迟(onMSecs);//允许led显示其状态btnPush = (digitalRead(BTN_INPUT) == LOW);if (btnPush) {if (ledON==LOW) onMSecs -= 40; else break; } // wait for button not to be pushed while(btnPush) btnPush=(digitalRead(BTN_INPUT) == LOW); // stay here while button pushed } }
步骤4:2b课-添加一些声音
现在让我们为我们的活动添加一些声音。我们会用它来给予积极和消极的反馈。
在面包板上添加一个被动压电测深器,它的+V连接到D13,另一个引脚连接到GRD。参考照片。
首先,我们需要知道音频设备的连接位置。将以下行放入全局数据定义区域:
AUDIO_OUT = 13;
在'setup()'例程中添加代码初始化该数字IO:
pinMode (AUDIO_OUT、输出);
digitalWrite (AUDIO_OUT、低);
在循环中,我们将展开if (ledON==LOW)语句;'使用语句块,添加对声音子例程(函数)的调用,像这样:
if (ledON==LOW) {onMSecs -= 40;beep (20);} else {onMSecs = 400;boop (300);}
(为了更好地理解和理解,可以先将以下支持例程内联编码。)
以下支持函数被添加到文件的末尾。在代码delayMicroseconds(int)中使用了一个新函数,你应该查阅它并阅读相关内容(参见上面的研究参考链接)。
// =========================== 支持功能 =================== 空白beep (int毫秒断开){/ /好与一个蜂鸣器工作,最好的发言人(int i = 0;我<毫秒断开;i++){//循环如此多的'msecs' digitalWrite (AUDIO_OUT, HIGH);delayMicroseconds (500);digitalWrite (AUDIO_OUT, LOW);delayMicroseconds (500);}延迟(毫秒断开);//暂停相同的# 'msecs'} void boop(int msecs){//产生比'beep()'更低的频率音(int i=0;我<(毫秒断开/ 4);i++){//循环为'msecs'毫秒digitalWrite (AUDIO_OUT, HIGH); delay(2); digitalWrite ( AUDIO_OUT, LOW); delay(2); } delay(msecs/2); // pause for 1/2 as long }
我们还可以在设置代码中添加一行,这样我们就可以知道设置代码何时执行,音频何时工作。
beep (50);
你现在可以玩这个小游戏了。试着看看你能连续点击多少次,以及你能以多快的速度让LED闪烁。当你“点击”LED ON闪烁时,你会听到奖励的小哔哔声;当你错过时,你是嗡嗡的。
以下是完整的代码:
// ================================================================ // 项目2:最低Arduino ' C '计划/ /迷你闪烁LED游戏,使用微控制器,一个领导和一个按钮 // // ---------------- 硬件相关的部分 ------------------ // 常量不会改变。它们在这里被用来设置pin码://连接到LED的pin const int BTN_INPUT = 18//按钮输入引脚,到arduino引脚18," A4 " const int PSUDOGND = 15;//用作按钮的接地线。//================================================================= // 安装程序在启动或运行一次当你按下复位:无效的设置(){pinMode (LED_OUT、输出);digitalWrite (LED_OUT、高);//启动w/ led关闭pinMode(BTN_INPUT, INPUT);//按钮引脚为输入digitalWrite(BTN_INPUT, HIGH);//启用内部上拉; buttons start in high position; pressed -> LOW pinMode(PSUDOGND, OUTPUT); // provide Ground (-V) for the button digitalWrite(PSUDOGND, LOW); pinMode(AUDIO_OUT, OUTPUT); digitalWrite(AUDIO_OUT, LOW); beep(50); } //================================================================= // the loop routine runs over and over again forever on void loop() { // Lesson 2b bool ledON=LOW; bool btnPush; int onMSecs; onMSecs = 400; while(true) { ledON = ! ledON; // toggles the state digitalWrite(LED_OUT, ledON); delay(onMSecs); // allow the LEDs to display its state btnPush = (digitalRead(BTN_INPUT) == LOW); if (btnPush) { if (ledON==LOW) { onMSecs -= 40; beep(20); } else { onMSecs = 400; boop(400); } } // wait for button not to be pushed while(btnPush) btnPush=(digitalRead(BTN_INPUT) == LOW); // stay here while button pushed } } // =========================== Support Functions =================== void beep(int msecs){ // works for OK with Buzzers, best with Speakers for (int i=0; i试试这个:
在setup()中替换beep(50);符合:
beep (50);beep (50);嘟嘟(150);编译-下载并运行代码。注意你所听到的。
注释掉(使用//或/*…*/)支持函数beep()中的最后一行。
/ /延迟(毫秒断开);//暂停相同#的'msecs'编译-下载并运行代码。注意你所听到的。要再次收听它,拔掉和重新插入微型USB线或按下微控制器板上的“重置”按钮。BTW:忽略任何突发音频产生只是微控制器获得电源或重置;这是在代码执行之前。
当您注释掉beep()函数中的最后一行代码并重新测试代码的行为时,
有什么区别?为什么?
撤销刚刚为上面的测试所做的更改;因此可以识别对beep()的单个调用。
现在让我们来了解一下当事情不像需要或想要的那样时可能会发生什么。
每次注释掉beep()代码的一行;从“// void beep(…第一行。
然后注意在重新编译期间发生了什么。如果输出红色错误文本,简要研究它,尝试将它与您的编辑相关联。在注释掉下一行之前恢复一行。
如果编译成功并下载,那么迷你游戏的行为有什么不同?
步骤5:第三课-构建一个迷你STEM平台设备
构建(或获取)您的迷你STEM硬件平台。在Instructable中查看如何组装这个硬件平台:
让我们修改第2课中的“Speed Flasher”代码,它将在这个“教育Arduino游戏/活动硬件平台”上工作。
更改头/配置代码如下:
// ================================================================ // 程序3课:/ /使用微控制器,8 4彩条和4按钮模块 // // ---------------- 硬件相关的部分 ------------------ // 常量不会改变,除非硬件变化const int AUDIO_OUT = 13;const int AUDIO_NEG = 12;//作为伪地面和音频启用/禁用// ---------- 8 LED配置数据const int nleds=8;Const int lites[] = {9,8,7,6,5,4,3,2};// LED引脚分配#define ON_STATE 0 const int PSUDOVCC = 10;//提供+V到8 LED模块// ----------按钮配置。Data const int button[] = {16,17,18,19};//四个按钮输入引脚#define PRESSED_STATE 0 const int PSUDOGND = 15;//使用4键模块//================================= //临时#定义,所以我们可以测试旧的代码与新的硬件和它的配置数据#define LED_OUT lites[7] #定义BTN_INPUT按钮[2]
新硬件平台的设置应该如下所示:
void setup(){// ------------设置LED引脚作为输出(int x = 0;X < nleds;x++) {pinMode(lite [x],输出);digitalWrite (lite [x], (! ON_STATE));// start w/ LEDs off} // pinMode(PSUDOVCC, OUTPUT);//提供+v LED条模块// digitalWrite(PSUDOVCC, HIGH);pinMode (PSUDOVCC、输入);//让它外部提供(通过红色电线)// ------------设置四个按钮模块(int x = 0;X < 4;x++) {pinMode(按钮[x],输入); // button pins are inputs digitalWrite(button[x], HIGH); // enable internal pullup; buttons start in high position; logic reversed } pinMode(PSUDOGND, OUTPUT); // provide Ground (-V) for the button module digitalWrite(PSUDOGND, LOW); // ------------ setup & init test for the Audio pinMode(AUDIO_OUT, OUTPUT); digitalWrite(AUDIO_OUT, LOW); pinMode(AUDIO_NEG, OUTPUT); digitalWrite(AUDIO_NEG, LOW); beep(50); boop(75); }
为了正确的行为,需要修改loop()代码中的一行:
是:if (ledON==LOW) {
需要:if (ledON==ON_STATE) {
鉴于上述代码更改,“Speed Flasher”单led按键游戏应该仍然适用于第2课中使用的硬件设置,并适用于这个新硬件;利用左边的第三个按钮和右边的最后一个led灯。试一试。
还要注意,在重置时,D13上的活动(BTW点亮板上LED)将不再导致音频,因为还没有返回-V(地面)路径。
现在创建一个代码循环来测试/验证按钮是否都能工作。
当按下按钮时,每个按钮都点亮一个独特的LED灯,否则关闭。
看看你是否可以在没有进一步指导的情况下完成。
……
这是我的这个活动的代码:
void loop() {// Lesson_3a反映相关led上的按钮状态bool ledON;while(true){//在相关的led上反映按钮状态if (digitalRead(button[0])==PRESSED_STATE) digitalWrite(lites[0], ON_STATE);if (digitalRead(button[1])==PRESSED_STATE) digitalWrite(lites[1], ON_STATE);if (digitalRead(button[2])==PRESSED_STATE) digitalWrite(lites[2], ON_STATE);if (digitalRead(button[3])==PRESSED_STATE) digitalWrite(lites[3], ON_STATE);延迟(1);//允许led发光时间//重置led为关闭(int i=0;我< 4;i++) {digitalWrite(lites[i], !ON_STATE);} ledON = ! digitalWrite(lites[nleds-1], ledON); // alternate On/Off the last LED } }
此代码将反映分别显示在led 1-4上的按钮1-4的任何组合。
试一试。
最后一个LED会点亮一半的时间,但我们会觉得它是亮着的,只是比全速亮要暗一些。
我喜欢在没有用户交互的情况下呈现一些视觉和/或音频。这样设备就不会被误认为是关闭的。如果这样的设备被遗忘,它最终可能会放电,并可能损坏电池或附带的电源包。
为了增加一些“等待”的感觉……我们可以把它做成LED闪光灯,否则会很无聊。
为此,在loop()代码中添加变量声明:
int抽搐= 0;
和替换:
ledON = !一同出席;
:
If (tic++ > 750) {tic = 0;ledON = !一同出席;}
最后一个LED现在每1.5秒闪一次。
步骤6:第4课-在显示器上做一个光点扫描
创建代码在led上进行光点扫描。大概每一到两秒。
……
希望你有所收获。
以下是一组代码:
第4课,扫描led (int blip=0;插曲< nleds;blip++) {digitalWrite(lite [blip], ON_STATE);延迟(150);//将LED (blip)闪烁一个bit digitalWrite(lites[blip], !ON_STATE);//关闭最后点亮的LED灯
试一试。
当第5个LED亮起时按下按钮1,我们就会听到哔哔声。
加上,就在延迟(150)以下代码行:
//如果第5个LED亮时按下按钮-1,则发出蜂鸣声if (digitalRead(button[0])==PRESSED_STATE && blip==4)蜂鸣声(50);
测试和评估结果行为。
……
那么,你是否注意到,你可以简单地按住Btn1,当第5个LED亮起时,你会听到哔哔声?
为了修复这个add,在loop()之后,声明如下:
字节btnState, lastState;bool btnPressed;
将测试按钮和LED状态的代码行更改为:
//如果第5个LED亮起时刚好按下了按钮-1,则给出beep btnState=digitalRead(按钮[0]);btnPressed = (btnState!=lastState) && (btnState==PRESSED_STATE);lastState = btnState;if (btnPressed && blip==4) beep(50);
测试和评估结果行为。
……
注意,当它到达Led5时按下按钮,而不是在Led5点亮时按下按钮,它就会发出哔哔声。
为了解决这个问题,将延迟(150)行移到打开LED的行之后。
好了,现在验证它是否按预期工作。
下面是loop()代码的样子:
//第4课扫描LED(同样如果Btn1按&& LED 5点亮…Beep int btnState, lastState;bool btnPressed;for (int信号= 0;插曲< nleds;blip++) {digitalWrite(lite [blip], ON_STATE);延迟(150);//闪烁LED (blip)一点//如果按钮-1刚刚被按下,当第5个LED是亮的,给一个beep // if (digitalRead(button[0])==PRESSED_STATE && blip==4) beep(50);btnState = digitalRead(按钮[0]);btnPressed = btnState!=lastState && btnState==PRESSED_STATE; lastState=btnState; if (btnPressed && blip==4) beep(50); digitalWrite(lites[blip], !ON_STATE); // turn last lit LED off } }
接下来,做出必要的改变以加快扫描速度,就像我们让单个LED闪光越来越快一样。
要做到这一点(在loop()代码中),
添加声明:int onMSecs = 200;
改变延迟(150)来延迟(onMSecs)
和替换:
if (btnPressed && blip==4) beep(50);
:
if (btnPressed) {if (blip==4) {onMSecs -= 20;beep (20);} else {onMSecs = 200;boop (400);}}
试着看看它是否像预期的那样工作。
……
您可能会注意到,它似乎并不能可靠地加速。这是由于当特殊函数'loop'重新运行时,它不能保证将它的变量放在与之前相同的位置,所以'onMsecs'不能可靠地维护对它所做的值更改。在我们早期的单LED“Speed Flasher”中,主代码是在一个while(true) forever循环中,所以“loop()”函数永远不会重新运行。
要解决这个问题,你可以更改onmssec的声明为:静态int onMSecs = 200;
请向你解释“静态”或阅读有关它的内容,也许是范围的主题。
你的代码现在应该是这样的:
void loop(){字节btnState, lastState;bool btnPressed;静态int onMSecs=200;for (int信号= 0;插曲< nleds;blip++) {digitalWrite(lite [blip], ON_STATE);延迟(onMSecs);//当第5个LED亮时,按下按钮-1,则发出哔哔声btnState=digitalRead(按钮[0]);btnPressed = btnState!=lastState && btnState==PRESSED_STATE; lastState=btnState; if (btnPressed) { if (blip==4) { onMSecs -= 20; beep(20); } else { onMSecs = 200; boop(400); } } digitalWrite(lites[blip], !ON_STATE); // turn last lit LED off } }
在'loop()'函数中使用'static'的一个问题是,你可能会错过你的某个变量需要它,而且你的代码越复杂,这种情况就越有可能发生。出于这个原因和其他原因,我喜欢使用“loop()”作为一个简单的顶层活动控制器和一个独立的(非特殊的)功能,用于活动和游戏,其中它们有一个永远而根据需要循环。
假设我们将我们的小活动命名为“Speed_Scan”,我们会得到如下内容:
void loop() {Speed_Scan();} void Speed_Scan() {'loop()'函数中的声明(不带'static')。{我们在'loop()'函数中的代码。}}
不再需要使用'static',因为我们永远不会离开(退出并重新运行)Speed_Scan()函数的作用域。局部变量将保留在一个位置并保持其值。
我修改了自己的《Speed_Scan》,将其变成一款带有目标和奖励的更具挑战性的游戏。
请注意,对用户的行为和成就给予反馈是非常重要的。给你。研究我所做的改变以及它们相关的特征差异是什么。
……
void Speed_Scan() {int btnState, lastState;bool btnPressed;int onmssec, stRate=165;Int blip, hits=0, goal=10;信号= 0;onMSecs = stRate;while(true) {digitalWrite(lite [blip], ON_STATE);延迟(onMSecs);//闪烁LED (blip)一点//允许使用左或右最按钮btnState=(digitalRead(button[0])==PRESSED_STATE || digitalRead(button[3])==PRESSED_STATE);btnPressed = btnState!=lastState && btnState; lastState=btnState; if (btnPressed && (blip==4 || blip==5)) { beep(100); hits++; if (hits==goal) { beep(100);delay(50); beep(100);delay(50); beep(250); // you did it hits=0; // start over delay(1000); } } // added block for support of a missed penalty if (btnPressed && !(blip==4 || blip==5)) { delay(300); hits--; // slow down update rate } onMSecs = stRate - (15*hits); // more hits he get faster the blip scans digitalWrite(lites[blip], !ON_STATE); // turn last lit LED off blip = (blip+1) % nleds; // advance to next LED } }
步骤7:第4B课-添加随机性
对于游戏,random()函数非常有价值。鉴于x =随机(10、30);X将被分配一个数字=>10和<30。
试试这个:创建一个功能,挑战一个人的快速反应,并对他们的表现进行反馈。
利用随机函数,使他们需要做出反应的事件的时间不可预测。
……
作为一个很好的例子,你可能编写了这样的代码:
void TagIt(){//当LED灯亮时,立即按下按钮-1进行响应,同时(true){延迟(随机(1000,4000));//等待1 - 4秒digitalWrite(LED_OUT, ON_STATE);延迟(200);//给他们一点反应的时间。(根据你的喜好调整)if (digitalRead(BTN_INPUT)==PRESSED_STATE) boop(1000);// success digitalWrite(LED_OUT, !ON_STATE);}}
记住,BTN_INPUT被定义为按钮[2],第三个按钮。我建议现在使用左边的第一个按钮,通过重新定义它:
#定义BTN_INPUT按钮[0]
下面是一个更复杂的示例,它使用了更多的I/O,多个random()语句,并涉及到额外的Math。研究编码及其相关行为。
void SeeIt_TagIt(){//尝试点击相关的按钮,当一个LED亮起int time_given = 350;//在给定的时间内(调整到你喜欢的)While (true) {delay(random(1000,4000));//等待1 - 4秒n = random(4);//选择一个LED digitalWrite(lites[2*n], ON_STATE);延迟(time_given);if (digitalRead(button[n])==PRESSED_STATE) {beep(100);boop (400);// ta Da!而(digitalRead(按钮[n]) = = PRESSED_STATE); // stay until released } digitalWrite(lites[2*n], !ON_STATE); } }
挑战:给定同一个LED不能连续两次被选中的要求,更新SeeIt_TagIt以满足该要求。
……
当专业编程时,你通常会被要求用最小的CPU执行时间完成这些要求。对于这一挑战,可以通过一些调整好的数学方法来完成。
替换:
N =随机(4);//选择一个LED
:
N = (random(1,4) + N) % 4;//选择一个LED,而不是最后一个
(可选),研究并尝试这个更复杂的函数,它给出了反应时间的测量:
//---------------- React_Now - Swat快速当LED亮起void React_Now(){//尝试按下按钮时,当第一个LED亮起//第一个LED点亮100毫秒,额外的LED减少每20毫秒//挑战:如果一个人按下并坚持在第一个LED错误赢;如何修复?bool btn = !int min_Period = 100;字节btnInput;字节LEDptr;btnInput =按钮[0];//使用四个按钮中左边的第一个按钮while(true){//确保按钮没有被按下while(btn==PRESSED_STATE) btn=digitalRead(btnInput);//确保所有的led都是关闭的(int LEDptr=0;LEDptr < 8; LEDptr++) digitalWrite(lites[LEDptr], !ON_STATE); delay(random(2000,5000)); // wait for 2 - 5 seconds digitalWrite(lites[0], ON_STATE); beep(10); // takes 2x msecs delay(min_Period-20-20); // account for the 20ms beep time and 20ms in for loop for (LEDptr=0; LEDptr<8; LEDptr++) { digitalWrite(lites[LEDptr], ON_STATE); delay(20); btn = digitalRead(btnInput); if (btn==PRESSED_STATE) { // they pressed the button delay(1000); break; } } if (LEDptr==8) beep(100); } }
研究了该函数的编码;获得定义,任何对你来说陌生的元素类型(操作符、关键字、函数、结构等);直到你对这一切有了真正的理解。
步骤8:第5课-硬件I/O支持例程的开发
将代码逻辑上划分为更小的子函数是一个非常好的主意。这种模块化使得代码更容易测试、改进、更容易重用(可移植),也更容易理解。有一种情况尤其如此;这就是把依赖硬件的代码从顶层函数代码中去掉。这样,如果硬件有任何变化,它不会影响您的应用程序代码。
我写了一些硬件支持例程。一个用于按钮模块" scanBtns() ",两个用于LED条显示" clearDisp() "和" refreshDisp() "。我们已经有了用于音频的" beep() "函数。
在相关的应用程序代码中,您需要在基于按钮活动做出决策之前调用“scanBtns()”。硬件支持例程(又名:硬件驱动程序)维护几个全局变量,#定义了这些变量,然后您可以在应用程序代码的控制和决策过程中使用它们。他们是:
// ------------------------------------------------------------ // 4-Button模块支持bool btn1 = false;//反映按钮#1的状态;Bool btn3 = false;Bool btn4 = false;bool Btn = false;//反映按钮的集合bool ESC = false;//一个伪按钮,如果按下btn4 2秒(给定~1ms更新频率),则为true。//如果btn1刚刚改变bool btn2Changed = false;bool btn3Changed = false;bool btn4Changed = false; bool BtnChanged = false; // true if any button changes #define btn1Pressed (btn1Changed && btn1) #define btn2Pressed (btn2Changed && btn2) #define btn3Pressed (btn3Changed && btn3) #define btn4Pressed (btn4Changed && btn4) #define BtnPressed (BtnChanged && Btn)
LED显示支持代码使用以下全局变量与之连接:
// ------------------------------------------------------------ // unsigned int msCnt 8-LED显示栏支持;//伪mss,每次'refreshDisp()'被调用时递增在下面的数组中,元素[1]-[8]分别与led 1-8相关。([0]和[9]用于溢出保护)bool dim[10];//设置你想要暗的led (~10% on) bool lit[8+2];// " lit (~33% on) bool brt[8+2];// " bright (100%) int brightOne;//设置指示(1-8)LED亮。在litLED中用作光标或精灵;// " Lit "
“refreshDisp()”代码提供了维持LED亮度水平的方法,通过定期按给定比例开关它们的开/关。它是由这个代码直接完成,而不是使用控制模拟输出电平或PWM(脉宽调制)的MCU控制,主要是因为不是所有的8条控制线连接到我们的8个led是模拟输出线或DIO线支持PWM控制。
为了按预期执行“refreshDisp()”需要大约每1毫秒执行一次,这与更高级别功能的实现无关。这可以(也许应该,因为它确实有一些优点)通过使用ISR(中断服务例程)来完成。它们的实现高度依赖于硬件,很难调试,而且通常很深奥。所以我们将通过做以下事情来绕过这个高级选项:
在应用程序代码的循环中,“refreshDisp()”需要相当有规律地调用(~每1+毫秒)。这通常可以通过延迟(1)来实现;调用refreshDisp()后的第一行。意识到循环中所有剩余的代码可能需要1/10毫秒左右的时间来执行。
使用下面的appShell。在o write some lines of code, inside of “myApp()” which utilizes these buttons and LED facilities.
……
我希望您已经创建了一些有趣的代码集。
下面是一组简单的,希望有启发意义的指令示例:
if (btn1Pressed) {boop(75);} if (btn2Pressed) {beep(25);} if (btn3Pressed) {beep(150);} if (btn4Pressed) {clearDisp();}
下面是另一个示例代码,它使用了硬件支持例程提供的更多一些特性:
if (BtnPressed) {clearDisp();For (int i=1;我< = nleds;i++){//设置所有led到给定的电平如果(btn1Pressed) dim[i]=true;if (btn2Pressed) lit[i]=true;if (btn3Pressed) brt[i]=true;}} //if (btn4Pressed) {clearDisp();} //这一行不需要//当btn1-3被按住时产生声音。Btn3应该会产生一种刺耳的蜂鸣器般的声音。while (Btn) {if (btn1 || btn3) boop(3);If (btn2 || btn3) beep(3); scanBtns(); //refreshDisp(); }
尝试这些代码块,而不是“//代码执行你的功能/活动/游戏选择”,并观察它们的行为。
你应该看到他们如何演示按钮和LED支持功能的一些功能。我发现,对于这些HW支持函数的行为,我可以做任何我想做的事情,并且很满意。我用过很多次了。
但在我的上一个代码示例中,我必须删除beep()和boop()末尾的delay()调用,以便在按住按钮时获得流畅的注释。现在没问题了,但在setup()中,出于实际目的,我有一个谎言:beep();beep ();beep ();我希望听到三个"哔"声。结果我得到一个很长的“b e e p”。因此,在beep()和boop()函数代码的末尾恢复注释的out delay()调用。现在在启动时,你应该听到三个“哔”声。对吧?
现在怎么办?使用这最后一个代码集,再次不再使平滑连续boop…或哔哔……同时按住按钮1或2。所以我有点两面派,有时我想让beep()是独立的,其他时候我想让beep()的声音融合在一起。在对这些函数的调用中使用默认参数可以实现这一点。以下是您对beep()所做的工作,您需要对boop()函数及其使用做类似的工作。
void beep(int duration, int delayms=0){//适用于蜂鸣器和扬声器的pinMode(BEEPPIN, OUTPUT);For (int i=0;我<持续时间;i++){//等待一个延迟ms digitalWrite (BEEPPIN, HIGH);delayMicroseconds (500);digitalWrite (BEEPPIN, LOW);delayMicroseconds (500);}延迟(delayms);//暂停延迟毫秒}
在文件顶部的开始注释块后面添加这些行:
// ----------------函数原型(预先定义,以帮助编译器管理)void beep(int duration, int delayms=0);Void boop(int msecs, int delayms=0);
将setup中的beep-beep-beep行更改为:
beep(50、30);beep(50、30);嘟嘟(150);//声明“它是活的”
在定义形参列表中为形参赋值时,如果没有在函数调用中给出该值,则使用该值。
现在重新测试,观察行为的变化。你会注意到,在启动和我的应用程序代码期间,我从beep()获得我想要的行为;在适当的情况下,在有或没有延迟暂停时间的情况下调用它,以及在按下按钮时调用它。
第9步:第5B课-在发出声音时刷新显示
现在让我们在发出声音的同时刷新LED显示屏。
恢复注释出行:/ / refreshDisp ();
在代码块中,标题为://当btn1-3被按住时产生声音
在重新测试中,你会发现即使在播放音频时led也会发光;然而,当一些声音产生时,显示器闪烁。
问题来自于声音代码使用delay()进行计时(而不是同时刷新显示)来获得我们想要的声音。同样的情况也可能出现在一些游戏/应用程序代码中。所以我们需要一个在等待时刷新的延迟函数。让我们使用这个函数:
// ----------------------- 空白refreshWait (int msec){而(msec > 0) {refreshDisp ();延迟(1);msec,;}}
改变延迟()调用refreshWait ()调用beep()和boop()函数。
把这一行加到末尾为在beep()函数中循环代码:
refreshDisp ();
现在,声音和显示更新应该工作得很好,正如预期的那样,有最小的闪烁。
您的代码文件现在应该类似于HW_Support_Demo。Ino,下载它并根据需要进行比较。
步骤10:第6课-使用支持功能使led变暗
重做第4课中的“Speed_Scan()”,使其内部没有digitalRead()或digitalWrite(),而依赖于第5课中开发的硬件支持函数。
……
如前所述,根据需要进行调试以使其工作。
现在添加一些新的功能到新的“Speed_Scan”。
使用该功能使许多led变暗,以反映加速扫描的进度。
在适当的地方添加以下一行:
For (int i=1;我< =打;我+ +)的[我]= true;
在需要的地方加上这一行:
clearDisp ();
也要用全局支持的“litLED”替换“lit[blip] =”之类的用法。
重新测试以确保您保留了以前的功能。
……
看到的:Speed_Scan_ver4 ()
顺便说一下,在这个修订版中,你可以使用任何按钮,而不仅仅是btn1,因为使用了“Btn”。
步骤11:第6B课-利用硬件支持功能
重做第4课中的“SeeIt_TagIt()”,使其内部没有digitalRead()或digitalWrite(),而依赖于第5课中开发的硬件支持函数。
……
根据需要进行调试。
您可能已经发现,将“digitalRead(button[n])”替换为来自新的硬件支持功能的内容并不直接。你可能会得到这样的结果:
替换:
if (digitalRead(button[n])==PRESSED_STATE) {
:
如果(btn1 & & n = = 0 | |(这里& & n = = 1) | | (btn3 & & n = = 2) | | (btn4 & & n = = 3)) {
这个编码涉及到并且需要几个CPU指令来执行。第一次检查时不直观,因此容易在调试或升级时出错。所以我改变了这个硬件支持代码块:
B1 = !digitalRead(按钮[0]);B2 = !digitalRead(按钮[1]);B3 = !digitalRead(按钮[2]);B4 = !digitalRead(按钮[3]);
:
digitalRead(button[0]);digitalRead(button[1]);digitalRead(button[2]);digitalRead(button[3]);
然后添加这个全局声明:
bool btn [5];// btn1-4状态数组,btn[0]没有被使用
因此,我能够在应用程序代码中使用这个简单的if测试:
If (btn[n+1]) {
(可选)重做" React_Now() ",就像你刚刚为SeeIt_TagIt所做的那样。
也可以使用“dim[]”,“litLED”,甚至“brightOne”。
然后让它响应btn1或btn4,这样左撇子和右撇子的用户就能得到同等的服务。
……
参见Lesson_6.ino中的SeeIt_TagIt_ver2()和React_Now_ver2()
步骤12:第7课-验证硬件实现
为了验证硬件设计和实现是否可靠,通常会生成测试软件。
我们已经做了一点,但还不够彻底。添加文本输出对于测试和调试是一个很大的改进。
Arduino IDE(交互式开发环境)应用程序为文本输出提供了一个Serial Monitor窗口;以及一组形式为" serial .function() "的串行支持函数,我们将使用" serial .print() "和" .println() "参考https://www.arduino.cc/reference/en/language/func..。
特别是查看“示例代码”部分。
添加到init()中…
//初始化串行通信速度为每秒9600位:serial .begin(9600);系列。打印(“Arduino教育小游戏平台”);系列。println(" -第7课");
输出这些“Serial。”的命令将在Serial Monitor窗口中看到。将草图下载到连接的项目平台后,您可以在Arduino IDE中通过菜单项“Tools”-“Serial Monitor”将其打开。草图将运行,您将看到打印语句的结果。如果您对串行监视器有问题,请审阅:
https://create.arduino.cc/projecthub/glowascii/ser..。
下面是一个函数,用于为我们提出的目的打印按钮状态。
空白btnReporting () { // ================================= 按钮,导致运动&报告beep (100);clearDisp ();while (Btn) scanBtns();//等待按钮释放while (1) {refreshWait(1);scanBtns ();// ------------------- 如果(BtnChanged){系列按钮报告。println (" ");if (btn1)串行。打印(“[Btn1]”);其他系列。打印(" ");if (btn2)串行。print("[Btn2] "); else Serial.print(" "); if (btn3) Serial.print("[Btn3] "); else Serial.print(" "); if (btn4) Serial.print("[Btn4] "); else Serial.print(" "); // ------------------ LED reflection of button state lit[1] = lit[2] = btn1; // set Grn LEDs lit[3] = lit[4] = btn2; // set Blu LEDs lit[5] = lit[6] = btn3; // set Yel LEDs lit[7] = lit[8] = btn4; // set Red LEDs brightOne=0; beep(15); // make a key press click, for up&down } } }
使用这个函数来测试你的硬件和我们的支持函数scanBtns()。
您是否注意到没有正确检测到所有的组合?你能看出修理它需要什么吗?
将btnState设置为全局的,并将这个(在btn4的print之后)添加到报告中:
并同时btnState);
注意,在scanBtns()中,'currState'一次只表示一个按钮。
为了解决这个问题,我们需要重新定义'currState'的设置等于什么。我还创建了一个新的全局变量“btnNum”来表示这个“一个”按钮的会计。所以我替换了:
currState = (b1)?1:((b2)?2:((b3)?3:((b4)?4: 0));//逻辑按钮# (1-4)
:
btnNum = (b1)?1:((b2)?2:((b3)?3:((b4)?4: 0));//逻辑按钮#(1-4)(不支持倍数)currState = int(b1) + 2*int(b2) + 4*int(b3) + 8*int(b4);//一个组合按钮的状态
有了这些更改,我们的按钮测试应该完全符合预期。看看吧。Lesson_7。在o has all the above code integrated in.
步骤13:第8课-功能选择菜单
提出一个菜单操作来选择我们的四个函数之一
HW_Support_Demo ();Speed_Scan ();//最新版本React_Now();btnReporting ();
实施你的想法,在需要的时候从别人那里获得帮助。
添加关于已选择的功能的打印通知. . . .
下面是一个相当简单的方法示例,为这4个按钮中的每个按钮选择不同的功能。参见我在Lesson_8.ino中的实现
确保你理解到目前为止的一切;如果不把你不懂的东西弄清楚。
第14步:第8B课-制定逃生策略
我们的软件项目到目前为止……
您需要循环供电、重新加载或重置,然后选择一个不同的功能。
看看你是否能让每个功能活动在按下ever -4按钮超过几秒钟时都有办法退出到顶层菜单。BTW: checkout milis ();
……
我建议我们使用逃生!按“ESC”返回顶层菜单。在提供的Lesson_8中。在o code there is a new global variable “ESC” which is maintained in scanBtns() with:
if (btn4) ESC = (millis()-lastChg)>2000;else ESC = false;……lastChg = millis();
通常情况下,当发现要设置'ESC'时,函数将退出。如:
if (ESC)返回;
展开btnReporting()来报告ESC,给出其状态的文本和可视化指示,包括:
if (ESC && brightOne==0 && btn4)串行。print(" [ESC] ");brightOne = (ESC)?8: 0;if (ESC && btn1) break;//如果btn1也被按住,只让Btn报告。
放在'while'永久循环的末尾。
注意这里,在btnReporting()中,我们需要一个特殊的用例测试来转义,因为需要报告'ESC'本身。
首先从Lesson_8中复制btnReporting()和scanBtns()的代码。ino进入Lesson_8b。在o (or your version) and then ...
扩展其他函数以支持一种回退到菜单的方法,适当地添加类似于:
if (ESC)返回;
……
测试您的所有转义代码是否按预期工作。您可能会发现,由于操作特性的不同,每个函数内部的响应性是不一样的。您将听到一种独特的嗡嗡声,当执行转义时,屏幕将被清除。当你松开按钮时,你就会回到主菜单。
步骤15:第9课-使用Include库进行模块化
C库是一组预先制作好的函数,放在一个单独的文件中;它通过#include语句成为编译草图的一部分。
要了解如何使用包含的lib文件,请看下面的Arduino库示例:https://www.arduino.cc/en/Tutorial/ToneMelody
我们将创建一个包含(库)文件,其中包含适合于我们的迷你STEM平台的所有硬件支持函数。这样就可以独立于任何特定的活动实现(如草图)进行维护,并在许多活动中重用。注意,这个文件将由C函数组成,而不是像许多其他文件那样由c++对象组成。
在支持这个迷你Arduino游戏平台的函数库中进行第一次切割尝试。文件名是任意的,但可以是“my_lib.h”。
从Lesson_8b中包含的代码中移动硬件支持数据结构声明和函数。Ino到这个.h文件。同样在.h文件中创建一个函数来执行当前在Lesson_8b的setup()函数中的硬件操作。Ino(或相关代码)文件。
让您的项目代码在.ino文件中使用#include命令加载创建的硬件支持文件,并在适当的地方调用新的硬件设置函数。
然后确保包含这两个文件的新草图能像以前一样编译和工作。
……
看到Lesson_9。在o & Mini_STEM_Platform.h for sketch using the new library include file. There should only be minor differences in this and your implementations.
步骤16:第10课-创建一个新的迷你应用程序
让我们创建一个小应用程序的灵感来自“魔术8球”玩具。
我们可以从这段代码开始。它会在等待按下按钮时闪烁1号LED。在推送时给出一个随机响应。
//四个响应之一:Red: NO YEL: Maybe Grn: YES Blue: Try again void Magic_8_ball() {while (1) {clearDisp();而(Btn) scanBtns ();//等待前一个按钮被释放,同时(!Btn) {scanBtns();利特尔= (msCnt / 1000) % 2;//每秒切换第一个LED;} litLED = 2*random(1,5)+1;//选择并显示4种可能的结果}}
试试这个最小的应用程序(取代btnReporting)。如果有任何一行代码您没有认识到它的用途,更改或删除它,并观察行为的变化,直到您清楚为止。
做以下改进,让它更像玩具:
-当按钮被按下时等待,目的是让用户思考他们的查询。
-在揭晓答案前稍作停顿。
-点亮给定颜色的led灯,以显示更明确。
要做到这一点,替换:
litLED = 2*random(1,5)+1;//选择并显示4个可能的选项之一
:
而(Btn) scanBtns ();//等待当按钮被按下延迟(300 +随机(900));//让他们多等一会儿,就像在猜答案一样。//选择并显示4种颜色之一作为可能的答案
为了支持最后一项,我添加了一个本地子例程“showColor()”
// ================== 当地的支持功能 ===================== 空白调色精灵(字节颜色){/ / 1 - 4:光LED颜色设置1 - 4,5:所有clearDisp ();If (color==0)返回;如果(颜色= = 1 | |色= = 5)点燃[1]= [2]= true点燃;// set 1中的led if (color==2 || color==5) lit[3] = lit[4] = true;// set 2中的led if (color==3 || color==5) lit[5] = lit[6] = true;// set 3中的led if (color==4 || color==5) lit[7] = lit[8] = true;// set 4}
看看这个小应用程序的新功能。
……
当用户按住按钮时,有可能的答案显然浮了出来。考虑到这一点,我将一次点亮一组led灯,不按顺序点亮,中间穿插一个关闭状态。
替换:
而(Btn) scanBtns ();//当按钮按下时等待
:
while(Btn){//当按钮被按下时闪现潜在的答案scanBtns();if (ESC || btn4)返回;if (cnt != (msCnt/400)%8) {// flash led (1-3-4) clearDisp();cnt = (msCnt/400) %8;//如果((cnt%2)==0) color=0,则确定下一个颜色设置为亮或不亮;Else if (cnt>3) color=cnt-3;其他颜色=问;调色精灵(颜色);} refreshWait (1);}
加上这些声明:int问;字节颜色;放在函数的顶部。
研究这个新代码及其数学运算,并将其与结果行为关联起来。
……
子句(msCnt/400)%8)遍历0-7的值,每400毫秒更改一次。
“if ((cnt%2)==0) color=0;”将使led每隔400ms关闭一次。
当'cnt'是奇数,>3时,它将= 5或7,而color= 2或4。
当'cnt'是奇数但<=3时,'color'将是= 1或3。
这将使潜在的答案形成一种漂浮的模式。你见过魔术8号球上的反应漂浮在窗户边吗?
这可能是一种巧妙的数学应用,以得到我们想要的行为。但是,还有其他方法可以达到同样的效果,有利有弊。
由于要处理的可能性很少(只有8种),这样做可能会更好、更清楚
取代……If (cnt>3) color=cnt-3;
与……If (cnt==5 || cnt==7) color=cnt-3;
或与……If (cnt==5) color=2;Else if (cnt==7) color=4;
另一个选择是数据驱动和代码驱动的逻辑。如果代码过于复杂,无法轻松理解和了解其中的内容,那么使用数据表可能是一个不错的选择。我认为这是一个不错的选择。
替换所有的代码大胆的在上述方块中,在"/ /确定只有这句话:
Color = cycle[cnt];
加上一个本地数组声明:
静态字节ccycle[] = {0,1,0,3,0,2,0,4};
现在您可以很容易地看到所创建的效果。此外,这种实现往往不容易出现错误。即使可以使用数据数组,代码与数据数组驱动的权衡并不总是有利于使用数据而不是代码。特别是当数据集非常大或非常复杂时,少量的代码就可以完成这项工作,而且可能更容易理解过程的重要性。
在Lesson_10.ino中有三个Magic_8_ball的开发版本。它们可以被选择为活动1-3。
第17步:第11课-使用随机和真实世界的影响
现在,让我们使Magic_8_ball()函数更像玩具,使结果更基于真正的随机,同时也直接受到用户的影响。
“随机()”的本质
我们使用“random(1,5)”来获得1到4的“随机”数字。第一个参数是包含的下限,而第二个参数是不包含的上限。尝试我们的“Magic_8_ball”,正如上面所写的,注意给定结果的伪随机性。现在重新开始,注意半打左右的回复。重复这个动作几次。
……
从重新启动之后开始,您得到的结果总是相同的。这是因为'random()'返回的数字序列在统计上具有随机性质(伪随机)。但从任何给定的起点,在重启或'randomseed()'之后,random()的结果将是预先确定的和可重复的。这对于代码测试来说非常有用,但对于创造游戏玩法来说却并非如此。
在'setup()'中添加一行用于种子随机函数。参数使用任意整数,由您选择。例如:randomseed (1234);
像以前一样测试结果的顺序;您会发现顺序与以前不同,但它确实在每次重新启动后重复。对于任何给定的种子值,你会得到不同的结果,但它们是可重复的。
为了获得更多真实的不可预测的随机性,可以直接使用真实世界事件或模拟值,或者(通常更容易和更好)与’randomseed ()”。
添加现实世界的影响力。
拥有一个具有高分辨率的模拟输入,例如外部空气温度(最好是宇宙射频噪声),用于为随机函数播撒种子,将从调用random()函数得到一组几乎全新的随机数。从开放模拟输入得到的模拟值更容易获得,但不是可变的。有些人建议在setup()代码中这样做:
randomSeed (analogRead (0));
这肯定更好,但实际上只能提供十几个种子值。
使用micros()作为种子似乎是个好主意,但它的值在启动时初始化,setup()中的代码都需要重复大量的时间。因此,您将从micros()获得一个可重复的值。
我建议添加模拟输入在给定范围内变化所需的时间。是这样的:
//由于HW输入噪声(熵),等待一段伪随机时间,然后随机化aVal = val = analogRead(A0);while (abs(aVal-val)<=20) {val=analogRead(A0);} //期望模拟噪声(A0需要打开)randomSeed(micros()/4);// micros()分辨率为~ 4us
试试这个方法,把上面的代码放在设置的末尾。确保将'aVal'和'val'声明为整数。初始反应集不应重复(<0.1%)
添加用户影响力。
当你使用一个实际的magic 8球时,“预测性”答案直接依赖于用户,通过他们的动作和他们翻转球的时间点。为了添加这个功能特征,我们可以根据他们在陈述或考虑他们的查询时按下按钮的毫秒数来给出答案。从概念上讲,我们这样做:(如有需要,请参阅代码了解详细实现)
Ans =(毫秒按下按钮)%4;
可选的练习:
检查草图“Lesson_11.ino”的可执行代码的操作。先不要看代码。
……
注意,applet #1是我对Magic_8_ball()的扩展实现,当使用按钮2或3而不是按钮1时,它还支持独特的行为。响应也会一直保持,直到您按下另一个查询的按钮。充分利用它们来了解它们的本质。然后尝试编写代码来展示相同的行为。对于更大的挑战,请对applet #2 (rebtn2)执行同样的操作;然后参考我的Magic_8_ball_v2()函数。我希望你在努力中获得成功。
一群程序员(更不用说学生了)可能会用几种不同的方法来实现这一点。完成之后,看看我是如何完成btn2和bnt3的行为的。我确实创建了一个名为“setLEDs()”的实用程序来支持btn#2的功能,因为我认为这可能在其他地方有用。
第18步:第12课-用你的新能力表达你自己的创造力
将函数“btnReporting();”的使用替换为您自己设计的活动。
将你的代码、变量描述、功能特征等记录下来,以便日后对他人和自己都有好处。
……
步骤19:第13课-展开顶层菜单
如果我们想要支持并从4个以上的活动中进行选择,我们该如何处理菜单呢?
设计和实现一个顶层菜单方案来处理这个问题。
……
复习一下我所做的事。根据需要使用它,以充分理解这个顶级菜单的操作。注意的用法开关声明。
void loop() {// Top菜单级别,用于选择N个活动中的1个字节func, maxFunc;func = 1;while(1) {clearDisp();而(Btn) {buZZ (1);} //等待没有按钮maxFunc=6;//目前支持6个活动/游戏//指示可选功能1-6 dim[1]=dim[2]=dim[3]=dim[4]=dim[5]=dim[6]=true;brightOne =函数;refreshDisp ();而(Btn) {scanBtns ();refreshDisp();} //等待按钮释放while (! btn1) { refreshDisp(); delay(1); scanBtns(); if (btn2Pressed) brightOne = (brightOne==1)? maxFunc : brightOne-1; // -- move left if (btn3Pressed) brightOne = (brightOne%maxFunc) + 1; // ++ moves right if (btn4Pressed) brightOne = (brightOne%maxFunc) + 1; // allow most play with only 2 buttons (1&4) } func = brightOne; clearDisp(); while(Btn) scanBtns(); // wait for button release Serial.print(" FUNC: "); Serial.println(func); switch (func) { case 1: HW_Support_Demo(); // Demonstrates LED display and audio support functionality break; case 2: Speed_Scan_ver4(); // hit it on the right spot to speed things up to a winning max break; case 3: React_Now_ver2(); // Test your Reaction time break; case 4: SeeIt_TagIt(); // Capture and Release fleeting blips // btnReporting(); // exercises the buttons and LEDs, and reports via Serial // Or replace this with your own previously devised activity break; case 5: pingPong(); // Two person game of Ping-Pong break; case 6: Magic_8_ball(); // Give responses using PRNG along with Human Heuristics break; default: buZZ(1000); } } }
中,所附文件Lesson_13。在o, you'll find the above loop “Menu” code, and two functions I included, along with the original 4, to fill out a suit of 6 activities. Here is a brief description of them:
乒乓球()支持两人对战。为了来回击打球,当球在结束位置(最后一个LED)时,适当的桨必须击中它(按下按钮,btn1/btn4)。第一个失误的一方输,获胜一方的灯会闪烁。一轮拉力赛的获胜者总是下一场拉力赛的发球者。反弹后,球被来回击打的次数会反映在显示器上。顺便说一下,一个或多个外部触发按钮控制器可以通过连接到D16和/或D19和地面来制作和使用;参考资料见https://youtu.be/EZTxLNJKRbw
Magic_8_ball()使用模拟IN和random()。Magic-8球的反应(红色:NO YEL: Maybe Grn: YES Blue: Try again)是由用户直接决定的,通过他们在提问时按住按钮的时间长短。虽然不是有意为之。使用btn2作为1/6的结果,就像一个骰子,在游戏中很有用。使用btn3获得1 / 8的结果。
第20步:第14课-最后一课练习
在Instructables上查看“Menu_16Games”部分的游戏。下载游戏描述文档,仔细阅读并选择一款游戏。下载.ino项目代码。重做游戏函数使用我们刚刚创建的库包含文件。它所使用的支持功能可能是相似的,但并不完全相同,而且游戏在设计时考虑到了12个LED条显示,而不是8个LED条。因此,可能需要进行一些修改。
将游戏包括在我们的活动集合中,相应地扩展顶层菜单。测试、调试和修改代码以达到预期的功能。
可选额外学分
使用这个迷你STEM平台(HW + Lib.)创建自己的游戏(或其他applet/活动)。
请分享和张贴(或电子邮件我)你做什么。如果你对我的任何游戏或功能提出了改进,你也可以这么做。
在教学计划中可能会有不一致的地方,因为它制定了很长一段时间。我会更新文本,如果我发现任何,或有任何报告给我。
进一步的研究
在类似的代码项目中发现的其他研究领域:
eepmPushIt ();看到的://www.sledutah.com/id/Single-Line-LED-Displ..。步骤6和文件:Menu_16Games.odt和Menu_16Games.ino
中断处理: psyche_meters()参见第10步:软件“代码”//www.sledutah.com/id/Single-Line-LED-Displ..。
由于网站上传错误“内部服务器错误”,一些文件的文件名增加了额外的扩展名(.txt);在那个时候,这个可教导性被创造出来了。
同样的STEM平台,现在已经被用于智能莫尔斯电码训练器的基础。看到的:
//www.sledutah.com/id/Morse-Code-Trainer/

第二名
阀杆比赛
5的讨论
9个月前
感谢您的反馈。
关于迷你led游戏平台的使用,我确实觉得肢体互动是学习的关键。
我希望你有机会把它们组合在一起,看看和它们一起工作和玩耍是多么有趣。
我很喜欢我的工作。罗恩
11个月前
嗨RonM9,
干得好,解释得好;-)
只需考虑一下"while(1){}"因为它已经被循环完成了。
Arduino有时内存不足,最好保存:)
祝贺。
伊曼纽尔。
11个月前的回复
你说得对。谢谢你!
11个月前
非常好,很有教育意义!来自巴西的祝贺!保罗
11个月前的回复
非常感谢。我确实很努力。