FRDM-KL46Z clock based on Paul Staron's FRDM-KL46Z-LCD-rtc-demo. Uses the on-board touch slider to set hours, minutes and seconds.

Dependencies:   SLCD TSI mbed-src

Fork of FRDM-KL46Z LCD rtc Demo by Paul Staron

After the instructions have finished scrolling across the LCD, press SW3 to cycle between, SET_HOURS, SET_MINUTES, SET_SECONDS and SHOW_TIME modes.

In (e.g.) SET_HOURS mode, press the capacitive touch slider (TSI), releasing when the LCD shows the correct hour (24H clock).

main.cpp

Committer:
tmorgan
Date:
2014-02-24
Revision:
2:46d52fa160b2
Parent:
1:34f0bfc62803

File content as of revision 2:46d52fa160b2:

/*
 * LCD code based on FRDM-KL46Z-LCD-rtc-Demo by Paul Staron.
 * Touch slider code based on serialSENS by Aaron Huang.
 */
#include "mbed.h"
#include "SLCD.h"
#include "TSISensor.h"

// Peripherals
SLCD        sLCD;
Serial      pc(USBTX, USBRX);
TSISensor   tsi;
DigitalOut  greenLED(LED1);
DigitalOut  redLED(LED2);
InterruptIn setModeSwitch (SW3);

// FUNCTION-MODES
// In SET_HOURS mode, wait for slider touch to set hours, or SW3 press to enter SET_MINUTES mode.
// In SET_MINUTES mode, wait for slider touch to set minutes, or SW3 press to enter SET_SECONDS mode.
// In SET_SECONDS mode, wait for slider touch to set seconds, or SW3 press to enter SHOW_TIME mode.
// In SHOW_TIME mode, advance display state every seconds, or, on SW3 press, enter SET_HOURS mode.
#define SET_HOURS   0
#define SET_MINUTES 1
#define SET_SECONDS 2
#define SHOW_TIME   3
int function_mode;

// TIME-DISPLAY STATES
// Show HH:MM from state SHOW_HHMM to state SHOW_SS,
// Show   :SS from state SHOW_SS to state SHOW_LOOP
#define SHOW_HHMM   0
#define SHOW_SS     5
#define SHOW_LOOP   10
int display_state;

char LCDbuffer[32];

// Scroll instructions across the LCD
void scroll_message(void)
{
    char message[60] = "    Press SW3 and touch slider to set time    ";
    
    for (int start = 0; start < strlen(message) - 4; start++)
    {
        for (int digit = 0; digit < 4; digit++)
            sLCD.putc(message[start + digit]);
        wait(0.25);
    }
}

// Set Real-time Clock HH:MM:SS
void set_HHMMSS(int hours, int minutes, int seconds)
{
    struct tm t;
    
    if(hours > 23) hours = 0;
    if(minutes > 59) minutes = 0;
    t.tm_sec = seconds;
    t.tm_min = minutes;
    t.tm_hour = hours;
    t.tm_mday = 23;
    t.tm_mon = 2;
    t.tm_year = 114;
    set_time (mktime(&t));
}

// Read Real-time Clock HH:MM:SS
void get_HHMMSS(int *hours, int *minutes, int *seconds)
{
    time_t rtcTime = time(NULL);
    struct tm *t = localtime(&rtcTime);
    *hours = t->tm_hour;
    *minutes = t->tm_min;
    *seconds = t->tm_sec;
}

// On SW3 press, cycle between function-modes
void setMode(void)
{
    if (function_mode == SET_HOURS)
        function_mode = SET_MINUTES;
    else if (function_mode == SET_MINUTES)
        function_mode = SET_SECONDS;
    else if (function_mode == SET_SECONDS)
        function_mode = SHOW_TIME;
    else if (function_mode == SHOW_TIME)
        function_mode = SET_HOURS;
}

// Wait for slider to be pressed (or mode change)
void waitForTouch(int mode)
{
    redLED = 0;
    while(tsi.readDistance() == 0 && function_mode == mode)
    {
        wait(0.2);
        redLED = !redLED;
    }
    redLED = 1;
}

