65.9K
CodeProject 正在变化。 阅读更多。
Home

游戏开启:Intel® Edison 与 Xadow 可穿戴套件

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2016年2月18日

CPOL

15分钟阅读

viewsIcon

21807

游戏开启:Intel® Edison 与 Xadow 可穿戴套件

获取新的 Intel® IoT Developer Kit,这是一套完整的硬件和软件解决方案,使开发者能够使用 Intel® Galileo 和 Intel® Edison 板创建令人兴奋的新解决方案。访问 Intel® 物联网开发者中心

大多数人第一次看到 Intel® Edison 模块是在 Arduino* 扩展板上,它看起来太大了,不适合移动使用。这就是为什么许多开发者不认为 Edison 适用于紧凑型或可穿戴设备。

正如你在图片中看到的,Intel® Edison 模块非常小。但它并不容易使用,因为连接外围设备的引脚很小:Intel Edison 板上的 Hirose 连接器有 70 个引脚,而其长度仅约 1 厘米。解决这个问题的方法之一是使用 Seeed 提供的 Xadow Wearable Kit for Intel® Edison。该套件包含设计紧凑型可穿戴设备所需的所有适配器和小型传感器。

该套件包括具有不同功能的小型扩展板。所有板都通过柔性扁平电缆(FCC)连接。你可以将板级联连接,为你的设备提供必要的功能。

套件包含以下内容

套件中的每个组件都在本文档的“可穿戴设备套件组件”部分进行了描述。

    • 电池。
    • Xadow – Edison:插入 Intel® Edison 板的主连接器。
    • Xadow – Edison Programmer:一个模块,用于通过 USB 将 Intel® Edison 连接到 PC。
    • Xadow – Edison SD:一个连接 SD 存储卡的模块。
    • Xadow – OLED:128x64 单色 OLED 显示屏。
    • Xadow – Buzzer。
    • Xadow – Vibration Motor。
    • Xadow – Q Touch Sensor:触摸按钮。
    • Xadow – NFC:NFC 读卡器。
    • NFC 标签 – 三个 NFC 标签(图示一个)。
    • Xadow – 3Axis Accelerometer。
    • Xadow – Barometer BMP 180:气压计和温度计。
    • Digital RGB LED Flexi-Strip:一个带有五个可控 RGB LED 的条带。
    • FFC 电缆包。
    • 电源线(图中未显示)。

入门说明

在描述过程之前,应注意我在本项目中发现的一些特性和问题及其解决方案。首先,我强烈建议更新板固件

要检查当前版本,请使用以下命令

configure_edison –version

在撰写本文时,当前的板固件版本为 159。

我还建议更新所有已安装的库。你需要互联网连接才能完成此操作。

opkg update

opkg upgrade

本文中的所有代码示例都适用于 Arduino* IDE。Seeed 套件的开发者不为其他 IDE 提供示例。

我曾尝试使用 Intel® XDK for IoT 和 С++ 来使用该板,但未能成功。一个可能的原因是该板的电路与标准 Arduino 扩展板不同。I2C 接口也存在一些问题,加速度计的操作并不总是稳定。但是,它在游戏设置中运行良好,因为它是在 OLED 显示屏之后连接的。我未能让气压计/温度计板工作。

有时板与 Arduino* IDE 的连接失败,或者草图的编译和传输无法工作。在这种情况下,你应该终止在板上运行的草图

systemctl stop clloader

之后,清除 /sketch 文件夹,并关闭 PC 上所有正在运行的 Arduino* IDE。关闭 Intel® Edison 板(使用 shutdown now),然后按住 PWR 按钮直到 LED 点亮,重新打开它。

如果你需要 Edison 板在开机时运行草图,可以创建一个文件在启动时运行:创建一个 /etc/init.d 文件夹。在该文件夹中创建一个名为 automateSketch.sh 的文件,内容如下

#!/bin/sh

exec /sketch/sketch.elf /dev/ttyGS0 /dev/ttyGS0

创建并保存 automateSketch.sh 后,使其可执行

chmod +x automateSketch.sh

然后将 automateSketch.sh 添加到启动列表中

update-rc.d automateSketch.sh defaults

入门

