~josealberto4444/arduino-quiz

d9e6a848a5483c4fd7382545b88d80132cc38300 — josealberto4444 5 years ago 1c0e82f
Display questions and answers stored in flash mem.
1 files changed, 83 insertions(+), 16 deletions(-)

M quiz/quiz.ino
M quiz/quiz.ino => quiz/quiz.ino +83 -16
@@ 39,6 39,8 @@ LiquidCrystal_I2C lcd(0x27,16,2);  // LCD address and size.
const byte irrecvPin = 10;         // IR receptor pin.
IRrecv irrecv(irrecvPin);          // Initialisation.
decode_results results;
char message[64];                  // Displaying message, will be populated from FLASH memory.
//#define _DEBUG 0                 // Uncomment to get debugging messages via serial port in certain steps.

// State-recording variables
volatile bool motion = false;     // Is there any movement that should turn on the device?


@@ 48,7 50,7 @@ bool welcomeScreenState = false;  // Is the welcome screen playing?


// Timing variables
const unsigned short secondsToInactive = 7;
const unsigned short secondsToInactive = 80;
volatile unsigned long prevActiveMillis = 0;
unsigned long prevToneMillis = 0;
unsigned long prevScreenMillis = 0;


@@ 57,6 59,8 @@ unsigned short screenStep = 300; // Not a byte because it is modified to a value

byte toneCounter = 0;
byte screenCounter = 0;
byte questionCounter = 0;
byte qaCounter = 0;


// Remote-command variabes


@@ 64,6 68,31 @@ const unsigned long remoteSwitchScroll = 0x1fe48b7;
const unsigned long remotePause = 0x1fee817;


// Questions and answers
char buffer[256]; // Maximum length of any question or answer.

const char q_0[] PROGMEM = "What is the number of electrons going through the normal section of a wire whose current is 0.2 A during 16 s?";
const char a_00[] PROGMEM = "Answer 1: 10^16";
const char a_01[] PROGMEM = "Answer 2: 10^19";
const char a_02[] PROGMEM = "Answer 3: 1.6 * 10^19";
const char a_03[] PROGMEM = "Answer 4: 2.0 * 10^19";

const char q_1[] PROGMEM = "A particle's trajectory is given by the parametric equations x = t, y = t^2 / 2. What is its curvature radius?";
const char a_10[] PROGMEM = "Answer 1: (1+t^2)^(3/2)";
const char a_11[] PROGMEM = "Answer 2: (1+t^3)^(1/2)";
const char a_12[] PROGMEM = "Answer 3: (1+t)^(3/2)";
const char a_13[] PROGMEM = "Answer 4: (1+t)^(1/2)";

const char* const qa[] PROGMEM = {q_0, a_00, a_01, a_02, a_03, q_1, a_10, a_11, a_12, a_13};

const byte numberOfQuestions = sizeof(qa)/10;

char* getQA(byte qaNumber) {
  strcpy_P(buffer, (char*)pgm_read_word(&(qa[qaNumber])));
  return buffer;
}


// Scrolling class
class Scroller {
  // Receive a message and scroll it through the screen


@@ 71,28 100,34 @@ class Scroller {
  // If scrolling horizontally, charStep is  the amount of characters in every
  // step.
  // 
  // TODO: Pause.
  // TODO: A kind of manual scrolling, using the remote to move the text.
  // TODO: Change in charStep and speed, saving it for every player.
  // TODO: Change in charStep and speed, saving it for every player (TODO: multi-player support XD ).
  unsigned short counter;
  const String spaceFilling = "                ";
  String message;
  unsigned long prevMillis;
  unsigned short updateStep;
  byte charStep;
  char direct;
  
  public:
  bool completelyDisplayed;
  String message;
  
  Scroller(String msg, char drc) {
    message = spaceFilling + msg + spaceFilling;
    counter = 0;
    reset(msg);
    charStep = 2;
    direct = drc;
    if (direct == 'H') updateStep = 400;
    if (direct == 'V') updateStep = 1000;
  }

  void reset(String msg) {
    message = spaceFilling + msg + spaceFilling;
    counter = 0;
    completelyDisplayed = false;
  }
  
  void Update() {
  void scroll() {
    unsigned long currentMillis = millis();
    if (direct == 'H') { // Horizontal scrolling.
      if (counter == 0) {


@@ 108,6 143,7 @@ class Scroller {
          prevMillis = millis();
          if (counter >= message.length() - 16 + charStep) {
            counter = 0;
            completelyDisplayed = true;
          }
        }
      }


@@ 129,6 165,7 @@ class Scroller {
          prevMillis = millis();
          if (counter >= message.length()) {
            counter = 0;
            completelyDisplayed = true;
          }
        }
      }


@@ 150,7 187,7 @@ class Scroller {
  
  void pauseOrResume () {
    if (isUpperCase(direct)) {
      direct |= B00100000; // To lower-case.
      direct |= B00100000; // Change direction char to lower-case variant.
    } else {
      direct &= ~(B00100000); // To upper-case.
    }


@@ 158,18 195,25 @@ class Scroller {
};


// Interruption functions
// Interruption-related functions
void detectMotion() {
  motion = true;
  prevActiveMillis = millis();
}

void updateActiveMillis() {
  // Update the volatile variable prevActiveMillis securely
  detachInterrupt(digitalPinToInterrupt(motionPin));
  prevActiveMillis = millis();
  attachInterrupt(digitalPinToInterrupt(motionPin), detectMotion, RISING);
}





// Set-up
Scroller aMessage("This is quite a long message to show in such a tiny screen. =P", 'H');
Scroller currentQA(getQA(qaCounter), 'H');

void setup() {
  pinMode(motionPin, INPUT);


@@ 177,6 221,9 @@ void setup() {
  lcd.init();
  lcd.noDisplay();
  irrecv.enableIRIn();
  #ifdef _DEBUG
  Serial.begin(9600);
  #endif
}




@@ 247,21 294,41 @@ void loop() {
      }
    }
  }

  
  // Work only if the screen is on.
  if (screenState) {
    // If you are not welcoming, do your job.
    if (!(welcomeToneState || welcomeScreenState)) {
      aMessage.Update();
      #ifdef _DEBUG
      Serial.println(currentQA.message);
      #endif
      if (!(currentQA.completelyDisplayed)) {
        currentQA.scroll();
        #ifdef _DEBUG
        Serial.println("scroll");
        #endif
      } else {
        qaCounter++;
        if (qaCounter >= 5*(questionCounter+1)) {
          qaCounter = 5*questionCounter;
          #ifdef _DEBUG
          Serial.println("qaCounter overflow");
          #endif
        }
        currentQA.reset(getQA(qaCounter));
        #ifdef _DEBUG
        Serial.println("QAreset");
        #endif
      }
      if (irrecv.decode(&results)) {
        switch (results.value) {
          case remoteSwitchScroll:
            aMessage.switchDirection();
            prevActiveMillis = millis();
            currentQA.switchDirection();
            updateActiveMillis();
            break;
          case remotePause:
            aMessage.pauseOrResume();
            prevActiveMillis = millis();
            currentQA.pauseOrResume();
            updateActiveMillis();
            break;
        }
        irrecv.resume();