Week 07 - Output devices

Task #07

The task for the seventh week is to connect an output device and measure its power consuption.

Reaction Time Test

I chose to create a reaction time tester using these components

📟 Components
🕹️ Usage
The test goes like this. First, welcome window is shown. The red LED will glow and the user is asked to press the white button. When pressed, red LED blinks three times and the test started. Now, after some random time (0.2 - 5 s) one of the blue, yellow or green LED will light up. You need to press the same color button as soon as possible. Your time is measured. The other two LEDs will also light up. One at a time and only once. At the end, the user is provided with results for each color and also the average time, which is updated to the leaderboard with ID to compete with other users or to really push yourself.

You can see the wiring and code down bellow. Just a quick heads up, I used pull-up resistors for the button pins to define their voltage to HIGH when not pressed.

🔌 Wiring diagram
No image

I used breadboard for connecting all components.

No image

💻 Arduino IDE Code

#include <Arduino.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels
#define SCREEN_ADDRESS 0x3C  // OLED display address

// Initialize display object
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT); 

// LED pin definitions
#define LED_R 2  // Red LED
#define LED_G 3  // Green LED
#define LED_Y 4  // Yellow LED
#define LED_B 5  // Blue LED

// Button pin definitions
#define BUTTON_G 7  // Green button
#define BUTTON_Y 8  // Yellow button
#define BUTTON_B 9  // Blue button
#define BUTTON_W 11  // White button

// LED offset definitions
#define LED_TO_ZERO 3
#define LED_TO_BUTTON 4

// Store the best 5 average times and corresponding run IDs
#define LEADERBOARD_SIZE 5
#define ULONG_MAX 4294967295
unsigned long leaderboard_times[LEADERBOARD_SIZE] = {ULONG_MAX, ULONG_MAX, ULONG_MAX, ULONG_MAX, ULONG_MAX};
int leaderboard_ids[LEADERBOARD_SIZE] = {0, 0, 0, 0, 0};
int current_run_id = 1;  // Run ID for the current test

// Function headers
void showMessage(String line1, String line2, String largeText1, String largeText2);
void showResults(String blue_time, String yellow_time, String green_time, String average_time, String id);
void showLeaderboard();
void updateLeaderboard(unsigned long averageTime);
void order(int random_case, int led_order[3]);

void setup() {
    // Initialize serial communication
    Serial.begin(9600);
    randomSeed(analogRead(0));  // Seed random number generator using analog pin 0
    
    // Set LED pins as outputs
    pinMode(LED_R, OUTPUT);
    pinMode(LED_G, OUTPUT);
    pinMode(LED_Y, OUTPUT);
    pinMode(LED_B, OUTPUT);

    // Set button pins as inputs with pull-up resistors
    pinMode(BUTTON_W, INPUT_PULLUP);
    pinMode(BUTTON_G, INPUT_PULLUP);
    pinMode(BUTTON_Y, INPUT_PULLUP);
    pinMode(BUTTON_B, INPUT_PULLUP);

    // Turn off all LEDs initially
    digitalWrite(LED_R, LOW);
    digitalWrite(LED_G, LOW);
    digitalWrite(LED_Y, LOW);
    digitalWrite(LED_B, LOW);

    // Initialize the display
    display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);  
    showMessage("Welcome to", "", "REACTION", "TESTER");
    delay(5000);  // Display welcome message for 5 seconds
}

void loop() {
    showMessage("Start by", "pressing", "WHITE", "BUTTON");

    // Turn on the red LED
    digitalWrite(LED_R, HIGH);

    // Wait for the white button to be pressed
    while (digitalRead(BUTTON_W) == HIGH) {
    // Do nothing, just wait for the button press
    }

    // Show "Get Ready" message
    showMessage("Now", "", "GET", "READY");

    // Blink the red LED three times
    for (int i = 0; i < 3; i++) {
    digitalWrite(LED_R, LOW);
    delay(500);
    digitalWrite(LED_R, HIGH);
    delay(500);
    }
    
    // Turn off the red LED
    digitalWrite(LED_R, LOW);
    delay(500);  // Small delay before measuring reaction time

    // Show "Measuring Reaction Time" message
    showMessage("Measuring", "", "REACTION", "TIME");

    // LED order array and random number initialization
    int led_order[3];  
    int randomNumber = random(1, 7);  // Generate a random number between 1 and 6
    order(randomNumber, led_order);  // Set the LED order based on the random number

    // Variables for measuring reaction times
    unsigned long startTime;
    unsigned long reactionTime;
    unsigned long averageTime;
    unsigned long reaction_times[3];  // Array to store reaction times for each LED

    // Measure reaction times for each LED
    for (int i = 0; i < 3; i++) {
    // Generate random delay before lighting up the LED
    int randomTime = random(200, 5000); // 0.2 to 5 s
    delay(randomTime);

    // Turn on the LED
    digitalWrite(led_order[i], HIGH);
    startTime = millis();  // Record the start time

    // Wait until the corresponding button is pressed
    while (digitalRead(led_order[i] + LED_TO_BUTTON) == HIGH) {
        // Do nothing, just wait for the button press
    }

    // Calculate reaction time
    reactionTime = millis() - startTime;
    digitalWrite(led_order[i], LOW);  // Turn off the LED
    reaction_times[led_order[i] - LED_TO_ZERO] = reactionTime;  // Store the reaction time
    }

    // Calculate the average reaction time
    averageTime = (reaction_times[0] + reaction_times[1] + reaction_times[2]) / 3;

    // Display the results
    showResults(String(reaction_times[2]), String(reaction_times[1]), String(reaction_times[0]), String(averageTime), String(current_run_id)); //, String(current_run_id));

    delay(5000);  // Wait for 5 seconds

    // Update the leaderboard if the new average time is better than the worst time
    updateLeaderboard(averageTime);

    // Show the leaderboard
    showLeaderboard();

    delay(10000);  // Wait for 10 seconds before starting again
}