你应该在 PC 上安装了所有 Intel Edison 驱动程序。与此套件中的模块的所有交互都通过 Arduino* 草图进行,所以如果你还没有安装,你应该安装 Arduino* IDE。你可以从 www.arduino.cc 下载。

要使用该板,你应该连接 Xadow-Edison Programmer 模块。请注意,两个 USB 端口都应该插入:一个用于供电,另一个连接到 Arduino* IDE。板上的开关应设置为“Device”位置。请在你的 Arduino* IDE 中使用 Boards Manager 选择 Intel Edison 板。

Edison 操作系统启动后(约 30 秒),在 PC 的设备管理器中找到虚拟端口号。

在 Arduino* IDE 中选择 Intel® Edison Virtual Com Port (COM25)。你可以使用 USB Serial Port (COM29) 连接到控制台,例如通过 Putty。

Arduino* 库

库是与模块交互所必需的。你可以在 github.com/Seeed-Studio/Xadow_Edison_Demos 下载库——作为一个 ZIP 文件。很可能,你无法一次性安装整个包,所以你需要在 IDE 菜单中添加包含所需库的文件夹。

连接模块

在插入任何模块之前,请断开 Intel Edison 的电源,以减少损坏组件的可能性。如果你尝试热插拔模块,草图将无法正确加载。

所有模块都使用柔性扁平电缆(FFC)连接。电缆的长度和宽度各不相同;电缆的宽度应与连接器匹配。所有电缆都插入蓝色面朝上,引脚朝下。板上有两种类型的连接器。第一种类型向上打开,像盖子一样。打开连接器,将电缆轻轻推入(约 3 毫米),然后关闭连接器。

第二种类型的连接器是滑动夹,不太方便。你应该从侧面撬开它,然后拉出约 1 毫米。小心点,我不小心弄断了一个引脚。稍微用力地将电缆插入尽可能深的地方(约 3 毫米)。然后稍微用力地推入连接器。电缆应牢固地固定在连接器中。

所有模块的连接器都位于相对的两端。所有模块和主板在一侧也有斜角。你应该以使这些斜角在同一侧的方式连接所有板。在下面的图片中,你可以看到它们都在左侧。

可穿戴设备套件组件

套件中的每个部分,如本文档开头所述,都可以根据它们的组合方式和编程方式来创建许多不同类型的可穿戴技术。

电池

此系统的电池是标准的 3.7 V、500 mAh 锂离子电池。

Xadow - Edison

这是用于连接 Edison 模块的主板,它比模块本身稍大。如果你将 Edison 模块插入其插槽,它会牢固地固定住,但为了更安全,你可以用 Arduino* 模块上的螺丝固定它。

该板有一个电池连接器,以及侧面的四个扩展板连接器。顶部的连接器用于 Edison Programmer 板,侧面的连接器用于传感器和执行器板,底部的连接器用于 SD 卡模块。

有两个按钮,PWR 和 FW_RCVR。按住 PWR 键可打开和关闭设备——按住 9 秒钟关闭,按住 2 秒钟打开。

电池连接器附近的一个小型绿色 LED 指示电源状态。如果它在闪烁,则通过 USB 供电。如果它常亮,则电池正在充电。如果它熄灭,则电池已充满。

这个板和电池是你让 Edison 工作所需的一切。

这个紧凑型设备的运行给我留下了深刻的印象:这个带电池的小板是一个微型 PC,具有真正的 Linux* OS,可以通过 WiFi* 访问。

Xadow - Edison Programmer

这是一个用于 PC 连接的板。你可以用它进行调试和从 PC 供电。它包含两个 Micro USB 连接器

  • UART 连接器通过 COM 端口连接到 PC 并提供电源。
  • Device/Host 连接器用于从 Arduino* IDE 操作板。有一个开关用于选择“Device”或“Host”模式。对于 Arduino*,选择“Device”。

Xadow - Edison SD

该板包含一个用于插入 SD 存储卡的连接器。它通过最宽的电缆连接到主板的底部插槽。

你可以在 /dev/mmcblk1 的设备目录中找到 SD 卡。

挂载时,请遵循标准的 Linux 过程。创建一个空文件夹,例如

mkdir /home/data

然后将卡挂载到此文件夹

mount /dev/mmcblk1   /home/data 

要在 Linux 启动时自动挂载卡,请将以下字符串添加到 /etc/fstab 文件

