- ANALOG METER, initial offering - Emulation of an analog/mechanical meter using the SPI TFT display \"http://mbed.org/cookbook/SPI-driven-QVGA-TFT\" (touch not used) Meter takes an integer number from 0 - 100 and uses that number to position the meter\'s needle - An additional auto-scaling feature allows for + floating numbers from 0.0 - 10000.0 in \"NewfNumb\" Scaling is noted two ways a. Color of the meter body changes b. A text scale factor is displayed in the upper, right-hand corner, near the full scale reading Value of \"NewfNumb\" Meter_Body Scale_Factor < -0.0 Blue 0 0.1 - 9.9 Green x1 10.0 - 99.0 Yellow x10 100.0 - 999.0 Orange x100 1000.0 - 9990.0 Red x1k >= 10000.0 Red peg! - If NewfNumb is > 600.0, a flashing yellow warning message appears in the center of the meter movement - The date and time are displayed in the lower right corner of the display - The value of NewfNumb being shown in the movement is also displayed in the lower left coener of the display - A timer ISR automatically updates the meter\'s movement Other Stuff: - Additional demo test program, walks analog meter up and down through all auto scales by manipulating the value of NewfNumb - USB serial port used to dump a few messages. Not needed, set to 921600 BAUD - LED1 slowly gets brighter and dimmer as main loop runs - If for some reason, the \"MeterNumber\" int register ends up >100 or <0, a Purple display appears at 50% movement with a \"bad#\" scale factor - There is NO provision for setting the RTC. Note that TimeZone and DST are added to the RTC number

Dependencies:   mbed

main.cpp

Committer:
loopsva
Date:
2012-01-31
Revision:
0:fc70640071d2

File content as of revision 0:fc70640071d2:

/*
Rev Date        Changes:
------------------------------------------------------------------------------------------------------------------------------------------
100 1/30/12     - ANALOG METER, initial offering
                - Emulation of an analog/mechanical meter using the SPI TFT display "http://mbed.org/cookbook/SPI-driven-QVGA-TFT" (touch not used)
                  Meter takes an integer number from 0 - 100 and uses that number to position the meter's needle
                - An additional auto-scaling feature allows for + floating numbers from 0.0 - 10000.0 in "NewfNumb"
                  Scaling is noted two ways
                    a. Color of the meter body changes
                    b. A text scale factor is displayed in the upper, right-hand corner, near the full scale reading
                      Value of "NewfNumb"       Meter_Body  Scale_Factor
                      < -0.0                    Blue           0
                      0.1 - 9.9                 Green         x1
                      10.0 - 99.0               Yellow       x10
                      100.0 - 999.0             Orange      x100
                      1000.0 - 9990.0           Red         x1k
                      >= 10000.0                Red         peg!
                - If NewfNumb is > 600.0, a flashing yellow warning message appears in the center of the meter movement
                - The date and time are displayed in the lower right corner of the display
                - The value of NewfNumb being shown in the movement is also displayed in the lower left coener of the display
                - A timer ISR automatically updates the meter's movement
               Other Stuff: 
                - Additional demo test program, walks analog meter up and down through all auto scales by manipulating the value of NewfNumb
                - USB serial port used to dump a few messages.  Not needed, set to 921600 BAUD
                - LED1 slowly gets brighter and dimmer as main loop runs
                - If for some reason, the "MeterNumber" int register ends up >100 or <0, 
                    a Purple display appears at 50% movement with a "bad#" scale factor
------------------------------------------------------------------------------------------------------------------------------------------
*/
int revision = 100;                     // revision of this code
#include "mbed.h"
#include "SPI_TFT.h"
#include "Arial12x12.h"
#include "BookAntiqua19x19-14.h"        // kb modified font created by GLCD_Font_Creator.1.20.exe
#include "touch_tft.h"

#define Orange 0xFBE0                   // I like this orange better than SPI_TFT.h

/*--------------------------------------------------------------------------------------------------------------------------------------*/
//I/O Pin Definitions

PwmOut led1(LED1, "led1");              // pwm LED1
DigitalOut led2(LED2, "led2");          // simple on/off for LED2 - 4
DigitalOut led3(LED3, "led3");
DigitalOut led4(LED4, "led4");
Serial pc(USBTX, USBRX);                // Serial USB communications over mbed USB port
touch_tft tt(p19, p15, p16, p17, p5, p6, p7, p9, p14,"TFT"); // x+,x-,y+,y-,mosi, miso, sclk, cs, reset

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// Global Variables

