ECE 4180 2 Player Quiz (mbed trivia)

By Joyita Roy, Raish Wadhwaniya, Christopher Ray

/media/uploads/jroy32/rgd.jpeg

Overview

This project implements a two player trivia game with mbeds connected using GPIO pins . 1 mbed is the master/"trivia host" and the other 2 connected to it are the players. Each trivia question is multiple choice with 4 answer options. Answering a questions correctly adds 1 point, and a wrong answer subtracts 1 point.

Along with 3 mbeds, we used the Adafruit Bluefruit LE UART Friend, Adafruit VL530X LIDAR sensor, RGB LED, and a speaker with PWM output.

After you familiarize yourself with the components, you'll be well on your way to building the trivia game shown in the video below! All you have to do is connect your parts up as directed by the Pin Connections segment, import the ECE4180_master and ECE4180_player program into your compiler workspace, and then put the master program onto the master mbed and player program into both the player mbeds!

When your circuit is assembled and your code is on the mbed, then you should be good to go. Hit the Reset button on your 3 mbeds to start the game. Download the Bluefruit app for the bluetooth module. Connect 1 player mbed at a time to the bluetooth. A blue "Conn" light should light up once you are connected. You may begin the game as the first question is printed. Hover your hand close to the lidar if you are ready to answer the question (like a buzzer) and then respond to the question using your Bluefruit app. Score will be tallied after every question and the winner will be declared at the end!

Video Demo

Components

Pin Connections

Adafruit Bluefruit LE UART Friend:

Player mbedsAdafruit BLE
gndgnd
VU(5v)Vin(3.3-16V)
ncRTC
p13 (Serial RC)TXO
p14 (Serial TX)RXI

RGB LED:

/media/uploads/jroy32/rgbledschematic.png

  • connect to master mbed p24 (red) and p25 (green). Code for blue light is commented out in master program

Adafruit VL530X LIDAR sensor:

Player mbedsVL53L0X
3.3VVIN
GNDGND
p28SDA
p27SCL
p26SHDN

Speaker:

/media/uploads/jroy32/_scaled_speakerdriverschem.png

  • resistor connected to master mbed PWM Out pin p26

Code

Import programECE4180_Project_Master

4180 Project Master Code

main.cpp

#include "mbed.h"
#include "uLCD_4DGL.h"
#include "questions.h"

DigitalOut myled1(LED1); // leds for debugging
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);

DigitalOut lidar_enable(p29); //to determine when lidar should operate

DigitalIn p1_enable(p23); // data from player 1
BusIn p1_ans(p22, p21);

DigitalIn p2_enable(p18); // data from player 2
BusIn p2_ans(p19, p20);

uLCD_4DGL uLCD(p13, p14, p12);

Serial pc(USBTX,USBRX); // for teraterm debugging

PwmOut speaker(p26);

int msg;
int msg2;
int questionIndex = 0;
string *p;
int player = 0;

int player1Score = 0;
int player2Score = 0;

int p1Val = 0;
int p2Val = 0;

questions arr[30];

// Light
class RGBLed
{
public:
    RGBLed(PinName redpin, PinName greenpin)://, PinName bluepin);
    _redpin(redpin), _greenpin(greenpin) //, _bluepin(bluepin)
    {
        //50Hz PWM clock default a bit too low, go to 2000Hz (less flicker)
        _redpin.period(0.0005);
    }

    void write(float red,float green)//, float blue);
    {
        _redpin = red;
        _greenpin = green;
//    _bluepin = blue;
    }
private:
    PwmOut _redpin;
    PwmOut _greenpin;
//    PwmOut _bluepin;
};


//class could be moved to include file


//Setup RGB led using PWM pins and class
RGBLed myRGBled(p24,p25);//,p21); //RGB PWM pins

void shuffleQuestions()
{
    for (int i = 0; i < 90; i++) {
        int rand1 = rand() % 30;
        int rand2 = rand() % 30;
        questions temp = arr[rand1];
        arr[rand1] = arr[rand2];
        arr[rand2] = temp;
    }
}