/dev/mmcblk1   /home/data     auto    auto 0 0

Xadow - OLED 12864

套件中包含的显示屏是一个 128x64 OLED 显示屏。

请参阅 Seeed 网站上的规格.

显示屏通过 I2C 接口连接。设备地址为 0x3C。

以下代码是一个屏幕显示示例

#include <Wire.h>
#include <SeeedOLED.h>

void setup()
 {
  Wire.begin();
  SeeedOled.init();  //initialze SEEED OLED display
  SeeedOled.clearDisplay();          //clear the screen and set start position to top left corner
  SeeedOled.setBrightness(255);
  SeeedOled.setNormalDisplay();      //Set display to normal mode (i.e non-inverse mode)
  SeeedOled.setPageMode();           //Set addressing mode to Page Mode
  SeeedOled.setTextXY(0,0);          //Set the cursor to Xth Page, Yth Column  
  SeeedOled.putString("Xadow and Edison"); //Print the String

  SeeedOled.setTextXY(7,0);          //Set the cursor to Xth Page, Yth Column  
  for(int k = 0; k < 128; k++)
  {
    SeeedOled.sendData(k);
  }
}

void loop() {
}

屏幕包含 8 行,每行 16 个字符,帧速率为每秒几帧。

我们使用了以下函数

  • init() – 初始化 Seeed OLED 框架并设置显示为正常模式。
  • clearDisplay() – 清除整个屏幕。在开始新内容或取消滚动后应使用此函数。此函数还将光标设置为左上角。
  • setBrightness(unsigned char Brightness) – 设置 OLED 显示屏的对比度。亮度可以是 0 - 255 之间的任何数字。
  • setNormalDisplay() – 将显示屏配置为正常模式(非反转)模式。
  • setPageMode() - 将显示屏配置为页面寻址模式。
  • setTextXY(0,0) - 将文本位置(光标)设置为 X 页,Y 列。X 可以是 0 - 7 之间的任何数字。Y 可以是 0 - 127 之间的任何数字。
  • putString(cont char *string) - 从 setTextXY(X,Y) 设置的当前地址指针开始,将字符串打印到 OLED 显示屏。
  • sendData(unsigned char Data) – 将一个字节发送到屏幕。

其他函数和更多信息可以在 www.seeedstudio.com/wiki/OLED_FrameSeeedOLED.h 文件中找到。

Xadow - Buzzer

蜂鸣器连接到引脚 11 和 13。你必须同时打开和关闭它们。要发出声音,你需要向两个引脚发送 0 或 1。

我从经验中了解到,最简单的方法是预设一个引脚为 1,然后更改另一个引脚的状态以发出声音。

以下代码是声音输出示例

void buzzerInit()
{
    pinMode(11,OUTPUT);
    pinMode(13,OUTPUT);
}

void buzzerOn()
{
    digitalWrite(11,HIGH);
    digitalWrite(13,HIGH); 
}

void buzzerOff()
{
    digitalWrite(11,LOW);
    digitalWrite(13,LOW);
}

void buzzerSignal(int t_ms)
{
    unsigned long cur = millis(); 
    while((millis()-cur) < t_ms )
    {
        buzzerOn();
        delayMicroseconds(150);
        buzzerOff();
        delayMicroseconds(150);
    }
}

void setup()	
{
    buzzerInit();	
    buzzerSignal(1000);
}
 
void loop()	 	
{	
}

由于播放是基于软件的,所以声音不是很清晰。最好使用脉冲宽度调制。值得一提的是,我为 Intel® XDK for IoT 和 С++ 制作的此草图的副本未能奏效——没有声音。

Xadow - Vibration Motor

你可以用与蜂鸣器相同的方式控制振动电机:通过将引脚 10 和 11 设置为相同的值来打开和关闭。这个示例代码展示了一种方法

// Xadow - Vibro
void vibroInit()
{
    pinMode(11,OUTPUT);
    pinMode(10,OUTPUT);
}

void vibroOn()
{
    digitalWrite(11,HIGH);
    digitalWrite(10,HIGH); 
}

void vibroOff()
{
    digitalWrite(11,LOW);
    digitalWrite(10,LOW);
}

