RTOS homework 4

Dependencies:   C12832_lcd mbed

main.cpp

Committer:
gatedClock
Date:
2013-09-13
Revision:
26:986b539170fc
Parent:
25:fe4425b11e3c
Child:
27:c380923f02d8

File content as of revision 26:986b539170fc:

/*----------------------------------------------//------------------------------
    student   : m-moore
    class     : rtos
    directory : RTOS_HW_04
    file      : main.cpp
----description---------------------------------//------------------------------
    Joystick-Controlled Metronome
    
    features:
    1. joystick-controlled.
    2. turns off after one minute.
    3. ISR's for all joystick inputs.
    4. joystick debounce.
    5. LED and LCD displays.
    6. BPM rate adjustable even when metronome is off.
    7. BPM saturates at defined lower/upper bounds.

    controls:
    1. joystick-left   - increase metronome rate.
    2. joystick-right  - decrease metronome rate.
    3. joystick-down   - start metronome.
    4. joystick-up     - stop metronome.
    5. joystick-center - set metronome to 60BPM.
    
    notes:
    1. adding the mbed-rtos library to this project prevents the
       LED from blinking and the LCD from displaying, even if
       there is no #include "rtos.h" statement.
    2. i was considering having the BPM up/down ISRs set up self-
       ending threads for continuous button press for rapid rate
       change, but again, rtos.h was causing trouble.
    3. I'm making use of disable-interrupts for bounce suppression.
       this could microscopically delay the metronome while its
       BPM is being adjusted, since I can't turn off only the
       interrupt involved with joystick input.
    
    testing:
    1. start metronome - verify it blinks, and stops after a minute.
    2. stop  metronome - verity it stops metronome.
    3. verify display indicates ON and OFF state.
    4. verify display indicates BPM rate.
    5. operate left/right joystick, inspect for BPM jumps (bounce).
    6. verify lower/upper BPM bounds.  (only lower-bound tested).
-----includes-----------------------------------//----------------------------*/
    #include "mbed.h"                           // mbed class.
//  #include "rtos.h"
    #include "C12832_lcd.h"                     // LCD class.
    #include "PowerControl.h"

//---defines------------------------------------//------------------------------
    #define LCD1 lcd.locate(0, 0);              // LCD line 1.
    #define LCD2 lcd.locate(0,11);              // LCD line 2.
    #define LCD3 lcd.locate(0,22);              // LCD line 3.
       
    #define METROMAX       800                  // max. beats per minute.
    #define METROMIN         8                  // min. beats per minute.
    #define METROTIME       60.0                // metronome on-time in seconds.
    #define UDSAMPLERATE     0.1                // how often to sample U/D joystick.
    #define LCDSAMPLERATE    0.1                // how often to redraw the LCD.
    #define PULSELENGTH      0.0625             // how long the LED-on-time is.
    #define DEBOUNCE         0.16               // debounce pause duration in S.
//--global_definitions--------------------------//------------------------------
//--global_variables----------------------------//------------------------------ 
    float fMetroDelay;                          // time between ticks, in seconds.
    float fMetroDuty;                           // duration of metro high, in seconds.
    int   dMetroBPM;                            // master parameter.
    char  cMetronomeOn;                         // 1 = allow blink.
//--global_instances----------------------------//------------------------------ 
    C12832_LCD   lcd;                           // LCD object.
    
    InterruptIn  iJoyStickUp    (p15);          // joystick up rising edge.
    InterruptIn  iJoyStickDown  (p12);          // joystick down rising edge.
    InterruptIn  iJoyStickLeft  (p13);          // joystick left rising edge.
    InterruptIn  iJoyStickRight (p16);          // joystick right rising edge.
    InterruptIn  iJoyStickCenter(p14);          // 1 if joystick middle pressed.

    DigitalOut   led0(LED4);                    // magnetron enunciator (not magnatron control)
    DigitalOut   led1(LED3);                    // carousel  enunciator (not carousel  control)
    DigitalOut   led2(LED2);                    // magnetron CONTROL.
    DigitalOut   led3(LED1);                    // carousel  CONTROL.
    
    Ticker      tickerMetronome;                // blinking LED.
    Ticker      tickerLCD;                      // display ticker.
    Timeout     timeoutDutyCycle;               // LED duty cycle delay.
    Timeout     timeoutMetronome;
    

