Inexpensive piezoelectric elements are usually used to make sound. But in this project we will use one to generate a voltage when it is tapped lightly with a finger.
We connect the piezoelectric element to Port 1 pin 4 and ground. Now we can simply loop, sampling Port 1 pin 4 with digitalRead() or analogRead(), but that approach has two problems. First, doing things that way, we might miss an event that has a very short duration, especially if we are doing anything else in the loop. Second, and related to the first, it means that we can't do much else in the loop, for fear of missing a short event like a finger tap on the sensor.
However, the Launchpad has a feature we haven't yet used, that makes those problems go away. We can tell the Launchpad that if Port 1 pin 4 goes from low to high, we want the processor to interrupt whatever we are doing, and call one of our functions.
The function we want to have execute when the pin goes high is called felt_tap(). All it does is change a variable from false to true. We generally want to keep interrupt routines very short, so they execute quickly, and don't interrupt other processes much. It is somewhat like getting a phone call while you are driving -- if your attention is drawn away from the road for too long, bad things can happen.
The variable we are changing must be declared volatile, so the compiler knows that it can change out from under us at any moment. Otherwise the compiler might notice that it does not seem to ever change, and it might optimize the code to eliminate any uses of it.
In setup(), we tell the Launchpad that felt_tap() is supposed to be called on rising transitions of the pin by using this line:
attachInterrupt( P1_4, felt_tap, RISING );
Just for fun, we also want to use the piezo element for its more common purpose, to make noise. To do that, we need to convert the pin from an input to an output. But we also want to tell the Launchpad not to interrupt while we are using the pin as an output, because otherwise the moment we make the pin an input again, we would get an interrupt, and mistake it for a finger tap.
So the beep() function, detaches the interrupt routine from the pin using the line
detachInterrupt( P1_4 );
Then beep() set the pin to be an output, toggles it at the right frequency for the right amount of time, so we hear a beep, and then sets it back to being an input, and attaches the interrupt function again before it returns.
In our loop() function, we want to ignore any bouncing we get when the sensor is tapped. When you touch the sensor, it might give us many interrupts in a row as the sensor creates several spikes of voltage due to continued flexing of the piezoelectric ceramic. So we use the function millis() to ask how many milliseconds have elapsed since the Launchpad was turned on. Then we ignore any incoming events for the next 100 milliseconds. That gives the sensor time to settle down.
We turn on the green on-board LED when we first detect a tap. The next tap turns it off. If we are turning the green light on, we also call beep(), to give extra feedback to the user. We get an input device and an output device in the same little package.