void addQuestions()
{
    questions q1("Which of these\nchess figures is\nclosely related to'Bohemian\nRhapsody?\n","King","Queen","Pawn","Bishop","Queen");
    questions q2("What religion is\nthe most practicedone in India?\n","Sikhism","Islam","Hinduism","Shinto","Hinduism");
    questions q3("What is the name\nof the Jewish New\nYear?\n","Yom Kippur","Kwanzaa","Hanukkah","Rosh Hashanah","Rosh Hashanah");
    questions q4("What funk/soul\nband was Lionel\nRichie a member\nof?\n","Commodores","Amigas","Ataris","Spectrums","Commodores");
    questions q5("Which country\nhosted the Summer\nOlympics in 2016?\n","Greece","Brazil","China","Spain","Brazil");
    questions q6("Which of these\ncities is closest\nto London, UK?\n","Boston, MA","Miami, FL","Atlanta, GA","New York, NY","Boston, MA");
    questions q7("What did Alfred\nNobel Develop?\n","Atomic bomb","Nobelium","Gunpowder","Dynamite","Dynamite");
    questions q8("Which US Presidentis on the far leftof the Mount\nRushmore\nNational\nMemorial?\n","Theodore\n   Roosevelt","Thomas\n   Jefferson","George\n   Washington","Abraham\n   Lincoln","George\n   Washington");
    questions q9("Which actress\nplays a major\nrole in the TV\nshow 'The Big\nBang Theory'\n","Portia de\n   Rossi","Kaley Cuoco","Emily\n   Deschanel","Sofia Vergara","Kaley Cuoco");
    questions q10("Which of these\nantagonist\ncharacters was\ncreated by\nnovelist J.K.\nRowling?\n","Professor\n   Moriarty","Lord Voldemort","Darth Vader","Lord Farqaad","Lord Voldemort");
    questions q11("Which mammal firstreached Earth's\norbit alive?\n","Monkey","Human","Cat","Dog","Dog");
    questions q12("How many spaces\nare on a standard\nmonopoly board?\n","40","20","80","60","40");
    questions q13("Which actor does\nnot appear in\n'Saving Private\nRyan'?\n","Tom Hanks","Vin Diesel","Giovanni\n   Ribisi","Ralph Fiennes","Ralph Fiennes");
    questions q14("Which city's\nlandmard include:\nThe Pantheon, The\nSpanish Steps and\nTrevi Fountain?\n","Rome","Athens","Istanbul","Barcelone","Rome");
    questions q15("How many blue\nstripes does the\nUnited States of\nAmerica national\nflag have?\n","13","6","0","7","0");
    questions q16("Which of these\ncountries was not\na Soviet Republic\nin USSR?\n","Moldova","Serbia","Kyrgyzstan","Azerbaijan","Serbia");
    questions q17("What temperature\nis the same in\nCelsius and\nFahrenheit?\n","0","-40","+100","+40","-40");
    questions q18("What is the name\nof the boxer whoselife story is\ndepicted in the\n1999 movie 'The\nHurricane'?\n","Rubin Carter","Jake LaMotta","Muhammad Ali","Rocky Marciano","Rubin Carter");
    questions q19("Adele performed\nthe theme song to\nwhich James Bond\nfilm?\n","Casino Royale","From Russia\n   With Love","Quantum of\n   Solace","Skyfall","Skyfall");
    questions q20("What restaurant\nfranchise advises\nyou to 'Eat\nFresh'?\n","Subway","McDonald's","KFC","Taco Bell","Subway");
    questions q21("In which language\nwas the book 'War\nand Peace' originally written?\n", "Russian","English","French","German","Russian");
    questions q22("Which movie was\nthe first to win\n11 Academy\nAwards?\n","Sound of Music","La La Land","Ben-Hur","Titanic","Ben-Hur");
    questions q23("What is the\nlargest country,\nby area, that has\nonly one time\nzone?\n", "China","Russia","Australia","Turkey","China");
    questions q24("Which truck is\nproduced by the\nFord Motor\nCompany?\n", "Silverado 1500","CR-V","F-150","RAV4","F-150");
    questions q25("What is the\nlargest planet in our Solar System?\n","Pluto","Earth","Saturn","Jupiter","Jupiter");
    questions q26("Other than eggs,\nwhat is a primary\ningredient in\nEggs Florentine?\n", "Avocado","Gorgonzola","Spinach","Ham","Spinach");
    questions q27("According to\nPersian folklore,\nwho is the\nstoryteller of\n'One Thousand and\nOne Nights'?\n","Kanaan","Hatshepsut","Homer","Scheherazade","Scheherazade");
    questions q28("Which of these\nNBA franchises\nhas never signed\nLeBron James?\n", "Miami Heat","Los Angeles\n   Lakers","Cleveland\n   Cavaliers","Boston Celtics","Boston Celtics");
    questions q29("What is the color\nof Donald Duck's\nbowtie?\n","Yellow","Green","Red","Blue","Red");
    questions q30("What was the\nfirst successful\nvaccine developed\nin history?\n","Smallpox","Rabies","Cholera","Scarlet Fever","Smallpox");

    arr[0] = q1;
    arr[1] = q2;
    arr[2] = q3;
    arr[3] = q4;
    arr[4] = q5;
    arr[5] = q6;
    arr[6] = q7;
    arr[7] = q8;
    arr[8] = q9;
    arr[9] = q10;
    arr[10] = q11;
    arr[11] = q12;
    arr[12] = q13;
    arr[13] = q14;
    arr[14] = q15;
    arr[15] = q16;
    arr[16] = q17;
    arr[17] = q18;
    arr[18] = q19;
    arr[19] = q20;
    arr[20] = q21;
    arr[21] = q22;
    arr[22] = q23;
    arr[23] = q24;
    arr[24] = q25;
    arr[25] = q26;
    arr[26] = q27;
    arr[27] = q28;
    arr[28] = q29;
    arr[29] = q30;
}