//-------prototypes-----------------------------//------------------------------
    void initialization();                      // initialize settings.
    void lcd_display();                         // display on LCD.
    void interrupt_service_M();                 // metronome tick.                
    void led3_off();                            // attachable LED control.
    void led3_on();                             // attachable LED control.
    void ISR_up();                              // stop metronome.
    void ISR_down();                            // start metronome.
    void ISR_right_rising();                    // decrease BPM.
    void ISR_right_falling();                   // bounce protection.
    void ISR_left_rising();                     // increase BPM.
    void ISR_left_falling();                    // bounce protection.
    void ISR_center();                          // set to 60BPM.
    void turn_off_metronome();                  // turn off blinker.
    
    
    
class Watchdog {
public:
// Load timeout value in watchdog timer and enable
    void kick(float s) {
        LPC_WDT->WDCLKSEL = 0x1;                // Set CLK src to PCLK
        uint32_t clk = SystemCoreClock / 16;    // WD has a fixed /4 prescaler, PCLK default is /4
        LPC_WDT->WDTC = s * (float)clk;
        LPC_WDT->WDMOD = 0x3;                   // Enabled and Reset
        kick();
    }
// "kick" or "feed" the dog - reset the watchdog timer
// by writing this required bit pattern
    void kick() {
        LPC_WDT->WDFEED = 0xAA;
        LPC_WDT->WDFEED = 0x55;
    }
};    
       Watchdog wdt;                               // add a wachdog timer. 
//==============================================//==============================
    int main(void) 
    {
    
    
    // On reset, indicate a watchdog reset or a pushbutton reset on LED 4 or 3
    if ((LPC_WDT->WDMOD >> 2) & 1)  led0 = 1; else led1 = 1;
    
    
    
    
      iJoyStickUp.rise   (&ISR_up);             // metronome stop.
      iJoyStickDown.rise (&ISR_down);           // metronome start.
      
      iJoyStickLeft.rise (&ISR_left_rising);    // increase BPM.
      iJoyStickLeft.fall (&ISR_left_falling);   // anti-bounce.
      
      iJoyStickRight.rise(&ISR_right_rising);   // decrease BPM.
      iJoyStickRight.fall(&ISR_right_falling);  // anti-bounce.
      
      iJoyStickCenter.rise(&ISR_center);        // 60BPM.
      
      initialization();                         // initialize variables.
      
                                                // metronome ticker.
      tickerMetronome.attach(&interrupt_service_M,fMetroDelay);
      
                                                // LCD ticker.
      tickerLCD.attach(&lcd_display,LCDSAMPLERATE);  
      
 // #ifdef NOETHER
// Normal mbed power level for this setup is around 690mW
// assuming 5V used on Vin pin
// If you don't need networking...
// Power down Ethernet interface - saves around 175mW
// Also need to unplug network cable - just a cable sucks power
    PHY_PowerDown();
//#endif

 wdt.kick(10.0); 
      
      while(1)                                  // all timer/interrupt driven.
      {
        Sleep();
        
        
       
      }
    }       
/*----------------------------------------------//----------------------------*/
    void initialization(void)                   // program initializations.
    {
      dMetroBPM      = 60;                      // initialize to 60BPM.      
      fMetroDelay    = 60.0 / (float) (dMetroBPM);
      fMetroDuty     = PULSELENGTH;             // initialize LED on-duration.
      cMetronomeOn   = 0;
    }
/*----------------------------------------------//----------------------------*/
    void ISR_left_rising(void)                  // increase BPM.
    {
      __disable_irq();                          // anti-bounce.

      dMetroBPM++;                              // increase BPM.
      
                                                // saturate metronome BPM.
      if (dMetroBPM > METROMAX) dMetroBPM = METROMAX;
      if (dMetroBPM < METROMIN) dMetroBPM = METROMIN;
      fMetroDelay = 60.0 / (float) (dMetroBPM); // calculate Ticker delay time.
      
      wait(DEBOUNCE);                           // debounce time.
      
      __enable_irq();                           // safe by now.
    }