void updateLeaderboard(unsigned long averageTime) {
    // Check if the new average time is better than any of the current leaderboard times
    for (int i = 0; i < LEADERBOARD_SIZE; i++) {
    if (averageTime < leaderboard_times[i]) {
        // Shift the other leaderboard times down
        for (int j = LEADERBOARD_SIZE - 1; j > i; j--) {
        leaderboard_times[j] = leaderboard_times[j - 1];
        leaderboard_ids[j] = leaderboard_ids[j - 1];
        }
        // Insert the new time in the correct position
        leaderboard_times[i] = averageTime;
        leaderboard_ids[i] = current_run_id;
        break;
    }
    }
    current_run_id++;  // Increment the run ID for the next test
}

void showResults(String blue_time, String yellow_time, String green_time, String average_time, String id) {
    display.clearDisplay();
    display.setTextSize(1);  // Normal size text
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);
    // Print first lines
    display.println("Results:");
    display.println("Blue: " + blue_time + " ms");
    display.println("Yellow: " + yellow_time + " ms");
    display.println("Green: " + green_time + " ms");

    // Print larger text
    display.setTextSize(2);
    display.println("ID: " + id);
    display.println("~" + average_time + " ms");
    display.display();  // Update the screen
}

void showLeaderboard() {
    display.clearDisplay();
    display.setTextSize(1);  // Normal text size
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);

    display.println(F("Leaderboard:"));
    display.println(F(""));
    display.setTextSize(1);  // Normal text size
    for (int i = 0; i < LEADERBOARD_SIZE; i++) {
    if (leaderboard_times[i] != ULONG_MAX) {  // Only display non-max times
        display.print("ID: ");
        display.print(leaderboard_ids[i]);
        display.print(" Time: ");
        display.println(leaderboard_times[i]);
    }
    }
    display.display();  // Update the screen
}

void showMessage(String line1, String line2, String largeText1, String largeText2) {
    display.clearDisplay();
    display.setTextSize(1);  // Normal text size
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 0);

    // Print first lines
    display.println(F(""));  // Empty line for spacing
    display.println(line1);
    display.println(line2);
    display.println(F(""));  // Empty line for spacing

    // Print larger text
    display.setTextSize(2);
    display.println(largeText1);
    display.println(largeText2);

    display.display();  // Update the screen
}

void order(int random_case, int led_order[3]) {
    switch (random_case) {
    case 1:
        led_order[0] = LED_B;
        led_order[1] = LED_Y;
        led_order[2] = LED_G;
        break;
    case 2:
        led_order[0] = LED_B;
        led_order[1] = LED_G;
        led_order[2] = LED_Y;
        break;
    case 3:
        led_order[0] = LED_Y;
        led_order[1] = LED_B;
        led_order[2] = LED_G;
        break;
    case 4:
        led_order[0] = LED_Y;
        led_order[1] = LED_G;
        led_order[2] = LED_B;
        break;
    case 5:
        led_order[0] = LED_G;
        led_order[1] = LED_Y;
        led_order[2] = LED_B;
        break;
    default:
        led_order[0] = LED_G;
        led_order[1] = LED_B;
        led_order[2] = LED_Y;
        break;
    }
}

I coded it using Arduino IDE and loaded the program using microUSB cable. I used ChatGPT for formating and syntax.

🎞️ Demo video

LED power consuption

I also mesured the power consuption of the red LED by measuring voltage on the current-limit resistor (R = 470 Ω). I measured 2.974 V. We can get the current by

To compute the power consuption we used voltage on the LED (1.954 V) and measured current