吹蟑螂游戏机

这是一个使用表压传感器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*)&pr;

    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 拆开然后加上识别头的方法来进行传输

工作的视频

本文提到的 PCB 和代码下载:

====================================================

本文是2025年参加电子森林活动的项目,获得优秀奖

https://www.eetree.cn/project/4720

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注