void setup()	
{
    vibroInit();	
    vibroOn();
    delay(500);
    vibroOff();
}
 
void loop()	 	
{	
}

与蜂鸣器一样,你只需要控制一个引脚,在预设另一个引脚为 1 之后。

Xadow - Q Touch Sensor

该板在背面有三个触摸按钮,通过 I2C 连接;地址为 0x1B。

按钮非常灵敏。它们甚至可以通过几层纸或薄膜感应到触摸,所以你可以用图片覆盖按钮。

这里有一个示例代码,它返回按下按钮的编号

#include <Wire.h>
#include "Seeed_QTouch.h"

void setup()
{
    Serial.begin(9600);
    Wire.begin();
}

void loop()
{
    int tn = QTouch.touchNum();
    
    if(tn>=0)
    {
        Serial.print("KEY");
        Serial.print(tn);
        Serial.println(" touched");
    }
    
    delay(10);
}

Xadow - NFC

NFC 读卡器支持 I2C、SPI 和 UART 连接。工作频率为 13.56 MHz。它支持读写操作、ISO14443 Type A 和 Type B 协议以及 P2P。有一个带连接线的天线。更多信息请参阅 http://www.seeed.com/wiki/Xadow_-_NFC

套件包含三个可写入的空 NFC 标签。

此模块需要 NDEF、PN532、PN532_HSU、PN532_I2C 和 PN532_SPI 库。从通用 Seeed 示例库安装这些库。

要测试标签和读卡器,你可以使用 NDEF 库中的 readTag 示例程序。它读取标签数据并将其显示在控制台中。

套件中的标签有序列号。由于它们尚未格式化,它们在查询时返回以下输出

Tag is not NDEF formatted.
NFC Tag - Mifare Classic
UID 6E A5 0B 01

为了向标签写入数据,它们需要使用 NDEF 库中的 FormatTag 示例进行格式化。

要向标签写入数据,你可以使用 NDEF 库中的 WriteTag 示例。

这是读取标签数据的结果

NFC Tag - Mifare Classic
UID 5E B1 FB 01

NDEF Message 1 record, 28 bytes
  NDEF Record
    TNF 0x1 Well Known
    Type Length 0x1 1
    Payload Length 0x18 24
    Type 55  U
    Payload 00 49 6E 74 65 6C 20 45 64 69 73 6F 6E 20 77 69 74 68 20 58 61 64 6F 77  .Intel® Edison with Xadow
    Record is 28 bytes

Xadow - 3Axis Accelerometer

这是一个三轴加速度传感器。测量范围为 ±16 G。它通过 I2C 连接,地址为 0x53。该传感器安装在 ADXL345 芯片上。要使用它,请从套件中安装 DigitalAccelerometer_ADXL345 库。

有四种测量范围,具有不同的精度率和转换比:±2 g、±4 g、±8 g、±16 g。

芯片数据手册可以在这里找到:pdf1.alldatasheet.com/datasheet-pdf/view/254714/AD/ADXL345.html

数据以 16 位数字返回。库返回数字为 int 变量,所以你必须如下修改它们

void correct(int &a)
{
 if( a > 32767 )
     a = -(65536 - a);  
}

如果你使用 ±2g 范围,则根据数据手册,返回的值应除以 256。正如我提到的,我在加速度计方面遇到了一些问题。有时它无法被检测到,并且 Linux 控制台返回 I2C 错误。但是,当我将屏幕连接到主模块,然后将加速度计连接到屏幕时,操作是稳定的。也许这个传感器没有终端电阻。

Xadow - Barometer BMP 180

该板包含一个气压计和一个温度计。压力测量范围为 300–1100 hPa(即,海平面以上 -500 米至 +9000 米)。它通过 I2C 连接,地址为 0x77。

不幸的是,我未能使其工作,可能是由于 I2C 接口的一些错误。也许这是与加速度计相同的问题。我测试了其他 Xadow 套件,也未能奏效。

Xadow - Breakout

这是一个用于连接标准传感器的板。它具有以下引脚:3.3 V、SCL、SDA、TX0、GND、SCK、MOS1、MOS0、A5。还有两个用于连接标准“Seeed”模块的焊盘。一个标有“Serial”,另一个标有“I2C”。你可以连接 LED 条。

Digital RGB LED Flexi-Strip

