Display text on screen.

Dependencies:   TextLCD mbed MaxSonar RTC-DS1307

Fork of TextLCD_HelloWorld by Simon Ford

main.cpp

Committer:
aueangpanit
Date:
2017-05-26
Revision:
15:1e08396885bf
Parent:
14:2bde99b3345c

File content as of revision 15:1e08396885bf:

// Hello World! for the TextLCD

#include "mbed.h"
#include <string>
#include "TextLCD.h"
#include "MaxSonar.h"
#include "Rtc_Ds1307.h"

using std::string;

TextLCD lcd(PTE30, PTE29, PTE23, PTE22, PTE21, PTE20); // rs, e, d4-d7

DigitalOut questionScreen(PTE3);
DigitalOut screen1(PTE5);
DigitalOut screen2(PTE4);

//All functions for controlling screens
void UpdateScreen(DigitalOut screen, string text);
void UpdateScreen(DigitalOut screen, char text[1024]);
void UpdateScreen(DigitalOut screen, int firstLineLocation, string firstLineText, int secondLineLocation, string secondLineText);
string GetLocationSpaces(int location);
void ClearAllScreen();

//All funcitons for range sensors
void UpdateRange();

//All functions for menu page
void GameOption();
void StartGame(int gameOptionLocation);

//All functions for exit screen menu
bool ExitScreen();
bool CheckExit(float r1, float r2);

//all functions for Multi-Maths game
void MultiChoice();
void DisplayNewQuestion();
bool CheckCorrect(int screenNumber);

//All functions for clock
void Clock();

Rtc_Ds1307 rtc(PTE0, PTE1);
DigitalOut red(LED1);

DigitalIn pin(PTC7); //button
Serial pc(USBTX, USBRX);
Rtc_Ds1307::Time_rtc tim = {};
PwmOut boop(PTD4); //alarm buzzer
Timer t;

void displayTime();
int setAlrm(bool ho);
bool hitIt(int hor, int min, Rtc_Ds1307::Time_rtc teim);

int Halrm = -1;
int Malrm = 0; 


string questions[4] = {"What is 2*2?", 
                        "What is 5*2?", 
                        "what is 2+2?",
                        "What is 5*4?"};

string screen1Answers[4] = {"4    ", "10    ", "5    ", "18    "};
string screen2Answers[4] = {"5    ", "8    ", "4    ", "20    "};
int correctScreen[4] = {1, 1, 2, 2}; //1 = screen1; 2 = screen2;

int questionCount = 0;

//all functions for pong game
void Pong();
void UpdatePlayerLocation();
void UpdateBallLocation();
void Draw();

MaxSonar *range1;
    float r1;
    
    MaxSonar *range2;
    float r2;
int main() {
    
    //UpdateScreen(questionScreen, 5, "0", 7, "___");
    
    /*questionScreen = 1;
    
    for(int i = 0; i < 10; i++){
        lcd.cls();
        lcd.locate(2, 0);
        lcd.printf("0");
        lcd.locate(2, 1);
        lcd.printf("===");
    }*/
    //wait(5);
    
    // Create and configure object for 3.3V powered LV-series device, 
    // accessed with analog reads (in cm) on p16, triggered by p7.
    range1 = new MaxSonar(MS_LV, MS_ANALOG, PTB8, PTC2);
    range1->setVoltage(3.3);
    range1->setUnits(MS_CM);
    
    range2 = new MaxSonar(MS_LV, MS_ANALOG, PTB9, PTB3);
    range2->setVoltage(3.3);
    range2->setUnits(MS_CM);
    
    ClearAllScreen();
    
    //Pong();
    GameOption();
    
    /*
    UpdateScreen(questionScreen, "question screen");
    UpdateScreen(screen1, "screen1");
    UpdateScreen(screen2, "screen2");
    */
}

int gameOptionLocation = 0;
string gameName[3] = {"Muti-Maths", "Pong!", "Clock"};
void GameOption()
{
    //Clear all screens (so that all of the screens are blank)
    ClearAllScreen(); 
    
    //Display the selected game on "questionScreen"
    UpdateScreen(questionScreen, "Select a game:  >" + gameName[gameOptionLocation]);
    
    bool gameOption = true;    
    while(gameOption)
    {
        //trigger the distance sensors to take a reading and store them in r1 and r2
        UpdateRange();
        
        if(r1 < 25 && r2 < 25) //select
        {
            UpdateScreen(questionScreen, "Entering " + gameName[gameOptionLocation] + ".....");
            wait(1);
            
            gameOption = false;
        }        
        else if(r1 < 20) //down
        {
            if(gameOptionLocation > 0) { gameOptionLocation--; UpdateScreen(questionScreen, "Select a game:  >" + gameName[gameOptionLocation]); }
        }
        else if(r2 < 20) //up
        {
            if(gameOptionLocation < 2) { gameOptionLocation++; UpdateScreen(questionScreen, "Select a game:  >" + gameName[gameOptionLocation]); }
        }
    }
    
    StartGame(gameOptionLocation);
}

