See also: Part 1, Part 1b, Part 2, and Part 3.
In Part 1: How I got started with Arduino, I discussed a bit of my background and how I came to experiment with an Arduino to solve a particular problem in a haunted house attraction. We were needing something that was capable of reading a switch (like a push button), and sending out a serial message to the COM: port of a PC. Since the $200 Wal-Mart netbooks we were using were modern and had no RS232 ports, the device needed to speak USB or else we would have to use a USB to RS232 adapter, like the FTDI one I used for programming BASIC Stamps.
After a quick experiment with a coworkers Arduino, I discovered it was capable of sending out serial data via the USB port. The device appeared to the host PC as if it was a COM: port, and all one had to do was write a message out in the Arduino code:
Serial.println("Hello, world!");
My initial research about reading switches/buttons on an Arduino led me to a button tutorial on the official Arduino website. It showed that all I needed was a switch (like the pressure mats folks would step on inside the haunted house) and a 10K resistor. I was able to borrow such a resistor from our hardware lab.
Using the diagram on the tutorial site, I stuck one end of the resistor in to the GND header pin socket on the Arduino, then wrapped a wire around the other end and connected it to Pin 2. I wrapped a second wire on the same end, and then, to simulate a switch, I would plug and unplug the end of that wire in to the 5V header pin socket. Their sample code was able to read it as a switch!
During this research, I discovered that the Arduino didn’t actually need the resistor to do this. It had “pull up” resistors built in, and they could be enabled in software. A tutorial on the Digital Pins would explain this to me. Basically, you chose a pin and set it to input, then used a digitalWrite() call to enable the pullup resistor:
pinMode(pin, INPUT); // set pin to input
digitalWrite(pin, HIGH); // turn on pullup resistor
With this, I could simple put a switch between GND and the PIN and it would work with no extra resistors needed. In fact, it looked as if we could just wire all the mat switches up to various Digital Input pins and be set.
Unfortunately, the early experimental code (see Part 1) had some issues. I will dissect it and explain:
First, I defined the range of Digital Input pins I would be using. Pins 0 and 1 were reserved for talking to the serial port (TX, transmit, and RX, receive), leaving pins 2 through 14 available. I used #define macros so I could change these pin numbers in one place without having to touch the code. I also needed the number of how many pins were in use, so I made a second macro that just subtracted the END from START to get that number:
#define DI_PIN_START 2
#define DI_PIN_END 14
#define DI_PIN_COUNT (DI_PIN_END - DI_PIN_START)
Next, I needed to know the status of each pin so I could tell if it changed. I created an array of integers to hold the status values:
int pinStatus[DI_PIN_COUNT];
For the setup routine, I would initialize each pin for input, then read the status of each pin and store it in the array. I would also initialize the serial port, based on examples from the Arduino site:
void setup()
{
// Initialize the pins and pinStatus array.
for (int thisPin=0; thisPin < DI_PIN_COUNT; thisPin++ )
{
pinMode(thisPin+DI_PIN_START, INPUT_PULLUP);
pinStatus[thisPin] = digitalRead(thisPin);
}
// Initialize the serial port.
Serial.begin(9600);
while(!Serial) {
;
}
}
The main loop of the program would be very simple. I would loop through each pin and read its current status. If the status was different from the saved status, I knew it changed (button pressed, or button released). Since I wanted to send out serial data to represent the pins, I chose a simple single character, with UPPERCASE meaning “button pressed” and lowercase meaning “button released”. Since I had learned that the pin status was either a 0 or 1, I used that to determine if I should print UPPERCASE or lowercase. As I looped through the pins (0 through Max), I would print the character “A” (char 65) plus the pin number (thus, 0 would be A, 1 would be B, etc.). To tell if it was upper or lower, I took the status and multiplied it by 32. In the ASCII character set, 65 is where the uppercase alphabet starts, and 97 (32 higher) is where the lowercase alphabet starts. If status was 1, I would be adding 32 to the number (status*32). If status was 0, I would be adding 0 to the number (0*32) leaving it uppercase.
It was a quick and dirty way to do it, and it looked like this:
void loop()
{
int status = -1;
for (int thisPin=0; thisPin < DI_PIN_COUNT; thisPin++ )
{
status = digitalRead(thisPin+DI_PIN_START);
// Is pin status different from last time we read it?
if (pinStatus[thisPin]!=status)
{
pinStatus[thisPin] = status;
Serial.println(char((97+thisPin)-(status*32)));
}
}
}
This would indeed print out a series of characters based on which pin was connected. Going through all of them might produce:
AaBbCcDdEe
But, it seemed the action of making the connection would sometimes cause many characters to emit:
AaAaAaAaBbBbCcCcCc
Only if I was very quick with the connection could I prevent that. I was familiar with this problem, thanks to getting started with home computers in the early 1980s. The keyboard of my TRS-80 Color Computer was a matrix of switches, and it contained code in the BASIC ROM to do “denouncing”. Basically, it wouldn’t report that a switch was connected until it had been connected for some small amount of time. Thus, these jitters as the connection was being made would be smoothed out, and not detected.
I would need to add debounce code to my DItoSerial routine.
Until the next part, here is the Arduino tutorial on Debouncing switches. I will discuss how I did it in an upcoming posting.
Until then…
Pingback: Part 3: Debouncing digital inputs. | Appleause
Pingback: Part 3: Debouncing digital inputs. | Sub-Etha Software
Pingback: Part 1: How I got started with Arduino. | Sub-Etha Software