Part 1: Variable Input and Output

The first week of this lab served as an introduction to analog inputs and outputs using the Arduino Nano Every microcontroller. I experimented with a potentiometer and a photocell as analog inputs and LEDs as outputs.

Circuit Diagram of Analog I/O

The code used for this part of the lab was fairly simple, as seen here.

int turnPin = A4;
int turnVal = 0;

int lightPin = A2;
int lightVal = 0;

int ledPin1;
int ledPin2;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

  pinMode(5,OUTPUT);
  pinMode(3,OUTPUT);  

}

void loop() {
  // put your main code here, to run repeatedly:
  turnVal = analogRead(turnPin);
  lightVal = analogRead(lightPin);


  Serial.print(turnVal);
  Serial.print(" , ");
  Serial.println(lightVal);

  analogWrite(3,turnVal/4);
  analogWrite(5,map(lightVal,50,360,0,255));

}
Analog I/O with LEDs

As can be seen in the video, the potentiometer brightens or dims the green LED as it is turned, and the photocell causes the blue LED to dim as it takes in less light.

Part 2: The Box

In my typical fashion of overdoing projects, I chose to create a box that functions similarly to the classic arcade game Galaga. This decision led to many challenges in programming, 3D modelling, and circuitry.

The original idea was to create a box that looked like a miniature arcade cabinet. It would be a 5×5 array of LEDs, using neopixel strips. The player would have a “ship” they could control on the bottom row of pixels using the potentiometer, and there would be “attackers” which fall from the top of the screen towards the player’s “ship.” The player could use the force sensitive resistor to shoot a beam at the “attacker,” and on a hit a small animation and sound would play. If the “attacker” were to reach the row that the “ship” is on, a different animation and sound would play. The end product was very similar to the idea, however in the interest of space in the box, the sound part was cut.

The Original Concept Sketch

The biggest challenge I came across was the fabrication of the box itself. I chose to model in SolidWorks and 3D print at home, and I had to re-print a few of my pieces multiple times due to measurements I did not originally account for, such as extra space wires may take up.

Another manufacturing problem I ran into with the box was the fact that the micro-usb plug extended past the dimensions of the bread board, and there was simply not enough room to get my usual plug in. Instead of re-doing the print, however, I solved this problem by finding a new micro-usb cable with different dimensions.

The Circuit Diagram

Here is a diagram of the circuitry of my box. The circuits for each neopixel strip were identical, in the interest of saving space I only showed one.

I also came across a few problems in my code. At times, the “hit” sequence would play whenever the ship was lined up with the attacker, or it would play right after the “fail” sequence would play. I also had an issue with the “attacker” disappearing as soon as the player’s “ship” was lined up with it, however the game would otherwise function normally.

#include <Adafruit_NeoPixel.h>
#include <stdlib.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define ROW1PIN 21
#define ROW2PIN 20
#define ROW3PIN 19
#define ROW4PIN 18
#define ROW5PIN 17

//declare global variables (pin vals, etc)
  //initialize pins
  //input pins
  const int knobPin = A0;
  const int pressurePin = A1;

  int knobNum = 0;
  int pressureNum = 0;
  int cnum = 0;
  int rnum = 0;
  int r1c = 0;
  int count = 0;
  int count2 = 0;
  int power = 0;
  int interval = 16000000/4;
  bool noAttack = true;


  //output pins
  const int speakerPin = 10;

  //neopixel strip
  Adafruit_NeoPixel row1 = Adafruit_NeoPixel(5, ROW1PIN, NEO_GRB + NEO_KHZ800);
  Adafruit_NeoPixel row2 = Adafruit_NeoPixel(5, ROW2PIN, NEO_GRB + NEO_KHZ800);
  Adafruit_NeoPixel row3 = Adafruit_NeoPixel(5, ROW3PIN, NEO_GRB + NEO_KHZ800);
  Adafruit_NeoPixel row4 = Adafruit_NeoPixel(5, ROW4PIN, NEO_GRB + NEO_KHZ800);
  Adafruit_NeoPixel row5 = Adafruit_NeoPixel(5, ROW5PIN, NEO_GRB + NEO_KHZ800);


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

  //initialize neopixels
  row1.begin();
  row1.show();

  row2.begin();
  row2.show();

  row3.begin();
  row3.show();

  row4.begin();
  row4.show();

  row5.begin();
  row5.show();

}

