Crosswalk Project

ECE301 - Intro. to Circuits, Summer 2019, EiL Written by Ben Sergent V
ECE301 Crosswalk | Stage 3
Back

Stage 3 - Walk Tone

Basic Setup

Review the first stage's sections on using the Arduino IDE before continuing on if you're fuzzy on the topic.

From the last group's stage, you should have a breadboard with three resistors and two LEDs wired to the Arduino that turn on when the Arduino is powered.

Generating Sound with Piezos

Piezoelectric speakers (commonly known as piezos) rely on the piezoelectric effect to generate sound via the physical bending of a diaphragm when voltage is applied. The application of voltage at a regular frequency causes the diaphragm to displace air and produce sound (of a pitch frequency matching that at which the voltage is being applied). This means that we can generate a plethora of musical tones with the piezo fairly easily (but only one at a time with a frequency resolution limited by the speed of the microcontroller and the frequency response of the piezo itself).

What is the frequency of A4, the pitch most commonly used for tuning?

fA4 = Hz
Check

Connecting the Piezo

If you've never used a breadboard before, review the section in stage one on them.

Now, choose a digital pin (2-13) and connect the piezo between it and ground (GND). The piezo is polarized but the polarity doesn't actually matter; it only dictates the direction that the diaphragm flexes. Having the wrong polarity will essentially shift the square wave by 180° with no effect on the produced tone.

Driving the Piezo Pin

Square wave with a period of 1/440

Programmatically generating a note on the piezo's pin is a little bit more complicated than one might think. It involves maintaining state and calculating the next time for the pin to toggle voltage. In general, we're going to apply a square wave with a period of 1/fA4 seconds. Since this number is incredibly small (~2.27 milliseconds), we'll need to use the micros() function which acts exactly like millis() except it returns a value about a thousand times more specific (the number of microseconds since the Arduino was started or reset). Note that this isn't quite accurate as it actually has a resolution of four microseconds for 16 MHz boards. Using micros() is important so that different notes may be discerned, otherwise G4 (f=392 Hz, T=~2.55s) would sound exactly the same due to the truncation of a floating point number to an integer (both truncate to 2 milliseconds). Afterall, the crosswalk should be pleasing to the ear and not flat or sharp, right? Okay, so maybe it's not super important unless we're playing a song, but please indulge me.

The hardest part coding this is deciding when to toggle the piezo. For that, remember to calculate the period from the A4 frequency, convert the Hz (1/s) to microseconds, and then account for toggling twice every period. Skeleton code may be found below for you to work with. Mostly focus on the TODO comments for where you need to write code, but feel free to modify other pieces to see what happens or even rewrite it from scratch if you like.

What is the period of an A4 square wave to the nearest whole number in microseconds?

TA4 = μs

How often should the piezo voltage be toggled to the nearest whole number in microseconds?

ttoggle_piezo = μs
Check

Skeleton Code

// Crosswalk Project - Stage 3
// ECE301 - Intro. to Circuits

// Pins
const int PIN_LED_RED = -1; // TODO Replace the -1s with the correct pin numbers
const int PIN_LED_GREEN = -1;
const int PIN_PIEZO = -1;

// State
const bool STATE_WAIT = false;
const bool STATE_WALK = true;
const unsigned long DELAY_WAIT = 10000;
const unsigned long DELAY_WALK = 5000;
bool state_current = STATE_WAIT;
unsigned long transition_last = 0;

// Tone
const float NOTE_A4 = -1; // TODO Replace -1 with A4 frequency here
bool tone_current = false;
unsigned long tone_last = 0;

void setup() {
  pinMode(PIN_LED_RED, OUTPUT);
  pinMode(PIN_LED_GREEN, OUTPUT);
  // TODO Set the pin mode for the piezo
}

void loop() {
  // Handle millis() and micros() rolling back over to 0
  if (millis() < transition_last)
    transition_last = 0;
  if (micros() < tone_last)
    tone_last = 0;

  // State Machine
  if (state_current == STATE_WAIT && millis() >= transition_last + DELAY_WAIT) {
    // Switch to walk state
    state_current = STATE_WALK;
    transition_last = millis();
    digitalWrite(PIN_LED_RED, LOW);
    digitalWrite(PIN_LED_GREEN, HIGH);
  } else if (state_current == STATE_WALK && millis() >= transition_last + DELAY_WALK) {
    // Switch to wait state
    state_current = STATE_WAIT;
    transition_last = millis();
    digitalWrite(PIN_LED_RED, HIGH);
    digitalWrite(PIN_LED_GREEN, LOW);
  }

  // Tone
  if (state_current == STATE_WALK) {
    // TODO Write the if-statement to flip tone_current at the appropriate increments
    if (micros() > /* time of next flip */) {
      tone_current = !tone_current;
      tone_last = micros();
    }
    // TODO Set the piezo pin to on or off depending on the time
  } else digitalWrite(PIN_PIEZO, LOW);
}

Video

Once you're finished, you should have something like what's in the below video.