
大多数人第一次看到英特尔Edison模块安装在 Arduino* 扩展板上时,会认为它太大了,无法移动使用。因此许多人认为Edison在紧凑型或可穿戴设备上不会发挥太大的作用。
如下图所示,英特尔Edison模块的体积非常小。但它的用法并不简单,因为用来连接外设的针脚极其的小:英特尔 Edison 开发板上的 Hirose 有 70 个针脚,其长度仅为 1 厘米。使用 Seeed 提供的面向英特尔 Edison 的 Xadow 可穿戴套件可以完全解决这一问题。该套件包含设计紧凑型可穿戴设备时需要的所有适配器和小型传感器。
它包含具有不同特性的各种小型扩展板。所有扩展板可以用一根柔性扁平电缆 (FFC) 连接起来。你可以用菊花链连接扩展板,为设备提供所需的特性。
套件所包含的内容如下所示:

本文 “可穿戴套件组件” 部分对这些组件进行了详细介绍。
1、 电池。
2、Xadow – Edison:插入英特尔® Edison 开发板的主要连接器。
3、Xadow – Edison 编程器:通过 USB 连接英特尔® Edison 和 PC 的模块。
4、Xadow – Edison SD:连接 SD 内存卡的模块。
5、Xadow – OLED: 128x64 单色 OLED 显示屏。
6、Xadow – 蜂鸣器。
7、Xadow – 振动电机。
8、Xadow – Q 触摸传感器:触摸按钮。
9、Xadow – NFC: NFC 读卡器。
10、NFC 标签 – 3 个 NFC 标签(图中显示了 1 个)。
11、Xadow – 3 轴加速计。
12、Xadow – 气压计 BMP 180:气压计和温度计。
13、数字 RGB LED Flexi-Strip:带有 5 个受控 RGB LED 的条带。
14、整套 FFC 电缆。
15、电源线(图中未显示)。
简介
开始描述流程之前,我觉得有必要跟大家阐述一下我在处理该项目时所发现的一些特殊性、问题及其解决方法。首先,强烈建议更新开发板固件。
如欲查看当前版本,请使用以下命令:
configure_edison –version
截至本文撰写时,当前开发板固件的版本是 159。
还建议更新所有安装的库。更新时需要连接互联网。
opkg update
opkg upgrade
本文的所有代码示例均面向 Arduino* IDE。 Seeed 套件的开发人员没有提供面向其他 IDE 的示例。
我尝试过将该开发板用于面向物联网和 С++ 的英特尔® XDK,但并未成功。原因可能是开发板电路与标准 Arduino 扩展板 的不同。I2C 接口也存在一些问题,而且加速计运行有时不太稳定。不过,在游戏设置中,它在 OLED 显示屏之后连接,运行 比较顺畅。无法成功运行气压计/温度计开发板。
有时无法连接开发板和 Arduino* IDE,或者无法编译或传输 sketch。在这种情况下,需要终止 sketch 在开发板上的运行 :
systemctl stop clloader
然后清空 /sketch 文件夹,并关闭所有在 PC 上运行的 Arduino* IDE。(使用“立即关闭”)关闭英特尔® Edison 开发板,并通过长按 PWR 按钮直至 LED 变亮来重新打开开发板。
电源接通后,如果需要 Edison 开发板运行 sketch,可以创建在启动时运行的文件: 创建文件夹 /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 上安装所有英特尔 Edison 驱动程序。与该套件的模块之间的所有交互均通过 Arduino* sketche 执行,因此需 要安装 Arduino* IDE。可以从 www.arduino.cc 下载。
如欲操作开发板,需要连接 Xadow-Edison 编程器模块。请注意,两个 USB 端口都已插入:一个用于提供电源,一个用于 连接 Arduino* IDE。开发板上的开关应设在 "Device" 位置。请使用 Boards Manager 在 Arduino* IDE 中选择 英特尔 Edison 开发板。
Edison 操作系统启动后(大约 30 秒),在 PC 的 Device Manager 中查找虚拟端口的编号。