这是一个带有 5 个 RGB WS2812B LED 的条带。LED 通过单线控制。

你需要焊接它们才能正确连接,如下图所示。使用 Xadow-Breakout 板。

数据是通过软件发送的,所以有时会出现数据传输错误,LED 可能会随机闪烁。

这是“Running light”程序

#include <Wire.h>
#include "Seeed_ws2812.h"

#define SIG_PIN 12
#define LEN_NUM 5

WS2812 strip = WS2812(LEN_NUM, SIG_PIN);

void setup() {
  strip.begin();
  //Serial.begin(115200);   
}

int pos = 0;

void loop() {  
  strip.WS2812SetRGB(pos,255,0,0);
  strip.WS2812Send();
  delay(100);
  
  strip.WS2812SetRGB(pos,0,0,0);
  strip.WS2812Send();
  delay(100);

  pos = (pos+1)%LEN_NUM;
}

创建游戏

我想用这个套件做一个东西,于是我有了制作游戏的想法。

在这个游戏中,LED 条被连接到游戏盒的外部。当 LED 闪烁时,玩家根据 LED 的颜色将盒子倾斜 45 度。如果中间的 LED 变绿,你应该向前倾斜盒子(远离你)。如果中间的 LED 变红,你应该向你倾斜盒子。如果最右边的 LED 变绿,向右倾斜盒子,但如果这个 LED 变红,向左倾斜盒子。

这款游戏的设计不仅是为了测试反应,更是为了让玩家在行动前思考。

要创建游戏,你需要以下组件

  • 陀螺仪
  • OLED 显示屏
  • LED 条
  • 用于连接 LED 条的扩展模块
  • 按钮板
  • 电池

首先,我将 Breakout 板连接到电池连接器的一侧,然后连接传感器按钮。在另一侧,我连接了屏幕,然后连接了陀螺仪。我通过将厚彩色纸板粘合在一起制作了盒子。然后我切开了一个屏幕的开口。我将按钮板固定在屏幕下方;你记得,按钮的灵敏度非常高。在正面,我在按钮上画了标志。

所有板都用透明胶带固定在纸层上,以避免损坏。

草图在 Linux 中自动启动。

要开始游戏,请按住主模块上的 PWR 按钮约 9 秒钟。要关闭游戏,请按住相同的按钮 3 秒钟。

游戏启动后,将出现一个菜单,在该菜单中你可以开始游戏(按 A 按钮)或显示帮助(按 B 按钮)。要关闭帮助屏幕,请按箭头按钮。

游戏包含五个回合。在每个回合中,一个随机 LED 会亮起,你必须将盒子倾斜到某个方向。如果你做得对,屏幕将显示“You Win!”。如果你失败或时间耗尽,屏幕将显示“You Lose!”。

你可以观看示例视频 https://www.youtube.com/watch?v=1Tjff7wDPIQ

所有的游戏代码都在一个文件中。我试图使其尽可能简单,以便于分析。

游戏草图代码

#include <Wire.h>
#include <Seeed_ws2812.h>
#include <SeeedOLED.h>
#include <Seeed_QTouch.h>
#include <ADXL345.h>

// game state
const int stateMenu = 1;
const int stateCount = 3;
const int stateHelp = 4;

// buttons
const int keyBack = 0;
const int keyA = 1;
const int keyB = 2;

// LED strip
const int ledSigPin =  12;
const int numLed = 5;

// answers
const int answerLeft = 1;
const int answerRight = 2;
const int answerUp = 3;
const int answerDown = 4;

const int colorGreen = 1;
const int colorRed = 2;

const int numLevels = 6;
const int answerID = 5;

const int angleScale = 100;
const int angleReact = 100;//tangent of actuating angle * angleScale

int numWins;// number of wins
int numLosts;// number of losses
int gameState;// game state

const int numSets = 5;// number of rounds in a game

// level coding
int levels[numLevels][numLed+1] = {  {colorGreen,0,0,0,0,answerLeft},
                             {colorRed,0,0,0,0,answerRight},
                             {0,0,0,0,colorGreen,answerRight},
                             {0,0,0,0,colorRed,answerLeft},
                             {0,0,colorGreen,0,0,answerUp},
                             {0,0,colorRed,0,0,answerRight}};
