RTOS homework 4

Dependencies:   C12832_lcd mbed

main.cpp

Committer:
gatedClock
Date:
2013-08-18
Revision:
6:bb5f989e3425
Parent:
5:faa6d8a04501
Child:
7:562f136c7681

File content as of revision 6:bb5f989e3425:

/*----------------------------------------------//------------------------------
    student   : m-moore
    class     : rtos
    directory : RTOS_HW_04
    file      : main.cpp
----description---------------------------------//------------------------------
    Joystick-Controlled Metronome
    
    features:
    1. post-initialization functionality all timer-driven.
    2. IRSs contain no blocking functions.
    3. LED shows the metronome beat.
    4. metronome speed controlled with up/down joystick.
    5. rate-of-speed-change depends on how long the up/down has been active.
    6. Beat-Per-Minute (BPM) shown on LCD display.
    
    controls:
    1. joystick-up     - increase metronome rate.
    2. joystick-down   - decrease metronome rate.
    3. joystick-center - set metronome to 60BPM.
    
    notes:
    
    testing:
    1. confirm ease of being able to adjust one BPM rate with joystick up/down.
    2. confirm three joystick up/down change rates, if keeping the stick pressed.
    3. confirm max/min BPS saturation & display.
    4. confirm joystick up/down control works to change display & LED BPM.
    5. confirm joystick center-press sets rate to 60BPM immediately.
    6. confirm long-test does not result in a crash.
       -> all items confirmed.

-----includes-----------------------------------//----------------------------*/
    #include "mbed.h"                           // mbed class.
    #include "C12832_lcd.h"                     // LCD class.
//---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 JOYUP     p15
    #define JOYDOWN   p12
    #define JOYLEFT   p13
    #define JOYRIGHT  p16
    #define JOYCENTER p14
    
    #define METROMAX       800                  // max. beats per minute.
    #define METROMIN         8                  // min. beats per minute.
    #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.
//--global_definitions--------------------------//------------------------------
//--global_variables----------------------------//------------------------------ 
    float fMetroDelay;                          // time between ticks, in seconds.
    float fMetroDuty;                           // duration of metro high, in seconds.
    int   dMetroBPM;                            // master parameter.
    long  lUpDownHowMany;                       // count how long up/down joystick pressed.
//--global_instances----------------------------//------------------------------ 
    C12832_LCD  lcd;                            // LCD object.
    
    InterruptIn   iJoyStickUp    (p15);            // 1 if joystick up     pressed.
    InterruptIn   iJoyStickDown  (p12);            // 1 if joystick down   pressed.
    InterruptIn   iJoyStickLeft  (p13);
    InterruptIn   iJoyStickRight (p16);
    InterruptIn   iJoyStickCenter(p14);            // 1 if joystick middle pressed.
    
    DigitalOut    dJoyStickUp    (p15);
    DigitalOut    dJoyStickDown  (p12);
    DigitalOut    dJoyStickLeft  (p13);
    DigitalOut    dJoyStickRight (p16);
    DigitalOut    dJoyStickCenter(p14);

    DigitalOut  led3(LED1);                     // leftmost LED.
    
    Ticker      tickerMetronome;                // blinking LED.
    Ticker      tickerJoystickUD;               // joystick up/down sample.
    Ticker      tickerLCD;                      // display ticker.
    Timeout     timeoutDutyCycle;               // LED duty cycle delay.
//-------prototypes-----------------------------//------------------------------
    void initialization();                      // initialize settings.
    void lcd_display();                         // display on LCD.
    void interrupt_service_M();                 // metronome tick.
    void interrupt_service_UD();                // joystick up/down sample.                
    void led3_off();                            // attachable LED control.
    void led3_on();                             // attachable LED control.
    void ISR_up();
    void ISR_down();
    void ISR_right();
    void ISR_left();
    void ISR_center();
//==============================================//==============================
    int main(void) 
    {
      iJoyStickUp.rise(&ISR_up);    
      iJoyStickDown.rise(&ISR_down);
      iJoyStickLeft.rise(&ISR_left);
      iJoyStickRight.rise(&ISR_right);
      iJoyStickCenter.rise(&ISR_center);
      
      initialization();
      
                                                      // metronome ticker.
      tickerMetronome.attach(&interrupt_service_M,fMetroDelay);
      
                                                // LCD ticker.
      tickerLCD.attach(&lcd_display,LCDSAMPLERATE);  
      
      while(1)
      {
      
        wait(10.0);
      }

    }       