在 Arduino* IDE 中选择英特尔® Edison 虚拟 Com 端口 (COM25)。 可以使用 USB 串行端口 (COM29) 连接控制台,比如通 过 Putty。
Arduino* 库
与模块交互时,库必不可少。 可以从 github.com/Seeed-Studio/Xadow_Edison_Demos 下载库(单个 ZIP 文件)。可能无法一次 性安装整个程序包,因此需要在 IDE 菜单中添加包含所需库的文件夹。
连接模块
插入模块之前,请关闭英特尔 Edison 的电源,以降低损坏组件的几率。如果尝试热插拔模块,sketch 应停止加载。
用柔性扁平电缆 (FFC) 连接所有模块。电缆的长度、宽度各不相同;电缆宽度必须与连接器相匹配。所有电缆插入时,蓝 色边朝上,针脚朝下。 开发板上的连接器分为两种。第一种是向上打开的连接器,像一个盖子。打开连接器,轻轻插入电缆 (约 3 毫米),然后关闭连接器。

第二种连接器是一个滑动板夹,使用起来不太方便。需要撬开板夹的两端,向外拔出 1 毫米。请小心操作,我曾不小心折断了一个针脚。稍微用力往里插电缆(约 3 毫米)。然后将连接器按下去。电缆必须牢牢固定在连接器上。

所有模块的另一端都有连接器。模块和主板的一边还有斜角。开发板连接后,这些斜角应该在同一边。如下图所示,斜角 都在左边。

可穿戴套件组件
正如本文开头所述,套件的每个部件都可用来创建不同类型的可穿戴技术(取决于你如何组合与编程)
电池
该系统的电池为标准的 3.7 V、500 mAh 锂电池。

Xadow - Edison

它是用来连接 Edison 模块的主板,比模块稍大一些。如果将 Edison 模块插入其插槽,连接的非常牢固,不过为了提高安 全性,可以将它连接至 Arduino* 模块的螺钉。
开发板有一个针对电池的连接器和四个针对扩展板的连接器。上部的连接器用于连接 Edison 编程器开发板、两边的连接器 用于连接传感器和制动器开发板,底部的连接器用于连接 SD 卡模块。
还有两个按钮:PWR 和 FW_RCVR。长按 PWR 可以打开和关闭设备 — 长按 9 秒关闭设备,长按 2 秒打开设备。
电池连接器旁的绿色 LED 表示电源状态。闪烁表示通过 USB 供电。常亮表示正在充电。关闭表示充电完成。
开发板和电池是保持 Edison 运行的必要条件。

这款紧凑型设备的功能给我留下了非常深刻的印象:小型开发板和电池就是一台采用真实 Linux* 操作系统、可通过 WiFi* 访问的迷你 PC。
Xadow - Edison 编程器

这个开发板用于连接 PC。可以用于调试和通过 PC 提供电源。它包含两个 Micro USB 连接器:
1、UART 连接器通过 COM 端口连接 PC 并提供电源。
2、Device/Host 连接器运行 Arduino* IDE 的开发板。 还有一个用于选择 "Device" 或 "Host" 模式的开关。 就
3、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 显示屏。

该显示屏通过 I2C 接口连接。 设备地址为 0x3C。
以下代码为屏幕显示示例:
01 #include
02 #include
03
04 void setup()
05 {
06 Wire.begin();
07 SeeedOled.init(); //initialze SEEED OLED display
08 SeeedOled.clearDisplay(); //clear the screen and set start position to top left corner
09 SeeedOled.setBrightness(255);
10 SeeedOled.setNormalDisplay(); //Set display to normal mode (i.e non-inverse mode)
11 SeeedOled.setPageMode(); //Set addressing mode to Page Mode
12 SeeedOled.setTextXY(0,0); //Set the cursor to Xth Page, Yth Column
13 SeeedOled.putString("Xadow and Edison"); //Print the String
14
15 SeeedOled.setTextXY(7,0); //Set the cursor to Xth Page, Yth Column
16 for(int k = 0; k 128; k++)
17 {
18 SeeedOled.sendData(k);
19 }
20 }
21
22 void loop() {
23 }
屏幕包含 8 排,每排 16 个字符,帧速率为每秒数帧。
我们使用了以下函数:
1、init() – 初始化 Seeed OLED 帧,并将显示屏设置为 Normal 模式。
2、clearDisplay() – 清空整个屏幕。 应在重新打开之前或滚动取消激活之后使用。 该函数还可以将光标设 置在左上角。
3、setBrightness(unsigned char Brightness) – 设置 OLED 显示屏的对比度。 亮度范围是 0 - 255。
4、setNormalDisplay() – 将显示屏设置为 mode(non-inverse) 模式。
5、setPageMode() - 将显示屏设置为页面寻址模式。
6、setTextXY(0,0) - 将文本位置(光标)设置为 Xth Page,Yth Column。 X 范围为 0 - 7。 Y 范围为 0 - 127。
7、putString(cont char *string) - 从 setTextXY(X,Y) 设置的当前地址-指示器开始将字符串印在 OLED 屏幕上。
8、sendData(unsigned char Data) – 将一字节发送至屏幕。
如欲了解其他函数和信息,请访问 www.seeedstudio.com/wiki/OLED_Frame 和 SeeedOLED.h 文件。
Xadow - 蜂鸣器

