Fast PWM - Compare to OCR1A

Part 2:

/*****
  This function is used to set up the interrupt for the Timer1/Couner interrupt.
  Timer1 is a 16 bit timer and used here with no prescaling. This function also
  sets the state for the three ports used by the sketch.

  Paramter list:
    void
    
  Return value:
    void
*****/
void InitTimer()
{
  // Clear Timer/Counter Control Register for Interrupt 1, bytes A and B (TCCR1?)
  TCCR1A = 0;       // Clear TCCR1A/B registers
  TCCR1B = 0;
  TCNT1 = 0;        // Initialize counter to 0

  // Compare register for TIMER1: (16mHz / frequency - `) = 15999 = 0x3E7F / 2^6
  period = (CLOCKFREQUENCY / frequency - 1) / 64;
  OCR1A = period;
  
  // Timer/Counter Control Register for Interrupt 1 on register B
  TCCR1B |= (1 << WGM12);    // Mode 4, CTC--Clear Timer on Compare
  TCCR1B |= (1 << CS10);     // Clock Select Bit, no prescaling
  TIMSK1 |= (1 << OCIE1A);   // The value in OCR1A is used for compare
 
  DDRB = 0b11111111;         // PORTB all outputs
  DDRC = 0b00111111;         // PORTC all inputs except PC6, which is RESET ** DANGER, and PC7
  DDRD = 0b11111111;         // PORTD all outputs
}


/*****
  This function is used to set up the interrupt for the rotary encoder on pins
  2 (PCINT18) and 3 (PCINT19).
  
  Paramter list:
    void
    
  Return value:
    void
*****/
void InitEncoder()
{
  PCICR |= (1 << PCIE2);  // Turn on Port Control Interrupt Enable for Timer2 for 
                          // Pin Change Interrupt Control Register
  //PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); // Look for Pin Control Interrupts on pins 2 and 3
  PCMSK2 |= (1 << PCINT18) | (1 << PCINT19) | (1 << PCINT20); // Look for Pin Control Interrupts 
                                                              // on pins 2, 3, and 4
}  

void loop() 
{ 
  buttonRead = digitalReadFast2(ENCODERSWITCH);
  
  if (buttonRead == LOW) {
    deBounce(ENCODERSWITCH);
    buttonRead = ENCODERSETTOSELECT;
    UpdateDisplayIncrement();
  }
   
  if (frequency != oldFrequency) {    // Did frequency cahnge?
    if (frequency > MAXFREQUENCY) {   // New one too hihg??
      frequency = MAXFREQUENCY;
    }
    if (frequency < MINFREQUENCY) {   // New one too low??
      frequency = MINFREQUENCY;
    }
    UpdateDisplayFrequency();
    oldFrequency = frequency;    // So we don't update unless needed
  }
  CheckFrequency();
}

/*****
  This function is used to update the LCD display for any changes in the increment index
  which is used to display the second LCD line.
  
  Parameter List:
    void
    
  Return value:
    void
*****/  
void UpdateDisplayIncrement()
{
  increIndex++;

  if (increIndex >= (MAXENCODERVALUES + MAXWAVETYPES)) { // Increment too far??
    increIndex = 0;                                      // Yep, start over.
  }
  
  lcd.setCursor(0, 1);                                 // Start second line
  if (increIndex < MAXENCODERVALUES) {
    lcd.print("Incr: ");
    increment = incrementTable[increIndex];
  } else {
    lcd.print("Wave: ");
    waveType = increIndex - MAXENCODERVALUES;
    switch (waveType) {
      case TRIANGLE:  
        waveTypePtr = triangle;
        break;
      case SAWTOOTH:
        waveTypePtr = sawTooth;
        break;
      case SINE:
        waveTypePtr = sineWave;
        break;
      case SQUARE:
        waveTypePtr = squareWave;
        break;
      default:
        waveTypePtr = sineWave;
        break;
    }
  }  
  lcd.print(waveForms[increIndex]);
}

/*****
  This function is used to move the new frequency to the interrupt routines
  
  Parameter List:
    void
    
  Return value:
    void
*****/  
void CheckFrequency()
{
  if (frequency == oldFrequency)  // Nothing's changed...
    return;
  // The clock speed / frequency less 1 clock cycle for update divided by
  // wavefrom bits, 2^6 = 64.
  period = (CLOCKFREQUENCY / frequency - 1) / 64;
  cli();
  OCR1A = period;
  sei();
}

/*****
  This function is used to update the LCD display for any changes in the frequency.
  
  Parameter List:
    void
    
  Return value:
    void
*****/
void UpdateDisplayFrequency()
{
  lcd.setCursor(0, 0);
  lcd.print("Freq:        ");            // Faster than clear
  lcd.setCursor(LCDCOLUMNOFFSET, 0);  
  lcd.print(frequency);
}

/*****
  This function is the Interrupt Service Routine (ISR) for interrupt 2. This uses the 
  rotary encoder to increment/decrement the frequency.
  
  Parameter List:
    N/A
    
  Return value:
    N/A
*****/
ISR(PCINT2_vect) 
{
  volatile unsigned char result = myEncoder.process(); // What did they do with encoder?
  
  switch (result) {
  case 0:      
    return;
  case DIR_CW:     // Turning Clockwise, going to higher frequencies
    frequency += increment;
    break;
  case DIR_CCW:    // Lower frequencies
    frequency -= increment;
    break;
  default:
    frequency = DEFAULTFREQ;    // Default
    break;
  }

}

/*****
  This function is the Interrupt Service Routine (ISR) for Timer1. This sets
  the waveform to be used and routes the value to PORTC.
  
  Parameter List:
    N/A
    
  Return value:
    N/A
*****/
ISR(TIMER1_COMPA_vect)//timer 1 interrupt
{

  if (index >= tableVals) {
    index = 0;
  }
  PORTC = (byte)( pgm_read_byte_near(waveTypePtr + index));  
  index++; 
}

/*****
  This function is a debouce routine used to let the affected switch to stablize.
  This is based on the function by Nick Gammon: http://www.gammon.com.au/forum/?id=11488
 
  Parameter List:
    int button      the switch to settle
    
  Return value:
    void
*****/
void deBounce(int buttonPin)
{
  unsigned long now = millis ();
  do
  {
    if (digitalRead(buttonPin) == LOW)  // on bounce, reset time-out
      now = millis ();
  } while (digitalRead(buttonPin) == LOW || (millis() - now) <= ENCODERDELAY);
}

I'm embarrassed to tell you how long I've been looking at this, as it's my first use of Arduino interrupts.