int gDebug = 1;                         // display debog level (0 - 3)
float Led1Pwm = 0.01;                   // LED1 brightness
bool Led1Up = true;                     // LED1 auto up-down
float gWait = 0.005;                    // Main loop wait timeout
float const DISP_SLOW(2.0);             // Long wait for LCD display
float const DISP_FAST(0.5);             // Faster wait for LCD
char timebuf[16];                       // local time format buffer hh:mm:ss
char datebuf[16];                       // local date format buffer mm/dd/yy
int DST = 0;                            // Daylight Saving Time (or as defined in tft.ini)
int TZone = -8;                         // Time Zone from UTC (or as defined in tft.ini)
time_t ctTime;                          // get time structure


// For analog meter
int LineEndX = 0;                       // end of new line
int LineEndY = 0;                       // end of new line
bool onceBlack = true;                  // overwrite to black out text
int MeterText = 3;                      // index pointer into MeterTextArray[]
int MeterTextOld = 5;
int MeterColor = Yellow;                // Meter frame color
int OldMeterText = MeterText;           // Previous meter frame color
int MeterTic = Green;                   // Meter tic color
int MoveColor = White;                  // Meter armature color
int MeterNumber = 0;                    // Meter scale (0 - 100)
bool UpdateMove = true;                 // semifore between calling pgm and interrupt
float NewfNumb = -1.0;                  // + floating number from 0.0 to 10000.0