该蜂鸣器连接至针脚 11 和 13。 这两个针脚必须同时关闭和打开。 向它们发送 0 或 1,可以使蜂鸣器发出声音。
根据我的经验,最简单的方法是将其中一个针脚预设值为 1,然后改变另一个针脚的状态,就可以使蜂鸣器发出声音。
以下代码为声音输出示例:
01 void buzzerInit()
02 {
03 pinMode(11,OUTPUT);
04 pinMode(13,OUTPUT);
05 }
06
07 void buzzerOn()
08 {
09 digitalWrite(11,HIGH);
10 digitalWrite(13,HIGH);
11 }
12
13 void buzzerOff()
14 {
15 digitalWrite(11,LOW);
16 digitalWrite(13,LOW);
17 }
18
19 void buzzerSignal(int t_ms)
20 {
21 unsigned long cur = millis();
22 while((millis()-cur) t_ms )
23 {
24 buzzerOn();
25 delayMicroseconds(150);
26 buzzerOff();
27 delayMicroseconds(150);
28 }
29 }
30
31 void setup()
32 {
33 buzzerInit();
34 buzzerSignal(1000);
35 }
36
37 void loop()
38 {
39 }
由于是基于软件进行的回放,因此声音不太清晰。最好使用脉宽调制。值得一提的是,为面向物联网和 С++ 的英特尔® XDK 制作的 sketch 副本无法工作 — 没有发出声音。
Xadow - 振动电机

控制振动电机的方法可以与蜂鸣器相同:通过将针脚 10 和 11 设置为相同的值来打开和关闭振动电机。 以下示例代码为控 制方法:
01 // Xadow - Vibro
02 void vibroInit()
03 {
04 pinMode(11,OUTPUT);
05 pinMode(10,OUTPUT);
06 }
07
08 void vibroOn()
09 {
10 digitalWrite(11,HIGH);
11 digitalWrite(10,HIGH);
12 }
13
14 void vibroOff()
15 {
16 digitalWrite(11,LOW);
17 digitalWrite(10,LOW);
18 }
19
20 void setup()
21 {
22 vibroInit();
23 vibroOn();
24 delay(500);
25 vibroOff();
26 }
27
28 void loop()
29 {
30 }
与蜂鸣器一样,(将另一针脚预设为 1 之后)仅需控制一个针脚。
Xadow - Q 触摸传感器

该开发板背面有三个触摸按钮,通过 I2C 接口连接;地址为 0x1B。
按钮非常敏感。 它们甚至还可以通过几层纸或膜感知触摸,因此可以用照片盖住按钮。
以下示例代码返回了所按按钮的编号:
01 #include
02 #include "Seeed_QTouch.h"
03
04 void setup()
05 {
06 Serial.begin(9600);
07 Wire.begin();
08 }
09
10 void loop()
11 {
12 int tn = QTouch.touchNum();
13
14
if(tn>=0)
15 {
16 Serial.print("KEY");
17 Serial.print(tn);
18 Serial.println(" touched");
19 }
20
21 delay(10);
22 }
Xadow - NFC