void readQuestion()
{
    arr[questionIndex].shuffleOptions();
    //uLCD.cls();
    uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
    uLCD.locate(0,0);
    uLCD.printf(arr[questionIndex].getQuestion().c_str());
    p = arr[questionIndex].getAllOptions();
    uLCD.printf("\n1: ");
    uLCD.printf((*(p)).c_str());
    uLCD.printf("\n2: ");
    uLCD.printf((*(p+1)).c_str());
    uLCD.printf("\n3: ");
    uLCD.printf((*(p+2)).c_str());
    uLCD.printf("\n4: ");
    uLCD.printf((*(p+3)).c_str());
}

int main()
{
    uLCD.baudrate(3000000); // lcd settings + randomize questions
    srand(time(NULL));
    addQuestions();
    shuffleQuestions();
    uLCD.display_control(PORTRAIT);

    while(1) {
        if (questionIndex == 30) {
            uLCD.filled_rectangle(0, 0, 130, 130, BLACK); //game over + win screen
            uLCD.locate(0,0);
            uLCD.printf("The game is over;");
            wait(2);
            uLCD.locate(0,2);
            uLCD.printf("Player 1: %d", player1Score);
            uLCD.locate(0,4);
            uLCD.printf("Player 2: %d", player2Score);
            wait(3);
            // gameover....
            uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
            uLCD.locate(1,6);
            if (player1Score > player2Score) {
                uLCD.printf("PLAYER 1 WINS!!!");
            } else if (player1Score < player2Score) {
                uLCD.printf("PLAYER 2 WINS!!!");
            } else {
                uLCD.locate(3,6);
                uLCD.printf("IT'S A TIE!!!");
            }
        } else {
            readQuestion(); //print questions
            lidar_enable = 1; // tell players that lidar can now work as buzzer
        }
        while ((!p1Val)&&(!p2Val)) {
            msg = -1;
            msg2 = -1;

            if (p1_enable) { //if player 1 is ready
                p1Val = p1_enable;
                myled1 = !myled1;
                msg = (p1_ans + 1); //answer from player mbeds + 1 to make it numbers between 1-4
                while (msg < 1);
                //checking if answer is right
                if (msg == 1) {
                    if ((*(p)).compare(arr[questionIndex].getCorrectAnswer()) == 0) {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Correct");
                        myRGBled.write(0.0,1.0);
                        speaker.period(1.0/1000.0); // 500hz period 
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        player1Score++;
                        p1Val = 1;
                        break;
                    } else {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Incorrect");
                        myRGBled.write(1.0,0.0);
                        speaker.period(1.0/500.0); // 500hz period
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        player1Score--;
                        p1Val = 1;
                        break;
                    }
                } else if (msg == 2) {
                    if ((*(p+1)).compare(arr[questionIndex].getCorrectAnswer()) == 0) {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Correct");
                        myRGBled.write(0.0,1.0);
                        speaker.period(1.0/1000.0);// 500hz period
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        player1Score++;
                        p1Val = 1;
                        break;
                    } else {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Incorrect");
                        myRGBled.write(1.0,0.0);
                        speaker.period(1.0/500.0); // 500hz period
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        player1Score--;
                        p1Val = 1;
                        break;
                    }
                } else if (msg == 3) {
                    if ((*(p+2)).compare(arr[questionIndex].getCorrectAnswer()) == 0) {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Correct");
                        myRGBled.write(0.0,1.0);
                        speaker.period(1.0/1000.0); // 500hz period
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        player1Score++;
                        p1Val = 1;
                        break;
                    } else {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Incorrect");
                        myRGBled.write(1.0,0.0);
                        speaker.period(1.0/500.0); // 500hz period
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        player1Score--;
                        p1Val = 1;
                        break;
                    }
                } else if (msg == 4) {
                    if ((*(p+3)).compare(arr[questionIndex].getCorrectAnswer()) == 0) {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Correct");
                        myRGBled.write(0.0,1.0);
                        speaker.period(1.0/1000.0); // 500hz period
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        player1Score++;
                        p1Val = 1;
                        break;
                    } else {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Incorrect");
                        myRGBled.write(1.0,0.0);
                        speaker.period(1.0/500.0); // 500hz period
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        player1Score--;
                        p1Val = 1;
                        break;
                    }
                }
            } else if (p2_enable) {
                p2Val = p2_enable;
                myled2 = !myled2;
                msg2 = (p2_ans + 1);
                while (msg2 < 1);
                if (msg2 == 1) {
                    if ((*(p)).compare(arr[questionIndex].getCorrectAnswer()) == 0) {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Correct");
                        player2Score++;
                        myRGBled.write(0.0,1.0);
                        speaker.period(1.0/1000.0); // 500hz period
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        p2Val = 1;
                        break;
                    } else {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Incorrect");
                        myRGBled.write(1.0,0.0);
                        speaker.period(1.0/500.0); // 500hz period
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        player2Score--;
                        p2Val = 1;
                        break;
                    }
                } else if (msg2 == 2) {
                    if ((*(p+1)).compare(arr[questionIndex].getCorrectAnswer()) == 0) {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Correct");
                        myRGBled.write(0.0,1.0);
                        speaker.period(1.0/1000.0); // 500hz period
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        player2Score++;
                        p2Val = 1;
                        break;
                    } else {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Incorrect");
                        myRGBled.write(1.0,0.0);
                        speaker.period(1.0/500.0); // 500hz period
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        player2Score--;
                        p2Val = 1;
                        break;
                    }
                } else if (msg2 == 3) {
                    if ((*(p+2)).compare(arr[questionIndex].getCorrectAnswer()) == 0) {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Correct");
                        myRGBled.write(0.0,1.0);
                        speaker.period(1.0/1000.0); // 500hz period
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        player2Score++;
                        p2Val = 1;
                        break;
                    } else {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Incorrect");
                        myRGBled.write(1.0,0.0);
                        speaker.period(1.0/500.0); // 500hz period
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        player2Score--;
                        p2Val = 1;
                        break;
                    }
                } else if (msg2 == 4) {
                    if ((*(p+3)).compare(arr[questionIndex].getCorrectAnswer()) == 0) {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Correct");
                        myRGBled.write(0.0,1.0);
                        speaker.period(1.0/1000.0); // 500hz period
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        player2Score++;
                        p2Val = 1;
                        break;
                    } else {
                        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
                        uLCD.locate(0,0);
                        uLCD.printf("Incorrect");
                        myRGBled.write(1.0,0.0);
                        speaker.period(1.0/500.0); // 500hz period
                        speaker =0.5;
                        wait(1);
                        speaker =0.0;
                        player2Score--;
                        p2Val = 1;
                        break;
                    }
                }
            }
        }
        //reset all values
        wait(3);
        p1Val = 0;
        p2Val = 0;
        myled1 = 0;
        myled2 = 0;
        msg = -1;
        msg2 = -1;
        lidar_enable = 0;
        myRGBled.write(0.0,0.0);
        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
        uLCD.locate(0,0);
        uLCD.printf("Player 1: %d", player1Score);
        uLCD.locate(0,2);
        uLCD.printf("Player 2: %d", player2Score);
        wait(2);
        uLCD.filled_rectangle(0, 0, 130, 130, BLACK);
        questionIndex++;
    }
}



