ECE 4180 2 Player Quiz (mbed trivia)
By Joyita Roy, Raish Wadhwaniya, Christopher Ray

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
- mbed LPC1768 x3
- Adafruit Bluefruit LE UART Friend x2
- RGB LED
- Adafruit VL530X LIDAR sensor x2
- Speaker
Pin Connections
Adafruit Bluefruit LE UART Friend:
| Player mbeds | Adafruit BLE |
|---|---|
| gnd | gnd |
| VU(5v) | Vin(3.3-16V) |
| nc | RTC |
| p13 (Serial RC) | TXO |
| p14 (Serial TX) | RXI |
RGB LED:

- connect to master mbed p24 (red) and p25 (green). Code for blue light is commented out in master program
Adafruit VL530X LIDAR sensor:
| Player mbeds | VL53L0X |
|---|---|
| 3.3V | VIN |
| GND | GND |
| p28 | SDA |
| p27 | SCL |
| p26 | SHDN |
Speaker:

- 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
Please log in to post comments.