NFC 读卡器支持 I2C、SPI 和 UART 连接。运行频率为 13.56 MHz。它支持读写操作、ISO14443 Type A 和 Type B 协议 ,以及 P2P。 还有一根带有连接线的天线。 如欲了解更多信息,请访问 http://www.seeedstudio.com/wiki/Xadow_-_NFC
套件包含 3 个空白可写入 NFC 标签。

该模块要求安装 NDEF、PN532、PN532_HSU、PN532_I2C 和 PN532_SPI 库。 安装通用 Seeed 示例库提供的这些库。
如欲测试标签和读卡器,可以使用 NDEF 库中的示例程序 readTag。 它可阅读标签的数据,并将其显示在控制台中。
套件的标签有序列号。 由于还没有格式化,查询时会返回以下输出:
1 Tag is not NDEF formatted.
2 NFC Tag - Mifare Classic
3 UID 6E A5 0B 01
经 NDEF 库中的 FormatTag 示例完成格式化后,才能将数据写入标签。
如欲将数据写入标签,可以使用 NDEF 库中的 WriteTag 示例。
如下所示为从标签读取数据的结果:
01 NFC Tag - Mifare Classic
02 UID 5E B1 FB 01
03
04 NDEF Message 1 record, 28 bytes
05 NDEF Record
06 TNF 0x1 Well Known
07 Type Length 0x1 1
08 Payload Length 0x18 24
09 Type 55 U
10 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
11 Record is 28 bytes
Xadow - 3 轴加速计

它是一个3轴加速传感器。 测量范围为±16G,通过 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 变量的形式返回数字,因此需要作出如下调整:
1 void correct(int &a)
2 {
3 if( a > 32767 )
4 a = -(65536 - a);
5 }
如果适用 ±2g 范围,按照数据表,返回值需要除以 256。 如前所述,我在使用加速计时遇到过一些问题。 有时检测不到 ,有时Linux 控制台返回I2C 错误。不过,将屏幕连接至主模块,然后将加速计连接至屏幕时,运行比较稳定。 也许该传 感器没有终端电阻。
Xadow - 气压计 BMP 180

该开发板包含一个气压计和一个温度计。压力测量范围为 300–1100 hPa(比如 -500m至海拔 +9000m)。 它通过 I2C 接口连接,使用 0x77 地址。
遗憾的是,我无法运行该开发板,可能是因为 I2C 接口出现了错误。 出现的问题可能与加速计的相同。 我测试了其他 Xadow 套件,也无法工作。
Xadow - Breakout

该开发板用来连接标准传感器。它包含以下针脚: 3.3 V,SCL,SDA,TX0,GND,SCK,MOS1,MOS0,A5。 还有两个供标准 "Seeed" 模块插入连接器的垫片。一个标记为 "Serial",另一个标记为 "I2C"。可以连接 LED条。
数字 RGB LED Flexi-Strip

条带上包含 5 个RGB WS2812B LED。 只需一根线就可以控制这些LED。
需要进行焊接,以牢固地连接它们,如下图所示。 使用 Xadow-Breakout 开发板。


数据由软件发送,因此有时会出现数据传输错误,导致 LED 可能随机闪烁。
以下为 "Running light" 程序:
01 #include
02 #include "Seeed_ws2812.h"
03
04 #define SIG_PIN 12
05 #define LEN_NUM 5
06
07 WS2812 strip = WS2812(LEN_NUM, SIG_PIN);
08
09 void setup() {
10 strip.begin();
11 //Serial.begin(115200);
12 }
13
14 int pos = 0;
15
16 void loop() {
17 strip.WS2812SetRGB(pos,255,0,0);
18 strip.WS2812Send();
19 delay(100);
20
21 strip.WS2812SetRGB(pos,0,0,0);
22 strip.WS2812Send();
23 delay(100);
24
25 pos = (pos+1)%LEN_NUM;
26 }
创建游戏
在想着如何使用这个套件时,我想到了创建游戏的主意。
在游戏中,LED 条连接至游戏盒子的外侧。 随着 LED的亮起和关闭,玩家可以根据LED的颜色将盒子朝某个方向倾斜 45 度。如果中间的 LED 变绿,应将盒子向前倾斜(远离你的方向)。 如果中间的 LED 变红,应将盒子朝你本人的方向倾斜。 如果最右边的 LED 变绿,将盒子朝右倾斜,但如果变红,则朝左倾斜。
设计该游戏的目的不仅是测试反应,而且可以让玩家先思考,再行动。

