所选任务介绍
这次展示的是使用表压传感器NSPGD1M006DT04设计一个双人对战的“吹蟑螂游戏机”。
在神秘的南亚次大陆,存在着一个神奇的国度,那里的人们经过几千年的洗礼,能够做到和各种小动物和平共存。在当地有着一个古老的游戏:吹蟑螂比赛。双方选手将一直蟑螂放置在玻璃管中,然后同时吹气,能够将蟑螂吹到另外一方的选手就获得了胜利。

很多人第一次听到这种游戏的时候,都会由衷感叹:印吹死挺!
项目描述
项目使用 WS2812 LED 作为指示灯,它是一款集控制电路与发光电路于一体的智能外控LED光源,其外型与5050LED灯珠相同,每个元件即为一个像素点。它采用单线归零码通信方式,通过一根信号线即可实现数据的接收与解码,支持级联控制,理论上可无限扩展。
游戏方法非常简单:
1. 双方比赛开始后,对着自己面前带有传感器的盒子吹气
2. 中间有24个LED,其中2个LED会亮起红色,当一方吹气后,LED会向着对方方向移动
3. 红色LED触及一方最后一个 LED后游戏结束
4. 按下按钮会重新开始新的对战
芯片选型/简短的硬件介绍
项目实际上有三块 PCB
1. NSPGD1M006DT04 的转接板,方便我们实现这个传感器和 Arduino 的连接。NSPGD1M006DT04是表压传感器。表压传感器(Gauge Pressure Sensor)是一种测量相对压力的传感器,即相对于大气压力的压力值。相对的还有绝压传感器(Absolute Pressure Sensor)是一种测量相对于真空或绝对零点的压力的传感器。
2. 带有 Arduino 的控制板,位于游戏机的最左侧和最右侧,理论上需要设计一个左侧和右侧板,但是这里为了成本考量,将二者放在同一块板子上,根据需要焊接左侧或者右侧;
3. WS2812 灯板,这个位于中间
出于成本考虑,板子长度都是小于10cm的,中间使用 U形状的 2.54mm排针进行连接
方案框图 + 设计思路
原理图、PCB设计
1.NSPGD1M006DT04 的转接板电路板和PCB