// Wait for slider to be released and return slider value between 0 and <scale>
int waitForRelease(char *label, int scale)
{
    float pct;
    int return_value = 0;
    
    greenLED = 0;
    while((pct = tsi.readPercentage()) != 0)
    {
        // In practice, readPercentage returns a number in the range 0.06..0.99
        // Stretch it to 0.00..0.99 before applying scale.
        pct = (pct - 0.09)/ 0.90;
        if (pct < 0.0) pct = 0.0;
        return_value = scale * pct;
        sLCD.printf("%2s%2i", label, return_value);
        wait(0.2);
        greenLED = !greenLED;
    }
    greenLED = 1;
    return return_value;
}

// If slider is touched, update hours
void setHours(void)
{
    int hours, minutes, seconds;

    get_HHMMSS(&hours, &minutes, &seconds);
    sLCD.printf("HH%2i", hours);
    waitForTouch(SET_HOURS);
    if (function_mode == SET_HOURS)
    {
        hours = waitForRelease("HH",24);
        pc.printf("Setting hours to %i\r\n", hours);
        set_HHMMSS(hours, minutes, seconds);
        function_mode = SHOW_TIME;
        display_state = SHOW_HHMM;
    }
}

// If slider is touched, update minutes
void setMinutes(void)
{
    int hours, minutes, seconds;
    
    get_HHMMSS(&hours, &minutes, &seconds);
    sLCD.printf("MM%2i", minutes);
    waitForTouch(SET_MINUTES);
    if (function_mode == SET_MINUTES)
    {
        minutes = waitForRelease("MM",60);
        pc.printf("Setting minutes to %i\r\n", minutes);
        set_HHMMSS(hours, minutes, seconds);
        function_mode = SHOW_TIME;
        display_state = SHOW_HHMM;
    }
}

// If slider is touched, update seconds
void setSeconds(void)
{
    int hours, minutes, seconds;
    
    get_HHMMSS(&hours, &minutes, &seconds);
    sLCD.printf("SS%2i", seconds);
    waitForTouch(SET_SECONDS);
    if (function_mode == SET_SECONDS)
    {
        seconds = waitForRelease("SS",60);
        pc.printf("Setting seconds to %i\r\n", seconds);
        set_HHMMSS(hours, minutes, seconds);
        function_mode = SHOW_TIME;
        display_state = SHOW_SS;
    }
}

// Cycle between time-display states
// In states SHOW_HHMM to SHOW_SS - 1, display HH:MM & flash green LED.
// In states SHOW_SS to SHOW_LOOP, display :SS & flash red LED.
void showTime(void)
{
    DigitalOut *flashLED;
    time_t rtcTime = time(NULL);
    
    if(display_state < SHOW_SS)
    {
        strftime(LCDbuffer, 4, "%H%M", localtime(&rtcTime));// display HH:MM 
        flashLED = &greenLED;                               // while flashing green LED
    }
    else
    {
        strftime(LCDbuffer, 4, "  %S", localtime(&rtcTime));// display :SS           
        flashLED = &redLED;                                 // while flashing red LED
    }
    sLCD.printf(LCDbuffer);     // Send to LCD
    redLED = 1; greenLED = 1;   // Both LEDs off
    wait(0.5);
    *flashLED = 0;              // Red or Green on.
    wait(0.5);
    redLED = 1; greenLED = 1;   // Both LEDs off.
    if (function_mode == SHOW_TIME) display_state++;        // Increment display counter if no switch pressed
    if (display_state > SHOW_LOOP) display_state = SHOW_HHMM;
}

main()
{
    pc.printf("\r\n\nFRDM-KL46Z Clock\r\n");
    
    sLCD.All_Segments(1); wait(1);  // Flash LCD segments
    sLCD.All_Segments(0); wait(1);    
    
    greenLED = 1; redLED = 1;       // Both LEDs off
    
    scroll_message();               // Display instructions
    
    setModeSwitch.rise(setMode);    // Enable setMode interrupt handler
    
    sLCD.Colon(1); sLCD.DP2(0);
    function_mode = SHOW_TIME;
    while(1)
    {
        if (function_mode == SET_HOURS)
            setHours();
        else if (function_mode == SET_MINUTES)
            setMinutes();
        else if (function_mode == SET_SECONDS)
            setSeconds();
        else if (function_mode == SHOW_TIME)
            showTime();
    }
}