如欲创建游戏,需要以下组件:
1、陀螺仪
2、OLED 显示屏
3、LED 条
4、连接条带的扩展模块
5、按钮板
6、电池
首先在电池连接器的一侧连接 Breakout 开发板和传感器按钮。 在另一侧连接屏幕和陀螺仪。 我把几张较厚的彩色纸板粘 贴起来,制成盒子。 然后面向屏幕剪出一个开口。 在屏幕下方连接按钮板;大家应该还记得,按钮的敏感度非常高。 在正面 的按钮上方画上符号。
将纸上方的所有开发板用透明胶带连接起来,以避免损坏。

sketch 开始在 Linux中自动运行。
如欲启动游戏,长按主模块上的 PWR 按钮约 9 秒钟。 如欲关闭游戏,同样按住该按钮越 3 秒钟。
游戏启动时,会出现一个菜单,你可以在菜单中开始游戏(按下按钮 A)或显示 “帮助”(按下按钮 B)。 如 欲关闭 “帮助” 屏幕,按下箭头按钮。

该游戏包括五个回合。 每一个回合亮起一个随机 LED,你需要将盒子朝某个方向倾斜。 如果倾斜方向正确,屏幕将显示 “你赢了!” 如果错误或超时,屏幕将显示 “你输了!”
如欲观看示例视频,请访问 https://www.youtube.com/watch?v=1Tjff7wDPIQ
所有游戏代码都在一个文件中。 我已尽量简化,因此分析起来非常简单。
游戏 sketch 代码
001 #include
002 #include
003 #include
004 #include
005 #include
006
007 // game state
008 const int stateMenu = 1;
009 const int stateCount = 3;
010 const int stateHelp = 4;
011
012 // buttons
013 const int keyBack = 0;
014 const int keyA = 1;
015 const int keyB = 2;
016
017 // LED strip
018 const int ledSigPin = 12;
019 const int numLed = 5;
020
021 // answers
022 const int answerLeft = 1;
023 const int answerRight = 2;
024 const int answerUp = 3;
025 const int answerDown = 4;
026
027 const int colorGreen = 1;
028 const int colorRed = 2;
029
030 const int numLevels = 6;
031 const int answerID = 5;
032
033 const int angleScale = 100;
034 const int angleReact = 100;//tangent of actuating angle * angleScale
035
036 int numWins;// number of wins
037 int numLosts;// number of losses
038 int gameState;// game state
039
040 const int numSets = 5;// number of rounds in a game
041
042 // level coding
043 int levels[numLevels][numLed+1] = { {colorGreen,0,0,0,0,answerLeft},
044 {colorRed,0,0,0,0,answerRight},
045 {0,0,0,0,colorGreen,answerRight},
046 {0,0,0,0,colorRed,answerLeft},
047 {0,0,colorGreen,0,0,answerUp},
048 {0,0,colorRed,0,0,answerRight}};
049 // correct answer
050 int rightAnswer;
051
052 WS2812 strip = WS2812(numLed, ledSigPin);
053 ADXL345 adxl;
054
055 // current game level
056 int gameLevel;
057
058 // initialization of accelerometer
059 void initAccel()
060 {
061 adxl.powerOn();
062
063 //set activity/ inactivity thresholds (0-255)s
064 adxl.setActivityThreshold(75); //62.5mg per increment
065 adxl.setInactivityThreshold(75); //62.5mg per increment
066 adxl.setTimeInactivity(10); // how many seconds of no activity is inactive?
067
068 //look of activity movement on this axes - 1 == on; 0 == off
069 adxl.setActivityX(1);
070 adxl.setActivityY(1);
071 adxl.setActivityZ(1);
072
073 //look of inactivity movement on this axes - 1 == on; 0 == off
074 adxl.setInactivityX(1);
075 adxl.setInactivityY(1);
076 adxl.setInactivityZ(1);
077
078 //look of tap movement on this axes - 1 == on; 0 == off
079 adxl.setTapDetectionOnX(0);
080 adxl.setTapDetectionOnY(0);
081 adxl.setTapDetectionOnZ(1);
082
083 //set values for what is a tap, and what is a double tap (0-255)
084 adxl.setTapThreshold(50); //62.5mg per increment
085 adxl.setTapDuration(15); //625us per increment
086 adxl.setDoubleTapLatency(80); //1.25ms per increment
087 adxl.setDoubleTapWindow(200); //1.25ms per increment
088
089 //set values for what is considered freefall (0-255)
090 adxl.setFreeFallThreshold(7); //(5 - 9) recommended - 62.5mg per increment
091 adxl.setFreeFallDuration(45); //(20 - 70) recommended - 5ms per increment
092
093 //setting all interrupts to take place on int pin 1
094 //I had issues with int pin 2, was unable to reset it
095 adxl.setInterruptMapping( ADXL345_INT_SINGLE_TAP_BIT, ADXL345_INT1_PIN );
096 adxl.setInterruptMapping( ADXL345_INT_DOUBLE_TAP_BIT, ADXL345_INT1_PIN );
097 adxl.setInterruptMapping( ADXL345_INT_FREE_FALL_BIT, ADXL345_INT1_PIN );
098 adxl.setInterruptMapping( ADXL345_INT_ACTIVITY_BIT, ADXL345_INT1_PIN );
099 adxl.setInterruptMapping( ADXL345_INT_INACTIVITY_BIT, ADXL345_INT1_PIN );
100
101 //register interrupt actions - 1 == on; 0 == off
102 adxl.setInterrupt( ADXL345_INT_SINGLE_TAP_BIT, 1);
103 adxl.setInterrupt( ADXL345_INT_DOUBLE_TAP_BIT, 1);
104 adxl.setInterrupt( ADXL345_INT_FREE_FALL_BIT, 1);
105 adxl.setInterrupt( ADXL345_INT_ACTIVITY_BIT, 1);
106 adxl.setInterrupt( ADXL345_INT_INACTIVITY_BIT, 1);
107 }
108
109 void initGame()
110 {
111 SeeedOled.clearDisplay();
112 SeeedOled.setNormalDisplay();
113 SeeedOled.setPageMode();
114
115 switchToMenu();
116 }
117
118 void setup()
119 {
120 strip.begin();
121 SeeedOled.init();
122 initAccel();
123 initGame();
124 }
125
126 void cleanLED()
127 {
128 for( int led = 0; led numLed; led++ )
129 strip.WS2812SetRGB(led,0,0,0);
130 }
131
132 void updateLED()
133 {
134 strip.WS2812Send();
135 }
136
137 void drawMenu()
138 {
139 SeeedOled.clearDisplay();
140 SeeedOled.setTextXY(0,2);
141 SeeedOled.putString("Edison Game");
142
143 SeeedOled.setTextXY(2,1);
144 SeeedOled.putString("A - Start");
145
146 SeeedOled.setTextXY(4,1);
147 SeeedOled.putString("B - Help");
148 }
149
150 void drawHelp()
151 {
152 SeeedOled.clearDisplay();
153
154 char *messages[] = { "Center green -",
155 "tilt forward." ,
156 "Center red -" ,
157 "tilt backward.",
158 "Green edge -" ,
159 "tilt same side." ,
160 "Red edge - tilt",
161 "other side."
162 };
163
164 for( int k = 0; k 8; k++ )
165 {
166 SeeedOled.setTextXY(k,0);
167 SeeedOled.putString(messages[k]);
168 }
169 }
170
171 void makeNewLevel()
172 {
173 gameLevel = rand() % numLevels;
174 rightAnswer = levels[gameLevel][answerID];
175 }
176
177 void showGameStart()
178 {
179 SeeedOled.clearDisplay();
180 SeeedOled.setTextXY(0,0);
181 SeeedOled.putString("Press Start");
182 }
183
184 int getKeys()
185 {
186 int tn = QTouch.touchNum();
187 return tn;
188 }
189
190 int haveTime = 20;
191
192 void showGameLevel()
193 {
194 for( int k = 0; k numLed; k++ )
195 {
196 int color = levels[gameLevel][k];
197 switch(color)
198 {
199 case colorRed : strip.WS2812SetRGB(k,255,0,0); break;
200 case colorGreen: strip.WS2812SetRGB(k,0,255,0); break;
201 default : strip.WS2812SetRGB(k,0,0,0);
202 }
203 }
204
205 updateLED();
206 }
207
208 void switchToSets()
209 {
210 numWins = 0;
211 numLosts = 0;
212 switchToPlay();
213 }
214
215 //------------------------------------
216
217 void switchToPlay()
218 {
219 cleanLED();
220 updateLED();
221
222 SeeedOled.clearDisplay();
223 SeeedOled.setTextXY(3,3);
224 SeeedOled.putString("Get ready!");
225
226 int waitTime = 2000 + (rand()%4)*500;
227
228 delay(waitTime);
229
230 makeNewLevel();
231
232 SeeedOled.setTextXY(3,3);
233 SeeedOled.putString(" ");
234
235 haveTime = 100;
236 gameState = stateCount;
237 }
238
239 void doPlay()
240 {
241 if( haveTime >= 0 )
242 {
243 SeeedOled.setTextXY(3,1);
244 char str[100];
245 sprintf(str,"-- TILT NOW --");
246 SeeedOled.putString(str);
247
248 SeeedOled.setTextXY(5,6);
249 sprintf(str,"%d ",haveTime);
250 SeeedOled.putString(str);
251
252 showGameLevel();
253
254 int answerID = getAnswerID();
255
256 haveTime--;
257
258 if( answerID !=0 || haveTime 0)
259 {
260 char *message;
261 if( answerID != rightAnswer || haveTime 0)
262 {
263 numLosts++;
264 message = "You lose!";
265 }
266 else
267 {
268 numWins++;
269 message = "You win!";
270 }
271
272 cleanLED();
273 updateLED();
274
275 SeeedOled.clearDisplay();
276 SeeedOled.setTextXY(3,4);
277 SeeedOled.putString(message);
278
279 delay(1000);
280
281 if( numWins + numLosts == numSets )
282 {
283 switchToMenu();
284 }
285 else
286 {
287 switchToPlay();
288 }
289 }
290 }
291 }
292
293 //-----------------------
294
295 void switchToHelp()
296 {
297 drawHelp();
298 gameState = stateHelp;
299
300 cleanLED();
301 updateLED();
302 }
303
304 void doHelp()
305 {
306 cleanLED();
307 updateLED();
308
309 int key = getKeys();
310
311 if( key == keyBack )
312 switchToMenu();
313 }
314
315 //-----------------------
316 void switchToMenu()
317 {
318 drawMenu();
319 gameState = stateMenu;
320
321 cleanLED();
322 updateLED();
323 }
324
325 void doMenu()
326 {
327 int key = getKeys();
328
329 if( key == keyA )
330 switchToSets();
331
332 if( key == keyB )
333 switchToHelp();
334 }
335 //-----------------------
336
337 void correct(int &a)
338 {
339 if( a > 32767 )
340 a = -(65536 - a);
341 }
342
343 int getAnswerID()
344 {
345 int x,y,z;
346 adxl.readXYZ(&x, &y, &z);
347
348 correct(x);
349 correct(y);
350 correct(z);
351
352 int v1 = angleReact;
353 if( z != 0 )
354 v1 = y*angleScale/z;
355
356 if( v1 > angleReact )
357 return answerRight;
358
359 if( v1 -angleReact )
360 return answerLeft;
361
362 int v2 = angleReact;
363
364 if( z != 0 )
365 v2 = x*angleScale/z;
366
367 if( v2 > angleReact )
368 return answerUp;
369
370 if( v2 -angleReact )
371 return answerDown;
372
373 return 0;
374 }
375
376 void gameStep()
377 {
378 switch(gameState)
379 {
380 case stateCount: doPlay();break;
381 case stateMenu: doMenu();break;
382 case stateHelp: doHelp();break;
383 }
384 }
385
386 void loop()
387 {
388 gameStep();
389 delay(10);
390 }
文章来源:英特尔开发人员专区