Please Explain IRQ_x and IRQ_Angle. Are those just different ways of labeling interrupt 1 and interrupt 2?
Yes, these are two functions to be called by IRQ 0 and IRQ 1. IRQ_x contains minimal code for the X-line and IRQ_Angle() contains the minimal code to count the pulses per rotation.
What about the #define 800? I understand it is telling the arudino that there is 800 PPR, but exactly how does that work?
#define PPR 800
is a so called compiler directive, when the compiler read teh sourcecode it will replace the word PPR with the integer value 800. This makes it easy to use the same value anywhere in your code and just one place to maintain it. By choosing a good acronym PPR stands for PulsesPer Rotation as you have guessed
it keeps your code readable to a certain extend. So the compiler replaces "2 * PPR /4" with "2 * 800/4" and the optimizer sees it are all constants so it will code "200".
Also for the PPRcounter == 1*PPR/4, I assume that I just use this simple algebra to make it equal the count I am looking for
.
Yes
Is there a more elegant way of doing so? For example, this is only hypothetical, but if I wanted the valves to fire 16 different times in one revolution, I would have to write 16 different else statements... not including the extra code for how long the valves are open.
Two thoughts come into my mind, the switch statement and using an array.
The switch variant might look better but it has no performance gain wrt the - if then else if ... - construct
void IRQ_Angle()
{
switch(PPRcounter)
{
case 0: digitalWrite(valvePin, OPEN);
break;
case 200: digitalWrite(valvePin, CLOSE); // replace 200 with 1*PPR/4
break;
case 400: digitalWrite(valvePin, OPEN);
break;
case 600: digitalWrite(valvePin, CLOSE);
break;
}
PPRcounter ++;
}
An array implentation is a bit more complex, you need to define two arrays of values when to open and when to close the valves. In the code below the valves will stay open for 40 pulses 4 times every rotation (@800PPR => 1/20 rotation @ 2000RPM => 1.5 msec) This code is extendible by making the array larger e.g. 8, 12, 16 or 23 values.
int open[4] = { 0, 200, 400, 600};
int close[4] = { 40, 240, 440, 640};
void IRQ_Angle()
{
PPRcounter ++;
for (int i = 0; i< 4; i++)
{
if (PPRCounter == open[i])
{
digitalWrite(valvePin, OPEN);
return;
}
if (PPRCounter == close[i])
{
digitalWrite(valvePin, CLOSE);
return;
}
}
Here a simple sample sketch I made for you to test the rotary encoder. It does not include the switch or array variant but at least it compiles. It outputs the counters and the RPM every second. It let blink the Arduino LED at (0,3,6,9 oclock) Please give it a try
//
// FILE: Rotary.pde
// AUTHOR: Rob Tillaart
// DATE: 2011-03-17
//
// PUPROSE: proof of concept IRQ's for rotary encoder
//
///////////////////////////////////////////////////
//
// VALVE SIMULATOR
//
#define OPEN HIGH
#define CLOSE LOW
#define VALVEPIN 13 // use the LED as pseudo valve
void valve(int newState)
{
digitalWrite(VALVEPIN, newState);
}
///////////////////////////////////////////////////
//
// DEFINES AND VARS
//
#define PPR 800
volatile unsigned long PPRcounter = 0;
volatile unsigned long RotCounter = 0; // to measure RPM
unsigned long start = 0;
unsigned long RPM = 0;
// when line X is rising it resets the PPRcounter every rotation
void IRQ_X()
{
PPRcounter = 0;
RotCounter++;
}
// line A
void IRQ_Angle()
{
if (PPRcounter == 0 * PPR / 4) valve(OPEN);
else if (PPRcounter == 1 * PPR /4) valve(CLOSE);
else if (PPRcounter == 2 * PPR /4) valve(OPEN);
else if (PPRcounter == 3 * PPR /4) valve(CLOSE);
PPRcounter++;
}
///////////////////////////////////////////////////
//
// INITIALIZE
//
void setup()
{
Serial.begin(115200);
Serial.println("Rotary test 0.1");
pinMode(13, OUTPUT); // ledpin;
// LINE X connects to pin 2
attachInterrupt(0, IRQ_X, RISING);
// LINE A connects to pin 3
attachInterrupt(1, IRQ_Angle, RISING);
start = millis();
}
///////////////////////////////////////////////////
//
// GO !
//
void loop()
{
// once per second
if (millis() - start > 1000)
{
start = millis();
RPM = RotCounter * 60 + (PPRcounter * 60)/PPR;
Serial.print(RotCounter, DEC);
Serial.print(", \t");
Serial.println(PPRcounter, DEC);
Serial.print(", \t");
Serial.println(RPM, DEC);
}
}
OK, enough to keep you busy I guess 