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.