/*----------------------------------------------//----------------------------*/
    void initialization(void)                   // program initializations.
    {
      dMetroBPM      = 60;                      // initialize to 60BPM.      
      fMetroDelay    = 60.0 / (float) (dMetroBPM);
      fMetroDuty     = PULSELENGTH;             // initialize LED on-duration.
      lUpDownHowMany = 0;
    }
/*----------------------------------------------//----------------------------*/
    void ISR_left(void)                         // increase beat rate.
    {
      int  dPressedSeconds;                     // how many seconds joystick pressed.   
      int  dMultiCount;                         // slow count rate.
      char cDiscontinuity;                      // 1 = break phase & change BPM now.
      
      cDiscontinuity = 0;                       // don't break phase.
      
                                                // calculate slow rate period.
      dMultiCount = (int) ((float) (1.0 / ((float) UDSAMPLERATE)));
            
          while (dJoyStickLeft)                 // while joystick still pressed.
      {
                                                // rate-range calculations.
        dPressedSeconds = (int) (((float) lUpDownHowMany) * UDSAMPLERATE);
        if (dPressedSeconds < 5) {if (!(lUpDownHowMany % dMultiCount)) dMetroBPM ++;}
        else
        if (dPressedSeconds < 10) dMetroBPM++;
        else dMetroBPM += 5;
        lUpDownHowMany++;                       // joystick holddown time.
      }
      lUpDownHowMany = 0;                  // clear when not up or down.
      
                                                      // saturate metronome BPM.
      if (dMetroBPM > METROMAX) dMetroBPM = METROMAX;
      if (dMetroBPM < METROMIN) dMetroBPM = METROMIN;
      
      fMetroDelay = 60.0 / (float) (dMetroBPM); // calculate Ticker delay time.
      
      if (cDiscontinuity)                       // implement 60BPS now.
      {
        tickerMetronome.detach();               // only one attachment.  
        tickerMetronome.attach(&interrupt_service_M,fMetroDelay);      
      }
    }
/*----------------------------------------------//----------------------------*/
    void ISR_right(void)                        // decrease beat rate.
    {
      int  dPressedSeconds;                     // how many seconds joystick pressed.   
      int  dMultiCount;                         // slow count rate.
      char cDiscontinuity;                      // 1 = break phase & change BPM now.
      
      cDiscontinuity = 0;                       // don't break phase.
      
                                                // calculate slow rate period.
      dMultiCount = (int) ((float) (1.0 / ((float) UDSAMPLERATE)));
      while (dJoyStickRight)                    // while joystick still pressed.
      {
                                                // rate-range calculations.
        dPressedSeconds = (int) (((float) lUpDownHowMany) * UDSAMPLERATE);
        if (dPressedSeconds < 5) {if (!(lUpDownHowMany % dMultiCount)) dMetroBPM --;}
        else
        if (dPressedSeconds < 10) dMetroBPM--;
        else dMetroBPM -= 5;
        lUpDownHowMany++;                       // joystick holddown time.
      }
      lUpDownHowMany = 0;                  // clear when not up or down.
      
                                                 // saturate metronome BPM.
      if (dMetroBPM > METROMAX) dMetroBPM = METROMAX;
      if (dMetroBPM < METROMIN) dMetroBPM = METROMIN;
      
      fMetroDelay = 60.0 / (float) (dMetroBPM); // calculate Ticker delay time.
      
      if (cDiscontinuity)                       // implement 60BPS now.
      {
        tickerMetronome.detach();               // only one attachment.  
        tickerMetronome.attach(&interrupt_service_M,fMetroDelay);      
      }     
    }
/*----------------------------------------------//----------------------------*/
    void ISR_up(void)
    {
    }
/*----------------------------------------------//----------------------------*/
    void ISR_down(void)
    {
    }