Import programECE4180_Project_player1

ECE 4180 Project Player Code

main.cpp

#include "mbed.h"
#include "XNucleo53L0A1.h"
#include <stdio.h>




DigitalOut enable(p18);
BusOut answer(p19,p20);
BusOut myleds(LED1, LED2, LED3, LED4);
DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);

DigitalIn lidar_enable(p9);

// READING DATA BETWEEN MBEDS
DigitalIn other_player(p15);
DigitalOut my_player(p16);

Serial blue(p13, p14);  // tx, rx

Serial pc(USBTX,USBRX);
DigitalOut shdn(p26);
// This VL53L0X board test application performs a range measurement in polling mode
// Use 3.3(Vout) for Vin, p28 for SDA, p27 for SCL, P26 for shdn on mbed LPC1768

//I2C sensor pins
#define VL53L0_I2C_SDA   p28
#define VL53L0_I2C_SCL   p27
static XNucleo53L0A1 *board=NULL;

int msg = -1;
char bnum = 0; //button number variable
char bhit = 0;


void bluetooth() //function that is called after lidar distance <70 to get bluetooth inputs
{
    while(1) {
        pc.printf("Start bluetooth |");
        while (blue.readable()) {
            blue.getc();
        }
        if (blue.getc()=='!') {
            if (blue.getc()=='B') { //button data
                bnum = blue.getc(); //button number
                bhit = blue.getc(); //1=hit, 0=release
                if (blue.getc()==char(~('!' + 'B' + bnum + bhit))) {
                    blue.getc();
                    while (blue.readable()) {
                        blue.getc();
                    }
                    switch (bnum) {
                        case '1': //number button 1
                            if (bhit=='1') {
                                msg = 1;
                                myled1 = 1;
                            } else {
                                msg = 0;
                                myled1 = 1;
                            }
                            break;
                        case '2': //number button 2
                            if (bhit=='1') {
                                msg = 2;
                                myled2 = 1;
                            } else {
                                msg = 0;
                                myled2 = 1;
                            }
                            break;
                        case '3': //number button 3
                            if (bhit=='1') {
                                msg = 3;
                                myled3 = 1;
                            } else {
                                msg = 0;
                                myled3 = 1;
                            }
                            break;
                        case '4': //number button 4
                            if (bhit=='1') {
                                msg = 4;
                                myled4 = 1;
                            } else {
                                msg = 0;
                                myled4 = 1;
                            }
                            break;
                        default:
                            break;

                    }
                    //device.putc(msg);
                    return;
                }
            }
        }

        //device.putc(msg);
        wait(1);
    }
}

