01 March 2026

Scaffolding: Mapping - "Stop"

    This is a timing-based game in which the player must make a loud sound (e.g. yelling "STOP" or blowing into the mic) in order to stop on the green LED. The LEDs tick up from the bottom of the right side; the top LED is the green one, while the rest are red. The game gives feedback to tell the player whether they've won or lost: the neopixels on the left light up (red for failure, green for success) and a sound plays (buzzer for failure, jingle for success).

    The button starts and stops the game; the potentiometer changes the tempo, so the player can choose their own difficulty for the game. The LEDs also become brighter or darker when the surrounding light is bright or dark respectively, in order to reduce eye strain. (This is why the neopixels for the game are on the right side, away from the light sensor.)


Code:

#include <Adafruit_CircuitPlayground.h>
#include <Adafruit_Circuit_Playground.h>

//Analog Group 20
bool gameStart = false;
bool togglePrevState = 0;
bool greenLEDLit = false;

long timer = 0;
int newTempo;

int gameSpeed = 750;
int LEDBrightness = 255;
int lightInput;
int LEDindex = 0; //potentially use for gameStart section
const int MAX_BRIGHTNESS = 50;

int soundInput;
int soundBaseLevel;
int soundSensitivity = 20;

void setup() {
  //start Circuit Playground and set pin modes
  CircuitPlayground.begin();
  Serial.begin(9600);

  pinMode(A3, INPUT_PULLDOWN);
  pinMode(13, OUTPUT);

  digitalWrite(A3, LOW);

  delay(1000); //wait a second to initialize

  //do a quick average to set the ambient sound level
  int sum = 0;
  for (int i = 0; i < 10; i++){
    sum += CircuitPlayground.mic.soundPressureLevel(10);
  }
  soundBaseLevel = sum / 10;
}

void loop() {
  //check for game toggle, adjust LED brightness, and adjust game tempo
  ToggleGame();
  AdjustBrightness();
  AdjustTempo();

  //if game is started, game loop is run on an interval determined by gameSpeed
  if(gameStart){
    if(millis() > timer + gameSpeed){
      GameLoop();
      LEDindex++;
      timer = millis();
    }
  }

  Serial.println(digitalRead(A3));

  //get sound input to read either success or failure
  //also lights up pin 13 even when game is not started
  CheckSoundInput();

  //debounce
  delay(100);
}

//starts and stops the game with the button on A3
void ToggleGame(){

  int toggleState = digitalRead(A3);

  //if the button is clicked:
  if(toggleState == 1 && togglePrevState == 0){

    if(gameStart == false){ //turn on the game if it's off
      GameStart();
    } else{
      gameStart = false; //turn off the game and clear pixels if it's on
      CircuitPlayground.clearPixels();
    }

  }
  togglePrevState = toggleState;

  //delay(250);
}

//turns on the game and reset LED index
void GameStart(){
  gameStart = true;
  LEDindex = 0;
}

//lights up the LEDs in sequence
void GameLoop(){
  if(LEDindex == 5) {
    CircuitPlayground.clearPixels();
    greenLEDLit = false;
    LEDindex = -1; //this will be 0 on the next loop
  }
  //the final LED is lit green - this is the target, so set greenLEDLit to true
  else if(LEDindex == 4) {
    //sets neopixels i+5 so it happens on the right side of the CPE, further away from the light sensor
    CircuitPlayground.setPixelColor(LEDindex+5, 0, 255, 0);
    greenLEDLit = true;
  }
  //the LEDs leading up to the final are red; reset greenLEDLit to false just in case
  else {
    CircuitPlayground.setPixelColor(LEDindex+5, 255, 0, 0);
    greenLEDLit = false;
  }
}

//check for the input (sound)
void CheckSoundInput(){
  //get the sound volume
  soundInput = CircuitPlayground.mic.soundPressureLevel(10);
  //if the volume is higher than the base level plus sensitivity:
  if (soundInput > soundBaseLevel + soundSensitivity){
    digitalWrite(13, HIGH); //turn on LED 13
    if(gameStart)
      GameEnd();  //end the game, if started
  }
  //if sound input is at or lower than base, turn off LED 13
  else{
    digitalWrite(13, LOW);
  }
}

void GameEnd(){
  gameStart = false; //stop the game

  //if stopped on the green LED, light up the left side green and play a victory jingle
  if(greenLEDLit){
    for(int i = 0; i < 5; i++){
      CircuitPlayground.setPixelColor(i, 0, 255, 0);
    }
    //play the Mario theme as a victory jingle
    CircuitPlayground.playTone(440, 50);
    CircuitPlayground.playTone(440, 50);
    delay(100);
    CircuitPlayground.playTone(440, 50);
    delay(100);
    CircuitPlayground.playTone(350, 50);
    CircuitPlayground.playTone(440, 50);
    delay(100);
    CircuitPlayground.playTone(525, 50);
  }
  //if stopped on a red LED, light up the left side red and play a buzzer
  else{
    for(int i = 0; i < 5; i++){
      CircuitPlayground.setPixelColor(i, 255, 0, 0);
    }
    CircuitPlayground.playTone(120, 600);
  }
 
  //delay before clearing the pixels
  delay(1500);
  CircuitPlayground.clearPixels();
}

//set the neopixels' brightness depending on how much light is in the environment (to avoid eyestrain!)
void AdjustBrightness(){
  lightInput = CircuitPlayground.lightSensor();
  LEDBrightness = map(lightInput, 0, 1023, 1, MAX_BRIGHTNESS);
  CircuitPlayground.setBrightness(LEDBrightness);
}

void AdjustTempo(){
  //use the potentiometer on A2 to set the tempo
  int tempInit = analogRead(A2);
  newTempo = map(tempInit, 0, 1023, 0, 750);
  gameSpeed = newTempo;
}