2.控制板电路和PCB设计,控制板上也带有 WS2812 LED,这样可以最大化利用空间
具体使用的时候,需要额外导线将右侧Arduino 的 TX 连接左侧的 RX
3.WS2812 电路板和 PCB,输入VCC ,控制信号(DIN)和 GND 即可,多余的引脚主要是为了保证连接的稳固
软件流程图 + 调试软件说明 + 关键代码说明
代码分为2部分:左侧和右侧 Arduino 代码不同(具体左右区分方法在下图中)。右侧的只负责读取传感器数据,然后通过串口传输给左侧。然后左侧同样获得传感器数据,比较之后对 WS2812 发送控制信号,操作LED
右侧代码:
#include <Wire.h>
#include "NSPGD1M006DT04.h"
NSPGD1M006DT04 sensor(0xFF);
void setup() {
Serial.begin(115200);
Serial1.begin(2400);
if (!sensor.begin()) {
Serial.println("Device not found");
while(1);
}
}
void loop() {
char s[20];
float pr=sensor.readPressure();
//float pr=3.14159269;
uint8_t *p;
dtostrf(pr,1,6,s);
Serial.println(s);
p=(uint8_t*)≺
Serial1.write(0x55);
Serial1.write(0xAA);
Serial1.write(*p);
Serial1.write(*(p+1));
Serial1.write(*(p+2));
Serial1.write(*(p+3));
delay(50);
}
左侧代码:
#include <FastLED.h>
#include "NSPGD1M006DT04.h"
// 灯带
#define LED_PIN 5
#define COLOR_ORDER GRB
#define CHIPSET WS2812B
#define NUM_LEDS 24
#define BLOWTIME 300
#define RSTARTPIN 10
NSPGD1M006DT04 sensor(0xFF);
CRGB leds[NUM_LEDS];
void(* resetFunc) (void) = 0;
void setup() {
//Serial.begin(115200);
Serial1.begin(2400);
if (!sensor.begin()) {
Serial.println("Device not found");
while (1);
}
pinMode(RSTARTPIN, INPUT_PULLUP);
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
FastLED.setBrightness( 1 );
for (uint8_t i = 0; i < NUM_LEDS / 2; i++) {
memset(leds, 0, sizeof(leds));
leds[NUM_LEDS / 2 - i] = CRGB::Red;
leds[NUM_LEDS / 2 + i] = CRGB::Red;
FastLED.show(); // display this frame
FastLED.delay(300);
}
memset(leds, 0, sizeof(leds));
leds[NUM_LEDS / 2 ] = CRGB::Red;
leds[NUM_LEDS / 2 + 1] = CRGB::Red;
FastLED.show(); // display this frame
FastLED.delay(300);
}
long int Elsp = 0;
uint8_t CockroachPosition = NUM_LEDS / 2;
float LeftSum = 0, RightSum = 0;
uint8_t Index = 0;
void loop() {
float prRight;
uint8_t *p;
while (Serial1.available()) {
uint8_t c = Serial1.read();
if ((Index == 0) && (c == 0x55)) {
Index++;
p = (uint8_t*)&prRight;
} else if ((Index == 1) && (c == 0xAA)) {
Index++;
} else if (Index != 0) {
*p = c;
p++;
Index++;
if (Index == 6) {
RightSum = RightSum + prRight;
float Left = sensor.readPressure();
Index = 0;
if ((prRight < 0) || (Left < 0)) {
break;
}
LeftSum = LeftSum + Left;
// Serial.print("Rcv"); Serial.print(" "); Serial.print(Left); Serial.print(" "); Serial.println(prRight);
}
}
}
if ((millis() - Elsp > BLOWTIME) && (Index == 0)) {
if (LeftSum > RightSum + 0.1) {
CockroachPosition++;
}
if (LeftSum + 0.1 < RightSum) {
CockroachPosition--;
}
memset(leds, 0, sizeof(leds));
leds[CockroachPosition] = CRGB::Red;
leds[CockroachPosition + 1] = CRGB::Red;
FastLED.show(); // display this frame
// Serial.print("Set LED"); Serial.print(CockroachPosition); Serial.print(" ");
// Serial.print(LeftSum); Serial.print(" "); Serial.print(RightSum); Serial.print(" "); Serial.println(Index);
LeftSum = 0; RightSum = 0;
if ((CockroachPosition == 0) || (CockroachPosition == NUM_LEDS - 2)) {
Serial.println("Win");
while (1) {
if (digitalRead(RSTARTPIN) == LOW) {
resetFunc();
}
}
}
Elsp = millis();
}
}
实物演示以及说明
前面提到了,这次设计了三块PCB,实物如下
1.NSPGD1M006DT04 的转接板实物
2.控制板电路板实物

3.WS2812 电路板和

上述PCB 焊接之后通过U型排针连接在一起,按照下图放置
游戏的时候双方对着传感器吹气即可:

遇到的难点及解决方法
1. NSPGD1M006DT04传感器无法设定设备地址,因此 I2C 上只能放置一个。如果有需要,那么可以通过 GPIO 来进行模拟,或者通过添加元件来解决。最终选择的方案是使用2个Arduino 这样可以化简电路,方便代码编写;
2. 两个 Arduino 使用串口通讯,Arduino Leonardo 中 float 占用4字节。为了简单起见,采用直接将float 拆开然后加上识别头的方法来进行传输
对本次活动的心得体会(包括意见或建议)
刚开始玩 Arduino 的时候,碰到过需要判断用户吹气的需求,比如,做一个可以“吹灭”的LED,但是因为无法购买到合适的传感器,最终只能使用声音传感器来替代。这次看到这个活动,让我产生了尝试的想法,最终实现了这个作品。从可靠性上来说,并不完美,但是作为一个游戏机我是非常满意的。玩法简单,半分钟的讲解即可上手,双方在笑声中完成一次又一次的比赛。当然,副作用是用户反应大笑和狂吹气会导致肚子疼…….