void StartGame(int gameOptionLocation)
{
    switch(gameOptionLocation)
    {
        case 0:
            MultiChoice();
        case 1:
            Pong();
        case 2:
            Clock();
    }    
}

void MultiChoice()
{
    bool multiMaths = true;
    
    DisplayNewQuestion();
    while(multiMaths) {
        UpdateRange();
        
        if(CheckExit(r1, r2))
        {
            GameOption();    
        }
        
        if(r1 < 20)
        {
            if(CheckCorrect(1))
            {
                UpdateScreen(questionScreen, "Correct!");
                wait(1);
                DisplayNewQuestion();
            }
            else
            {
                UpdateScreen(questionScreen, "Try Again!");
                wait(1);
                UpdateScreen(questionScreen, questions[questionCount]);
            }
        }
        if(r2 < 20)
        {
            if(CheckCorrect(2))
            {
                UpdateScreen(questionScreen, "Correct!");
                wait(1);
                DisplayNewQuestion();
            }
            else
            {
                UpdateScreen(questionScreen, "Try Again!");
                wait(1);
                UpdateScreen(questionScreen, questions[questionCount]);
            }
        }    
        
        wait(0.5);
    }
}

void DisplayNewQuestion()
{
    if(questionCount >= 3)
    {
        questionCount = 0;    
    }
    else
    {
        questionCount++;    
    }
    
    UpdateScreen(questionScreen, questions[questionCount]);
    UpdateScreen(screen1, screen1Answers[questionCount]);
    UpdateScreen(screen2, screen2Answers[questionCount]);
}

bool CheckCorrect(int screenNumber)
{
    if(screenNumber == correctScreen[questionCount])
    {
        return true;    
    }
    else
    {
        return false;    
    }
}

//player
int pLocation = 5;
string player = "=====";
    
//ball 
string ball = "0";
    
int ballPX = 0;
int ballPY = 0;
    
int ballVX = 1;
int ballVY = 1;
int score = 0;

void Pong() //this is a version of pong where you can't see the middle part of the board (15*10 pixel but only 4 horrizontal pixels are displaying)
{
    bool pong = true;
    
    UpdateScreen(questionScreen, "Welcome to Pong!");
    wait(1);
    
    char score_char_array[10];
    sprintf(score_char_array, "%d", score);
    
    UpdateScreen(questionScreen, score_char_array);
    UpdateScreen(screen1, 0, ball, 0, "");
    UpdateScreen(screen2, 0, "", pLocation, player);
    
    while(pong)
    {
        UpdateRange();
        if(CheckExit(r1, r2))
        {
            GameOption();
        }
        
        UpdatePlayerLocation();
        UpdateBallLocation();
        
        Draw();
    }
}

void UpdatePlayerLocation()
{
    if(r2 < 20)
    {
        if(pLocation > 0) 
        { 
            pLocation--;
        }
    }
    if(r1 < 20)
    {
        if(pLocation < 9) 
        { 
            pLocation++;
        }
    }
        
    wait(0.5);
}

void UpdateBallLocation()
{
    if(ballPY == 0) { ballVY = 1; }
    if(ballPY == 9) { ballVY = -1; }
    if(ballPX == 0) { ballVX = 1; }
    if(ballPX == 15) { ballVX = -1; }
    
    if(ballPY == 8 && ballPX >= pLocation && ballPX <= pLocation + 5)
    {
        ballVY = -1;    
    }
    
    ballPY += ballVY;
    ballPX += ballVX; 
}

void Draw()
{
    //draw ball also 
    if(ballPY < 2 || ballPY > 7)
    {
        if(ballPY == 0) { UpdateScreen(screen1, ballPX, ball, 0, ""); }
        if(ballPY == 1) { UpdateScreen(screen1, 0, "", ballPX, ball); } 
        if(ballPY == 8) { UpdateScreen(screen2, ballPX, ball, pLocation, player); } 
        if(ballPY == 9) { UpdateScreen(screen2, 0, "", ballPX, ball); }
    }
    else //only draw player and enermy
    {
        ClearAllScreen();
        UpdateScreen(screen2, 0, "", pLocation, player);
    }    
}