/*----------------------------------------------//----------------------------*/
    void ISR_center(void)                       // set BPM = 60.
    {
          int  dPressedSeconds;                     // how many seconds joystick pressed.   
      int  dMultiCount;                         // slow count rate.
      char cDiscontinuity;                      // 1 = break phase & change BPM now.
      
          if (dJoyStickCenter)
      {
        dMetroBPM      = 60;                    // center-button -> 60BPM.
        cDiscontinuity = 1;                     // pending phase-break.
      }
      
         fMetroDelay = 60.0 / (float) (dMetroBPM); // calculate Ticker delay time.
      
      if (cDiscontinuity)                       // implement 60BPS now.
      {
        tickerMetronome.detach();               // only one attachment.  
        tickerMetronome.attach(&interrupt_service_M,fMetroDelay);      
      }   
      
    }
/*----------------------------------------------//----------------------------*/
    void lcd_display(void)                      // display metronome info.
    {
      lcd.cls();                                // clear display.
      
      LCD1;                                     // line 1.
      lcd.printf("  METRONOME");

      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 3 PART 1");
    }
/*----------------------------------------------//----------------------------*/
//  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.
    {        
      tickerMetronome.detach();                 // only one attachment.  
      tickerMetronome.attach(&interrupt_service_M,fMetroDelay);      
      led3 = 1;
      timeoutDutyCycle.attach(&led3_off,fMetroDuty);
    }
/*----------------------------------------------//----------------------------*/
//  this routine measures the number of seconds for which the joystick is
//  in the up or down position.  for three ranges of time, three different
//  BPM rates-of-change are used.  This means that as the user controls the
//  metronome rate using the joystick, at first it will change slowly, then
//  it will change at a moderate speed, then it will change quickly.
//  additionally, pressing the center joystick button will bring the metronome
//  back to 60BPM immediately, breaking BPM phase continuity.
    void interrupt_service_UD(void)             // joystick up/down sample
    {   
      int  dPressedSeconds;                     // how many seconds joystick pressed.   
      int  dMultiCount;                         // slow count rate.
      char cDiscontinuity;                      // 1 = break phase & change BPM now.
      
      cDiscontinuity = 0;                       // don't break phase.
      
                                                // calculate slow rate period.
      dMultiCount = (int) ((float) (1.0 / ((float) UDSAMPLERATE)));
            
      if (dJoyStickUp)                           // joystick up.
      {
                                                // rate-range calculations.
        dPressedSeconds = (int) (((float) lUpDownHowMany) * UDSAMPLERATE);
        if (dPressedSeconds < 5) {if (!(lUpDownHowMany % dMultiCount)) dMetroBPM ++;}
        else
        if (dPressedSeconds < 10) dMetroBPM++;
        else dMetroBPM += 5;
        lUpDownHowMany++;                       // joystick holddown time.
      }
      else
      if (dJoyStickDown)                         // joystick down.
      {
                                                // rate-range calculations.
        dPressedSeconds = (int) (((float) lUpDownHowMany) * UDSAMPLERATE);
        if (dPressedSeconds < 5) {if (!(lUpDownHowMany % dMultiCount)) dMetroBPM --;}
        else
        if (dPressedSeconds < 10) dMetroBPM--;
        else dMetroBPM -= 5;
        lUpDownHowMany++;                       // joystick holddown time.
      }
      else lUpDownHowMany = 0;                  // clear when not up or down.
      
      if (dJoyStickCenter)
      {
        dMetroBPM      = 60;                    // center-button -> 60BPM.
        cDiscontinuity = 1;                     // pending phase-break.
      }
                                                // saturate metronome BPM.
      if (dMetroBPM > METROMAX) dMetroBPM = METROMAX;
      if (dMetroBPM < METROMIN) dMetroBPM = METROMIN;
      
      fMetroDelay = 60.0 / (float) (dMetroBPM); // calculate Ticker delay time.
      
      if (cDiscontinuity)                       // implement 60BPS now.
      {
        tickerMetronome.detach();               // only one attachment.  
        tickerMetronome.attach(&interrupt_service_M,fMetroDelay);      
      }
      
    }
/*----------------------------------------------//----------------------------*/
    void led3_off(void) {led3 = 0;}             // turn off the LED.
/*----------------------------------------------//----------------------------*/
    void led3_on( void) {led3 = 1;}             // turn on the led.
/*----------------------------------------------//----------------------------*/