int main()
{

    int status;
    uint32_t distance;
    DevI2C *device_i2c = new DevI2C(VL53L0_I2C_SDA, VL53L0_I2C_SCL);
    /* creates the 53L0A1 expansion board singleton obj */
    board = XNucleo53L0A1::instance(device_i2c, A2, D8, D2);
    shdn = 0; //must reset sensor for an mbed reset to work
    wait(0.1);
    shdn = 1;
    wait(0.1);
    /* init the 53L0A1 board with default values */
    status = board->init_board();
    while (status) {
        pc.printf("Failed to init board! \r\n");
        status = board->init_board();
    }
    //loop taking and printing distance

    while (1) {
        msg = 0;
        status = board->sensor_centre->get_distance(&distance);
        if (status == VL53L0X_ERROR_NONE) {

           
            if (distance < 70) {
// once master mbed as already printed the question
                if (lidar_enable){
                    
                    my_player = 1;
                    
                    if (!other_player) {  //if the other player has not pressed buzzer yet
                        myleds = 15; // all leds on player mbed light up using BUSOUT
                        wait(0.5);
                        myleds = 0;
                        bluetooth();
                        if (msg > 0 && msg < 5) {
                            answer = msg - 1;//send answer to master
                            enable = 1; //let master mbed know youre ready
                            wait(1);
                        }
                    }
                }
            } else {
                //reset values
                msg = -1;
                enable = 0;
                myleds = 0;
                my_player = 0;
            
            }
        }
    }

}

Presentation

Design Project Presentation


Please log in to post comments.