string exitOption[2] = {"Yes", "No"};
bool CheckExit(float r1, float r2)
{
    if(r1 < 25 && r2 < 25)
    {
        return ExitScreen();
    }
    else
    {
        return false;
    }
}

bool ExitScreen()
{
    int exitOption_int = 0;
    UpdateScreen(questionScreen, "AreYouSureYouWantToExit? >" + exitOption[exitOption_int]);
    
    wait(1);
    
    bool choosing = true;
    while(choosing)
    {
        wait(0.5);
        UpdateRange();
        if(r1 < 25 && r2 < 25)
        {
            if(exitOption_int == 0) 
            { 
                choosing = false;
                UpdateScreen(questionScreen, "Exiting...");
                wait(1);
                return true; 
            }
            else 
            { 
                choosing = false; 
                UpdateScreen(questionScreen, "Returning to game");
                wait(1);
                return false; 
            }
        }
        else if(r1 < 20)
        { 
            if(exitOption_int > 0) { exitOption_int--; UpdateScreen(questionScreen, "AreYouSureYouWantToExit? >" + exitOption[exitOption_int]); }
        }
        else if(r2 < 20)
        {
            if(exitOption_int < 1) { exitOption_int++; UpdateScreen(questionScreen, "AreYouSureYouWantToExit? >" + exitOption[exitOption_int]); }
        }
    }
}

void UpdateScreen(DigitalOut screen, string text)
{
    //disable all E pin for all screens
    questionScreen = 0;
    screen1 = 0;
    screen2 = 0;
        
    //enable E pin for the scrren that we want to update
    screen = 1;
    
    //convert text to char array
    char text_char_array[1024];
    strcpy(text_char_array, text.c_str());
    //some weird behaviour after disabling the E pin once means that we need to update the screen several times for it to display properly
    for(int i = 0; i < 10; i++)
    {
        lcd.cls();
        lcd.printf(text_char_array);
    }
}

void UpdateScreen(DigitalOut screen, char text[1024])
{
    //disable all E pin for all screens
    questionScreen = 0;
    screen1 = 0;
    screen2 = 0;
        
    //enable E pin for the scrren that we want to update
    screen = 1;
    
    //some weird behaviour after disabling the E pin once means that we need to update the screen several times for it to display properly
    for(int i = 0; i < 10; i++)
    {
        lcd.cls();
        lcd.printf(text);
    }
}

void UpdateScreen(DigitalOut screen, int firstLineLocation, string firstLineText, int secondLineLocation, string secondLineText)
{
    //disable all E pin for all screens
    questionScreen = 0;
    screen1 = 0;
    screen2 = 0;
        
    //enable E pin for the scrren that we want to update
    screen = 1;
    
    string line1text = GetLocationSpaces(firstLineLocation) + firstLineText;
    string line2text = GetLocationSpaces(secondLineLocation) + secondLineText;
    
    //convert text to char array
    char firstLine_char_array[1024];
    char secondLine_char_array[1024];
    strcpy(firstLine_char_array, line1text.c_str());
    strcpy(secondLine_char_array, line2text.c_str());
    
    //some weird behaviour after disabling the E pin once means that we need to update the screen several times for it to display properly
    for(int i = 0; i < 10; i++)
    {
        lcd.cls();
        lcd.locate(0, 0);
        lcd.printf(firstLine_char_array);
        lcd.locate(0, 1);
        lcd.printf(secondLine_char_array);
    }
}

string GetLocationSpaces(int location)
{
    string space = "";
    for(int i = 0; i < location; i++)
    {
        space += " ";
    }    
    return space;
}

void ClearAllScreen()
{
    questionScreen = 1;
    screen1 = 1;
    screen2 = 1;
    
    lcd.cls();
}

void UpdateRange()
{
    // Trigger read, wait 49ms until ranger finder has
    // finished, then read. 
    range1->triggerRead();
    wait_ms(49);
    r1 = range1->read();
        
    range2->triggerRead();
    wait_ms(49);
    r2 = range2->read();
}