void loop() {
  // put your main code here, to run repeatedly:
  knobNum = analogRead(knobPin);
  pressureNum = analogRead(pressurePin);

  Serial.println(pressureNum);
  //need to be changed based on baseline reading



  //bottom LED strip will be the "ship," controlled by the potentiometer
  steerShip();


  //attackers: randomly timed and in random columns
  if (noAttack == true)
  {
    generateEnemy();
  }
  
  if (count%interval == 0)
  {
    descend();
  }
  //shoot: light up the column the ship is in, controlled by pressure sensor, higher pressure reading = higher row, shoot sound
  //up to row 2
  if (pressureNum != 1023)
  {
    shoot();
  }

  //on hit: green screen
  if (r1c == cnum && power >= rnum)
  {
    hit();
  }

  else if (pressureNum == 1023)
  {
    row5.setPixelColor(r1c,0,0,0);
    row4.setPixelColor(r1c,0,0,0);
    row3.setPixelColor(r1c,0,0,0);
    row2.setPixelColor(r1c,0,0,0);
    row2.show();
    row3.show();
    row4.show();
    row5.show();
    power = 0;
  }
  //on fail: red screen
  if (rnum == 1)
  {
    fail();
  }

  //16 million times per second
  count++;
}

void hit()
{
      for (int i = 0; i<5; i++)
    {
      row1.setPixelColor(i,0,255,0);
      row2.setPixelColor(i,0,255,0);
      row3.setPixelColor(i,0,255,0);
      row4.setPixelColor(i,0,255,0);
      row5.setPixelColor(i,0,255,0);
    }

    row1.show();
    row2.show();
    row3.show();
    row4.show();
    row5.show();

    tone(speakerPin,523.25);
    noTone(speakerPin);
    tone(speakerPin,659.25);
    noTone(speakerPin);
    delay (500);

    row1.clear();
    row2.clear();
    row3.clear();
    row4.clear();
    row5.clear();

    row1.show();
    row2.show();
    row3.show();
    row4.show();
    row5.show();

    rnum = 5;
    noAttack = true;
}

void fail()
{
    for (int i = 0; i<5; i++)
    {
      row1.setPixelColor(i,255,0,0);
      row2.setPixelColor(i,255,0,0);
      row3.setPixelColor(i,255,0,0);
      row4.setPixelColor(i,255,0,0);
      row5.setPixelColor(i,255,0,0);
    }

    row1.show();
    row2.show();
    row3.show();
    row4.show();
    row5.show();

    tone(speakerPin,659.25);
    noTone(speakerPin);
    tone(speakerPin,523.25);
    noTone(speakerPin);
    delay (500);

    row1.clear();
    row2.clear();
    row3.clear();
    row4.clear();
    row5.clear();

    noAttack = true;
    rnum = 5;
}

void shoot()
{
    if (pressureNum < 1016)
  {
    row2.setPixelColor(r1c, 0,0,250);
    row2.show();
    power = 2;
  }
  //up to row 3
  if (pressureNum < 1008)
  {
    row3.setPixelColor(r1c,0,0,250);
    row3.show();
    power = 3;
  }
  //up to row 4
  if (pressureNum < 1000)
  {
    row4.setPixelColor(r1c,0,0,250);
    row4.show();
    power = 4;
  }
  //up to row 5
  if (pressureNum < 992)
  {
    row5.setPixelColor(r1c,0,0,250);
    row5.show();
    power = 5;
  }
}

void generateEnemy()
{
  cnum = rand()%5;
    row5.setPixelColor(cnum, 255, 0, 0);
    row5.show();
    noAttack = false;
}

void steerShip()
{
  if (knobNum >= 0 && knobNum < 204)
  {
    row1.clear();
    row1.setPixelColor(0, 230,0,150);
    row1.show();
    r1c=0;
  }
  else if (knobNum >= 204 && knobNum < 408)
  {
    row1.clear();
    row1.setPixelColor(1, 230,0,150);
    row1.show();
    r1c=1;
  }
  else if (knobNum >= 408 && knobNum < 612)
  {
    row1.clear();
    row1.setPixelColor(2, 230,0,150);
    row1.show();
    r1c=2;
  }
  else if (knobNum >= 612 && knobNum < 816)
  {
    row1.clear();
    row1.setPixelColor(3, 230,0,150);
    row1.show();
    r1c=3;
  }
  else
  {
    row1.clear();
    row1.setPixelColor(4, 230,0,150);
    row1.show();
    r1c=4;
  } 
}

void descend()
{
    rnum--;
    if (rnum == 4)
    {
      row5.clear();
      row4.setPixelColor(cnum, 255, 0, 0);
      row5.show();
      row4.show();
    }
    else if (rnum == 3)
    {
      row4.clear();
      row3.setPixelColor(cnum, 255, 0, 0);
      row4.show();
      row3.show();
    }
    else if (rnum == 2)
    {
      row3.clear();
      row2.setPixelColor(cnum, 255, 0, 0);
    }
}
The Final Box