/*--------------------------------------------------------------------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------------------------------------------------------------------*/
// Analog meter scale text display
const unsigned char MeterTextArray[] = {
    0x20, 0x20, 0x20, 0x30,     //    0
    0x20, 0x20, 0x78, 0x31,     //   x1
    0x20, 0x78, 0x31, 0x30,     //  x10
    0x78, 0x31, 0x30, 0x30,     // x100
    0x20, 0x78, 0x31, 0x4b,     //  x1K
    0x70, 0x65, 0x67, 0x21,     // peg!
    0x62, 0x61, 0x64, 0x23 };   // bad#

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// Analog meter text display
void DispMeterText() {
    for(int i = MeterText * 4; i < MeterText * 4 + 4; i++) {
        tt.printf("%c", MeterTextArray[i]);
        if(gDebug > 2) pc.printf("%c", MeterTextArray[i]);
    }
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// Analog metet text display black-out
void EraseMeterText() {
    for(int i = MeterTextOld * 4; i < MeterTextOld * 4 + 4; i++) {
        tt.printf("%c", MeterTextArray[i]);
        if(gDebug > 2) pc.printf("%c", MeterTextArray[i]);
    }
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
//position the meter's movement
void MeterMovement() {
    LineEndX = 240 * MeterNumber / 100 + 40;  // ((280 - 40) * MeterNumber / 100) + 40;
    if(MeterNumber < 50) {
        LineEndY = 56 * MeterNumber / 100 + 177; // (((205 - 177) * 2) * MeterNumber / 100) + 177;
    } else {
        LineEndY = 56 * (100 - MeterNumber) / 100 + 177; // (((205 - 177) * 2) * (100 - MeterNumber) / 100) + 177;
    }
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
//set up analog meter's inner guts
void DispMeterTics() {
    tt.rect(20,130,50,190,MeterColor);
    tt.circle(35,160,10,MeterColor);

//inner box and cenerting circle are done, now paint the 11 tics in desired color
    tt.line(200,160,210,160,MeterTic);  //50%
    tt.line(197,136,207,135,MeterTic);  //40%
    tt.line(193,112,203,110,MeterTic);
    tt.line(188,88,198,84,MeterTic);
    tt.line(181,65,191,59,MeterTic);
    tt.line(172,45,182,36,MeterTic);    // 0%
    tt.line(197,184,207,185,MeterTic);  // 60%
    tt.line(193,208,203,210,MeterTic);
    tt.line(188,232,198,236,MeterTic);
    tt.line(181,255,191,261,MeterTic);  // 90%
    tt.line(172,275,182,284,MeterTic);  // 100%
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
//set up analog meter's frame
void DispMeterFrame() {
//first erase and display the meter's scale number in upper-right corner
    tt.set_font((unsigned char*) Arial12x12);
    tt.foreground (Black);
    tt.set_orientation(1);
    tt.locate(260,30);
    EraseMeterText();
    tt.foreground (MeterColor);
    tt.locate(260,30);
    DispMeterText();
    MeterTextOld = MeterText;

//now paint the outer frame in the desired color    
    tt.set_orientation(0);
    tt.rect(18,18,222,302,MeterColor);
    tt.rect(19,19,221,301,MeterColor);
    tt.rect(20,20,220,300,MeterColor);
    DispMeterTics();
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
//Test program for the analog meter
void DispMeterShell() {
    tt.cls();
    DispMeterFrame();
    MeterNumber = 0;
    for(int i = 0; i < 21; i++) {
        MeterMovement();
        DispMeterTics();
        tt.line(35,160,LineEndY,LineEndX,MoveColor);
        wait(DISP_FAST);
        tt.line(35,160,LineEndY,LineEndX,Black);  //erase previous line
        MeterNumber = MeterNumber + 5;
    }
    MeterNumber = 0;
    MeterMovement();
    DispMeterTics();
    tt.line(35,160,LineEndY,LineEndX,MoveColor);
    wait(DISP_SLOW);
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// timer interrupt.  Changes the position of the meter movement
int oln = 0 ;
int tmp = 0 ;
int UpdateTics = 0;

void myIRQ() {
    LPC_TIM0->IR |= 1 << 0;
    if(UpdateMove == true) {
        UpdateMove = false;
        tt.set_orientation(0);
        tmp = MeterNumber;
        MeterNumber = oln;
        tt.line(35,160,LineEndY,LineEndX,Black);        //erase previous line
        MeterNumber = tmp;
        MeterMovement();                                //calculate new position
        tt.line(35,160,LineEndY,LineEndX,MoveColor);
        UpdateTics++;
        if(UpdateTics >= 3) {                           //only update tics every few int's
            DispMeterTics();
            UpdateTics = 0;
        }   
    }
    oln = MeterNumber;
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// Updates the date/time and Number values on bottom of TFT and on Text LCD every second
bool flashtext = false;

void UpdateLowerDisplayEverySec() {
    flashtext = !flashtext;
    tt.set_font((unsigned char*) Arial12x12);
    tt.foreground (Cyan);
    tt.set_orientation(1);

//first print date/time in lower-left side of analog meter
    tt.locate(238,205);
    tt.printf("%s", timebuf);
    tt.locate(238,192);
    tt.printf("%s", datebuf);

//display text number in lower-right corner
    tt.foreground (DarkGrey);
    tt.locate(30,205);
    tt.printf("%.1f YYZ ", NewfNumb);

//display WARNING!! if Number too high
    if((NewfNumb > 600.0) && (flashtext == false)) {
        tt.set_font((unsigned char*) Book_Antiqua19x19);
        tt.foreground (Yellow);
        tt.locate(80,110);
        tt.printf("Get the HELL");
        tt.locate(80,130);
        tt.printf("out of here !!!");
        onceBlack = false;
    } else if(((NewfNumb <= 600.0) && (onceBlack == false)) || ((NewfNumb > 600.0) && (flashtext == true))) {
        tt.set_font((unsigned char*) Book_Antiqua19x19);
        tt.foreground (Black);
        tt.locate(80,110);
        tt.printf("Get the HELL");
        tt.locate(80,130);
        tt.printf("out of here !!!");
        onceBlack = true;
    }
    tt.set_orientation(0);

//set color of meter frame (and meter scaling factor) based on NewfNumb scale       
    if(NewfNumb < 10000.0) {
        MeterNumber =  (int)(NewfNumb / 100.0);
        MeterColor = Red;
        MeterText = 4;
    } else {
        MeterNumber =  100;
        MeterColor = Red;
        MeterText = 5;
    }
    if(NewfNumb < 1000.0) {
        MeterNumber =  (int)(NewfNumb / 10.0);
        MeterColor = Orange;
        MeterText = 3;
    }
    if(NewfNumb < 100.0) {
        MeterNumber =  (int)(NewfNumb);
        MeterColor = Yellow;
        MeterText = 2;
    }
    if(NewfNumb < 10.0) {
        MeterNumber =  (int)(NewfNumb * 10.0);
        MeterColor = DarkGreen;
        MeterText = 1;
    }
    if(NewfNumb <= 0.0) {
        MeterNumber = 0;
        MeterColor = Blue;
        MeterText = 0;
    }   
    if((MeterNumber > 100) | (MeterNumber < 0)) {
        MeterNumber = 50;
        MeterColor = Purple;
        MeterText = 6;
    }
//change meter frame color only if it's different from the previous color
    if(OldMeterText != MeterText) {
        OldMeterText = MeterText;
        tt.set_orientation(0);
        DispMeterFrame();
    }
    UpdateMove = true;          // allow interrupt to make change to movement
    if(gDebug > 2) pc.printf("NewfNumb: %.3f   MeterNumber: %d\n", NewfNumb, MeterNumber);
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
// Test routing puts analog meter through its pases
bool MeterUp = true;
void TestMeter() {
    if(MeterUp == true) {
        if(NewfNumb >= 11000.0) {
            MeterUp = false;
            return;
        }else if(NewfNumb >= 1000.0) {
            NewfNumb = NewfNumb + 500.0;
            return;
        }else if(NewfNumb >= 100.0) {
            NewfNumb = NewfNumb + 50.0;
            return;
        }else if(NewfNumb >= 10.0) {
            NewfNumb = NewfNumb + 5.0;
            return;
        }else {
            NewfNumb = NewfNumb + 0.5;
        }
    }else {
        if(NewfNumb <= -1.5) {
            MeterUp = true;
            return;
        }else if(NewfNumb > 1000.0) {
            NewfNumb = NewfNumb - 500.0;
            return;
        }else if(NewfNumb > 100.0) {
            NewfNumb = NewfNumb - 50.0;
            return;
        }else if(NewfNumb > 10.0) {
            NewfNumb = NewfNumb - 5.0;
            return;
        }else {
            NewfNumb = NewfNumb - 0.5;
        }
    }
    if(gDebug > 1) pc.printf("RTN: %.1f\n",NewfNumb);      
}

/*--------------------------------------------------------------------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------------------------------------------------------------------*/
int main() {
    int ResetState = LPC_WDT->WDMOD;
    pc.baud(921600);                    //set up USB serial speed
    ctTime = time(NULL);
    ctTime = ctTime + ((TZone + DST) * 3600);
    pc.printf("\n\n");
    pc.printf("-------------------------------------------------------------------\n");
    pc.printf("Scalable Analog Meter using TFT  Rev: %d   K Braun\n", revision);
    tt.cls();   
    wait(DISP_FAST);
    int StartTime = ctTime;
    int xTime = ctTime;
    int LedDelay = 0;

    pc.printf("Enabling Timer Interrupt\n");    
    // LPC_SC->PCONP |= 1<<1; // Timer0 Power On
    LPC_TIM0->MR0 = 4800000;  // Match count for 200ms (24000 per 1mS)
    LPC_TIM0->MCR = 3;     // Interrupt and Reset on Match
    LPC_TIM0->TCR = 1;     // Enable Timer0
    NVIC_SetVector(TIMER0_IRQn,(uint32_t)&myIRQ);
    NVIC_EnableIRQ(TIMER0_IRQn);
    pc.printf("Ready...\n"); 
       
/*--------------------------------------------------------------------------------------------------------------------------------------*/
    while (1) {
        wait_ms(3);
        ctTime = time(NULL);
        ctTime = ctTime + ((TZone + DST) * 3600);
        strftime(timebuf, 16, "%H:%M:%S", localtime(&ctTime));
        strftime(datebuf, 16, "%m/%d/%y", localtime(&ctTime));
        if(xTime != ctTime) {
            xTime = ctTime;
            if(gDebug > 1) pc.printf("%s  ", timebuf);
            if(gDebug > 1) pc.printf("%s  ", datebuf);
            TestMeter();
            UpdateLowerDisplayEverySec();
            if(gDebug > 1) pc.printf("cT: %d   sT: %d\n", ctTime, StartTime);
        }
       
// Winking LED1      
        LedDelay++;
        if(LedDelay >= 24) {
            LedDelay = 0;
            if(Led1Up == true) {
                Led1Pwm = Led1Pwm + 0.005;
                led1 = Led1Pwm;
                if(Led1Pwm >= 0.20) {
                    Led1Up = false;
                }
            } else {
                Led1Pwm = Led1Pwm - 0.005;
                led1 = Led1Pwm;
                if(Led1Pwm <= 0.005) {
                    Led1Up = true;
                }
            } //brighter else dimmer
        } //LedDelay > 24 (* 3ms from while loop)
    } //while loop
} //main