void Clock() {
    
    questionScreen.write(1);
    screen1 = 0;
    screen2 = 0;
    
    boop.write(0); //initialise buzzer
    boop.period(5);
    
    Ticker cloo; //declare a ticker to update clock every sec
    cloo.attach(&displayTime, 1); //the ticker runs the function that wipes the screen and displays the updated time
    
    rtc.startClock(); 
    
    bool clock = true;
    while(clock){
        
        UpdateRange();
        if(r1 < 25 && r2 < 25)
        {
            cloo.detach();
            if(CheckExit(r1, r2))
            {
            
                GameOption();
                clock = false;
                break;
            }
            cloo.attach(&displayTime, 1);
        }
        
        wait_ms(50); //wait so button states do not overlap
        
        if(pin.read()){                     //once it's 1 start the detection loop to decide whether this is a hold or a double click
            
            cloo.detach();                  //stop the ticker while performing button operations
            
            t.reset();                     
            t.start();                      //start timer
            
            while(t.read() < 1){            //if it's not unpressed in a second - HOLD case
                                    
                if(!pin.read()){            //if it goes low, check for double click
                
                    t.reset();
               
                    while(t.read() < 1){      //listen for 1 sec for a second click
                    
                        if(pin.read()){          //if x = 1 execute DOUBLE CLICK - set alarm
                            lcd.cls();
                            lcd.printf("settin' alarm!");
                            wait(2);
                            
                            Halrm = setAlrm(true);
                            if(Halrm >= 0){
                                Malrm = setAlrm(false);
                                lcd.cls();
                                lcd.printf("Alarm: %d:%d", Halrm,Malrm);
                                wait(2);
                            }
                            break;
                        }
                    }
                break;
            }
        }
        
        
        
        while(pin.read()){                  //still pressed? Execute Button HOLD case, exit hold when no longer held
            
            rtc.getTime(tim);
            
            lcd.cls();
            lcd.printf("Today is the :\n%02d/%02d/%02d", tim.date, tim.mon, tim.year); //display date 
            wait(1);
            
        }
            
         cloo.attach(&displayTime, 1);      //re-enable ticker after date release   
         
    }
        
    t.stop();
    
    }
    
}

void displayTime(){ //get the time from the rtc chip and display it on the LCD
    
    Rtc_Ds1307::Time_rtc tm = tim;
    
    if (rtc.getTime(tm) ) {
        lcd.cls();
        lcd.printf("The time is :\n%02d:%02d:%02d", tm.hour, tm.min, tm.sec);   //display time
        
        if(hitIt(Halrm, Malrm, tm)){        //check if the time is right for alarmage 
            boop.write(0.5);
            while(!pin.read()){
                lcd.cls();
                lcd.printf("You should be alarmed");
                wait(0.2);
            }
            boop.write(0);
        }
        
    }
     red = !red;   
}
    
int setAlrm(bool ho){
    
    int mod;
    float spd;
    if(ho){  
        mod = 24;
        spd = 0.5;
    }else{
        mod = 60;
        spd = 0.25;
    }
    
    int homin = 0;
    bool sat = false;    
    bool DC = false;
    
    while(!sat){
    
        while(!pin.read() && !sat){
            
            lcd.cls();
            if(ho) lcd.printf("Hour: %02d\nDC to confirm", homin);
            else lcd.printf("Minutes: %02d\nDC to confirm", homin);
            
            wait(0.2);
                if(pin.read()){                     //once it's 1 start the detection loop to decide whether this is a hold or a double click
            
                t.reset();                     
                t.start();                      //start timer
            
                while(t.read() < 1){            //if it's not unpressed in a second - HOLD case
                                    
                    if(!pin.read()){            //if it goes low, check for double click
                
                    t.reset();
               
                    while(t.read() < 1){      //listen for 1 sec for a second click
                    
                        if(pin.read()){          //if x = 1 execute DOUBLE CLICK - confirm selection
                            lcd.cls();
                            if(ho) lcd.printf("Hour: %02d\nSet!", homin);
                            else lcd.printf("Minutes: %02d\nSet!", homin);
                            sat = true;
                            DC = true; 
                            wait(2);
                            break;
                        }
                    }
                break;
            }
        }
            if(!pin.read() && !DC){        //if unpressed - single click detected - cancel alarm
                lcd.cls();
                lcd.printf("Alarm Canceled!");
                homin = -1;
                return homin;
            }
            
            while(pin.read()){                  //still pressed? Execute Button HOLD case, exit hold when no longer held
            
                homin = (homin + 1)%mod;        //increment the value while the button is held
                lcd.cls();
                if(ho) lcd.printf("Hour: %02d", homin);
                else lcd.printf("Minutes: %02d", homin); 
                wait(spd);
            
            }      
        }       
        }
        
    }
    
    return homin;
}

//this function checks whether it's time to sound the alarms
//if the minute and the hour is the same as that of the alarm, return true
bool hitIt(int hor, int min, Rtc_Ds1307::Time_rtc teim){
    int x = teim.hour - hor;
    if(x == 0){
        int y = teim.min - min;   
        if(y == 0){
            return true;
        }
    }
        return false;    
}