/*----------------------------------------------//----------------------------*/
    void ISR_left_falling(void)                 // ignore rising after falling edge.
    {
      __disable_irq();                          // anti-bounce.
      
      wait(DEBOUNCE);                           // debounce time.
      
      __enable_irq();                           // safe by now.
    }
/*----------------------------------------------//----------------------------*/
    void ISR_right_rising(void)                 // decrease BPM.
    {
      __disable_irq();                          // anti-bounce.

      dMetroBPM--;                              // decrease BPM.
      
                                                // saturate metronome BPM.
      if (dMetroBPM > METROMAX) dMetroBPM = METROMAX;
      if (dMetroBPM < METROMIN) dMetroBPM = METROMIN;
      fMetroDelay = 60.0 / (float) (dMetroBPM); // calculate Ticker delay time.
      
      wait(DEBOUNCE);                           // debounce time.
      
      __enable_irq();                           // safe by now.
    }
/*----------------------------------------------//----------------------------*/
    void ISR_right_falling(void)                // ignore rising after falling edge.
    {
      __disable_irq();                          // anti-bounce.
      
      wait(DEBOUNCE);                           // debounce time.
      
      __enable_irq();                           // safe by now.
    }
/*----------------------------------------------//----------------------------*/
    void ISR_up(void)                           // turn off metronome.
    {
      cMetronomeOn = 0;
    }
/*----------------------------------------------//----------------------------*/
    void ISR_down(void)                         // metronome on with timeout.
    {
      cMetronomeOn = 1;
      timeoutMetronome.detach();
      timeoutMetronome.attach(&turn_off_metronome,METROTIME);
    }
/*----------------------------------------------//----------------------------*/
    void ISR_center(void)                       // set BPM = 60.
    {
      dMetroBPM = 60;
      fMetroDelay = 60.0 / (float) (dMetroBPM); // calculate Ticker delay time.
      tickerMetronome.detach();                 // change BPM immediately.
      tickerMetronome.attach(&interrupt_service_M,fMetroDelay);
    }
/*----------------------------------------------//----------------------------*/
    void lcd_display(void)                      // display metronome info.
    {
      lcd.cls();                                // clear display.
      
      LCD1;                                     // line 1.
      
      if (cMetronomeOn)
      lcd.printf("  metronome ON");
      else
      lcd.printf("  metronome OFF");

      LCD2;                                     // line 2.
      
      if (dMetroBPM == METROMIN)                // BPM, with saturation notification.
      lcd.printf(" %5.2d BPM  minimum",dMetroBPM);
      else
      if (dMetroBPM == METROMAX)
      lcd.printf(" %5.2d BPM  maximum",dMetroBPM);    
      else
      lcd.printf(" %5.2d BPM",dMetroBPM);
            
      LCD3;                                     // line 3.
      
      lcd.printf("  RTOS HW 4");
    }
/*----------------------------------------------//----------------------------*/
//  this metronome tick ISR will self-adjust to the current user-selected
//  metronome rate.  that has to be done here, and at the start of the function,
//  in order to maintain a constant phase and to prevent a beat-skip.

    void interrupt_service_M()                  // metronome tick.
    {        
      if (cMetronomeOn)
      {
        tickerMetronome.detach();               // only one attachment.  
        tickerMetronome.attach(&interrupt_service_M,fMetroDelay);      
        led3_on();
        timeoutDutyCycle.attach(&led3_off,fMetroDuty);
      } else led3_off();
    }
/*----------------------------------------------//----------------------------*/
    void turn_off_metronome(void)               // turn off metronome.
    {
      cMetronomeOn = 0;
    }
/*----------------------------------------------//----------------------------*/
    void led3_off(void) {led3 = 0;}             // turn off the LED.
/*----------------------------------------------//----------------------------*/
    void led3_on( void) {led3 = 1;}             // turn on the led.
/*----------------------------------------------//----------------------------*/