// correct answer
int rightAnswer;

WS2812 strip = WS2812(numLed, ledSigPin);
ADXL345 adxl; 

// current game level
int gameLevel;

// initialization of accelerometer
void initAccel()
{
  adxl.powerOn();

  //set activity/ inactivity thresholds (0-255)s
  adxl.setActivityThreshold(75); //62.5mg per increment
  adxl.setInactivityThreshold(75); //62.5mg per increment
  adxl.setTimeInactivity(10); // how many seconds of no activity is inactive?
 
  //look of activity movement on this axes - 1 == on; 0 == off 
  adxl.setActivityX(1);
  adxl.setActivityY(1);
  adxl.setActivityZ(1);
 
  //look of inactivity movement on this axes - 1 == on; 0 == off
  adxl.setInactivityX(1);
  adxl.setInactivityY(1);
  adxl.setInactivityZ(1);
 
  //look of tap movement on this axes - 1 == on; 0 == off
  adxl.setTapDetectionOnX(0);
  adxl.setTapDetectionOnY(0);
  adxl.setTapDetectionOnZ(1);
 
  //set values for what is a tap, and what is a double tap (0-255)
  adxl.setTapThreshold(50); //62.5mg per increment
  adxl.setTapDuration(15); //625us per increment
  adxl.setDoubleTapLatency(80); //1.25ms per increment
  adxl.setDoubleTapWindow(200); //1.25ms per increment
 
  //set values for what is considered freefall (0-255)
  adxl.setFreeFallThreshold(7); //(5 - 9) recommended - 62.5mg per increment
  adxl.setFreeFallDuration(45); //(20 - 70) recommended - 5ms per increment
 
  //setting all interrupts to take place on int pin 1
  //I had issues with int pin 2, was unable to reset it
  adxl.setInterruptMapping( ADXL345_INT_SINGLE_TAP_BIT,   ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_DOUBLE_TAP_BIT,   ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_FREE_FALL_BIT,    ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_ACTIVITY_BIT,     ADXL345_INT1_PIN );
  adxl.setInterruptMapping( ADXL345_INT_INACTIVITY_BIT,   ADXL345_INT1_PIN );
 
  //register interrupt actions - 1 == on; 0 == off  
  adxl.setInterrupt( ADXL345_INT_SINGLE_TAP_BIT, 1);
  adxl.setInterrupt( ADXL345_INT_DOUBLE_TAP_BIT, 1);
  adxl.setInterrupt( ADXL345_INT_FREE_FALL_BIT,  1);
  adxl.setInterrupt( ADXL345_INT_ACTIVITY_BIT,   1);
  adxl.setInterrupt( ADXL345_INT_INACTIVITY_BIT, 1);
}

void initGame()
{
  SeeedOled.clearDisplay();
  SeeedOled.setNormalDisplay();
  SeeedOled.setPageMode(); 

  switchToMenu();
}

void setup()
{
    strip.begin();
    SeeedOled.init();
    initAccel();
    initGame();
}

void cleanLED()
{
  for( int led = 0; led < numLed; led++ )
      strip.WS2812SetRGB(led,0,0,0); 
}

void updateLED()
{
  strip.WS2812Send();
}

void drawMenu()
{
  SeeedOled.clearDisplay();
  SeeedOled.setTextXY(0,2);
  SeeedOled.putString("Edison Game");

  SeeedOled.setTextXY(2,1);
  SeeedOled.putString("A - Start");

  SeeedOled.setTextXY(4,1);
  SeeedOled.putString("B - Help"); 
}

void drawHelp()
{
  SeeedOled.clearDisplay();
  
  char *messages[] = {    "Center green -",
    "tilt forward." ,
    "Center red -" ,
    "tilt backward.", 
    "Green edge -" ,
    "tilt same side." ,
    "Red edge - tilt",
    "other side."
 };

   for( int k = 0; k < 8; k++ )
   {
      SeeedOled.setTextXY(k,0);
      SeeedOled.putString(messages[k]);
   }
}

void makeNewLevel()
{
    gameLevel = rand() % numLevels;
    rightAnswer = levels[gameLevel][answerID];
}

void showGameStart()
{
  SeeedOled.clearDisplay();
  SeeedOled.setTextXY(0,0);
  SeeedOled.putString("Press Start");
}

int getKeys()
{
    int tn = QTouch.touchNum();
    return tn;   
}

int haveTime = 20;

void showGameLevel()
{
  for( int k = 0; k < numLed; k++ )
  {
     int color = levels[gameLevel][k];
     switch(color)
     {
         case colorRed  : strip.WS2812SetRGB(k,255,0,0); break;
         case colorGreen: strip.WS2812SetRGB(k,0,255,0); break;
         default        : strip.WS2812SetRGB(k,0,0,0);
     }
  }

  updateLED();
}

void switchToSets()
{
  numWins = 0;
  numLosts = 0;
  switchToPlay();
}

//------------------------------------

void switchToPlay()
{
  cleanLED();
  updateLED();

  SeeedOled.clearDisplay();
  SeeedOled.setTextXY(3,3);
  SeeedOled.putString("Get ready!");

  int waitTime = 2000 + (rand()%4)*500;

  delay(waitTime);

  makeNewLevel();
  
  SeeedOled.setTextXY(3,3);
  SeeedOled.putString("          ");

  haveTime = 100;
  gameState = stateCount;
}

void doPlay()
{
  if( haveTime >= 0 )
  {
    SeeedOled.setTextXY(3,1);
    char str[100];
    sprintf(str,"-- TILT NOW --");
    SeeedOled.putString(str);

    SeeedOled.setTextXY(5,6);
    sprintf(str,"%d  ",haveTime);
    SeeedOled.putString(str);

    showGameLevel();
    
    int answerID = getAnswerID();

    haveTime--;
    
    if( answerID !=0 || haveTime < 0)
    {
      char *message;
      if( answerID != rightAnswer || haveTime < 0)
      {
        numLosts++;
        message = "You lose!";
      }
      else
      {
        numWins++;
        message = "You win!";
      }

      cleanLED();
      updateLED();

      SeeedOled.clearDisplay();
      SeeedOled.setTextXY(3,4);
      SeeedOled.putString(message);

      delay(1000);

      if( numWins + numLosts == numSets )
      {
        switchToMenu();
      }
      else
      {
        switchToPlay();
      }
    }
  }
}

//-----------------------

void switchToHelp()
{
    drawHelp();
    gameState = stateHelp;

    cleanLED();
    updateLED();
}

void doHelp()
{
  cleanLED();
  updateLED();
  
  int key = getKeys();
  
  if( key == keyBack )
      switchToMenu();  
}

//-----------------------
void switchToMenu()
{
  drawMenu();
  gameState = stateMenu;

  cleanLED();
  updateLED();
}

void doMenu()
{
  int key = getKeys();
  
  if( key == keyA )
      switchToSets();  

    if( key == keyB )
      switchToHelp();  
}
//-----------------------

void correct(int &a)
{
 if( a > 32767 )
     a = -(65536 - a);  
}

int  getAnswerID()
{
  int x,y,z;  
  adxl.readXYZ(&x, &y, &z);

  correct(x);
  correct(y);
  correct(z);

  int v1 = angleReact;
  if( z != 0 )
      v1 = y*angleScale/z;

  if( v1 > angleReact )
    return answerRight;

  if( v1 < -angleReact )
    return answerLeft;

  int v2 = angleReact;

  if( z != 0 )
      v2 = x*angleScale/z;

  if( v2 > angleReact )
    return answerUp;

  if( v2 < -angleReact )
    return answerDown;

    return 0;
}

void gameStep()
{
  switch(gameState)
  {
    case stateCount: doPlay();break;
    case stateMenu:  doMenu();break;
    case stateHelp:  doHelp();break;
  }
}

void loop()
{
    gameStep();
    delay(10);
}

关于作者

Valery Mosyagin 是英特尔官方软件创新者。他居住在俄罗斯下诺夫哥罗德。他拥有数学和计算机科学硕士学位。他曾在 OpenCV 团队在英特尔工作了 6 年,然后移居日本,在那里他曾在脑研究所开发用于生物实验的软件,之后,开发用于网络流量分析以及无线电覆盖和传播软件。他长期从事儿童编程课程的教学。他的兴趣领域广泛:虚拟现实、游戏开发、微控制器、物联网。

© . All rights reserved.