Tải bản đầy đủ (.pdf) (10 trang)

Practical Arduino Cool Projects for Open Source Hardware- P6 docx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (205.19 KB, 10 trang )

CHAPTER 2  APPLIANCE REMOTE CONTROL
} else if(val == '2') {
// Pulse the 2nd button
Serial.println("Output 2 ON");
digitalWrite(output2, HIGH);
delay(buttonPressTime);
digitalWrite(output2, LOW);
Serial.println("Output 2 OFF");
} else if(val == '3') {
// Pulse the 3rd button
Serial.println("Output 3 ON");
digitalWrite(output3, HIGH);
delay(buttonPressTime);
digitalWrite(output3, LOW);
Serial.println("Output 3 OFF");
} else if(val == '4') {
// Pulse the 4th button
Serial.println("Output 4 ON");
digitalWrite(output4, HIGH);
delay(buttonPressTime);
digitalWrite(output4, LOW);
Serial.println("Output 4 OFF");
} else if(val == '5') {
// Pulse the 5th button
Serial.println("Output 5 ON");
digitalWrite(output5, HIGH);
delay(buttonPressTime);
digitalWrite(output5, LOW);
Serial.println("Output 5 OFF");
} else if(val == '6') {
// Pulse the 6th button


Serial.println("Output 6 ON");
digitalWrite(output6, HIGH);
delay(buttonPressTime);
digitalWrite(output6, LOW);
Serial.println("Output 6 OFF");
} else if(val == '7') {
// Pulse the 7th button
Serial.println("Output 7 ON");
digitalWrite(output7, HIGH);
delay(buttonPressTime);
digitalWrite(output7, LOW);
Serial.println("Output 7 OFF");
} else if(val == '8') {
// Pulse the 8th button
Serial.println("Output 8 ON");
digitalWrite(output8, HIGH);
delay(buttonPressTime);
digitalWrite(output8, LOW);
Serial.println("Output 8 OFF");
}
}
}
29
CHAPTER 2  APPLIANCE REMOTE CONTROL
One subtlety that may not be apparent on first inspection of the code above is what sort of data is
being examined in the series of “if” comparisons. You’ll notice that the variable that holds the data from
the serial port is of type “byte,” which is not a numeric type: it could actually be any character at all. Each
“if” condition is comparing the data in the variable “val” with a string in quotes, such as '1', or '2', not
with the actual number 1 or 2.
If that’s beyond you right now, don’t worry about it. Things like variable types will become second

nature as you spend more time working with Arduino.
Once you’ve loaded the sketch in the Arduino IDE, plug your Arduino into the USB port, select the
port from Tools
h Serial Port, select your Arduino board type from Tools h Boards, click “verify” to
compile the sketch, and if there were no errors, click “upload” to push it across to the Arduino.
ApplianceRemoteControlCompact
One thing you’ll notice from the version of the preceding program is that although it is conceptually
quite simple there is a lot of repetition in it. There are eight nearly identical lines defining output pins,
and eight nearly identical lines forcing them low. There are also eight nearly identical blocks of code in
the main loop, which makes it very long for such a simple program.
The compact version of the program uses a number of techniques to reduce the repetition in the
code.
The button press definition doesn’t change, but the definition of the output pins is much shorter
because it lists them in an array rather than defining each of them as a separate variable. We also need to
know how many outputs are listed in the array. We could have done that manually by simply counting
them ourselves and assigning that value to a variable, but then we would have to remember to change
the value if we changed the array. To avoid that problem we do a little trick that gets the total size of the
array and then divides it by the size of a single element to get the number of elements. It doesn’t actually
matter which element we use as the divisor, because every element takes up the same number of bytes
in memory. We’ll just use the first element (element 0) in this case.

// Use pins 5 through 12 as the digital outputs
int pinMap[] = {5, 6, 7, 8, 9, 10, 11, 12};
byte pinCount = sizeof(pinMap) / sizeof(pinMap[0];

As before ,we also set a variable to specify how long to pulse each button for.

//Number of milliseconds to hold the outputs on
int buttonPressTime = 250;


An array is a list of values with the positions in the array numbered from 0. What that means is that
the first entry is position 0 and has value 5, the second entry is position 1 and has value 6, the third entry
is position 2 and has value 7, and so on.
What this allows us to do is simplify the setup function because instead of listing every single pin
and setting it as an output and forcing it low, we can loop through the elements in the array and use each
one in turn.

void setup()
{
// Open the serial connection to listen for commands from the host Serial.begin(38400);

int count = 0; // Variable to store current array position

30
CHAPTER 2  APPLIANCE REMOTE CONTROL
// Set up the pins as outputs and force them LOW
for(count; count < pinCount; count++) {
pinMode(outputArray[count], OUTPUT);
digitalWrite(outputArray[count], LOW);
}
}

The for loop uses a simple counter that starts at 0 to read the first position in the array, then
increments up through the positions to read each in turn.
The biggest change is in the main program loop which no longer has to check for every possible
value explicitly, but can just check that it falls within an acceptable range.

void loop()
{
byte val; // The raw character read from the serial port

int channel; // Integer version of channel ID
// Check if a value has been sent by the host
if(Serial.available()) {
val = Serial.read();

channel = (int)val - 48; // Convert ASCII value to digit
if(channel > 0 && channel <= pinCount) {
pulseOutput(channel); // Pulse the appropriate button
}
}
}

That’s certainly a much shorter function than in the first version! There are a few things to pay
careful attention to in the new version of the loop, though.
You’ll notice that we have a new variable called “channel,” which is an integer. While reading the
serial port there is a cryptic line that sets the value of “channel” by taking the integer value of the “val”
variable and subtracting 48 from it.
What’s going on here? The byte received from the serial port is not actually a number, as you would
generally expect. It’s an ASCII value that represents a character, and that character may (or may not) be a
number. The ASCII code for the character “1” is 49, and the ASCII code for the character “2” is 50, and so
on. So when we receive a value of “1” from the serial port, the ASCII code that is transmitted (and loaded
into the variable “val”) is “49.”What that line does is “cast” (convert) the value of “val” into an integer
using the (int) prefix, then subtract 48 from it to convert it to the equivalent number. If the value sent via
the serial port is “1” it will come through as ASCII code 49, then have 48 subtracted from it, and end up
as the integer 1. The end result of all this trickery is that you send “1” at one end and get “1” out at the
other end, but unfortunately it’s not as simple as you might expect it to be!
After converting the received value, “val,” to an integer value, “channel,” it is then tested to see if
it falls inside the acceptable range from 1 to “pinCount,” which is the number of pins defined in the
array.
Finally, if that test is met, the loop calls another function called pulseOutput(channel) which is

where the actual work of firing the relay takes place.

void pulseOutput(int channel)
{
Serial.print("Output ");
Serial.print(channel);
31
CHAPTER 2  APPLIANCE REMOTE CONTROL
Serial.println(" ON");
digitalWrite(outputArray[channel - 1], HIGH); // Channel number is 1 higher than array
position
delay(buttonPressTime);
digitalWrite(outputArray[channel - 1], LOW);
Serial.print("Output ");
Serial.print(channel);
Serial.println(" OFF");
}

The pulseOutput function accepts a single integer value passed to it from the main program loop,
and then sends notification via the serial port that it is about to turn on that channel. It then looks up the
array listing the output pins (outputArray) to find the pin number that corresponds to the requested
output. Because arrays are numbered starting from 0, while our output channels are numbered starting
from 1, we have to subtract 1 from the requested channel to access the correct position in the array:
output channel 1 is array position 0, and so on.
The function then pauses briefly, turns the appropriate relay back off, and sends notification that
it’s all done.
As you can see the compact version of the program is much shorter than the original. Once you’re
used to the way things such as arrays and functions work, you’ll find it much less clumsy working with
programs structured to remove repetition using techniques such as these.
Test Reed Relay Shield and Sketch

Your Arduino should now be connected to the appliance remote control transmitter using the reed relay
shield, the transmitter should have its battery in place, and your Arduino will be listening on the serial
port for an instruction to “press” a button.
Click the “monitor” button in the IDE to switch to serial-monitor mode where you can see values
being sent to you by the Arduino and also send values to it. Select 38400 from the baud rate drop-down
box (see Figure 2-13) to match the value we set the Arduino to in the setup function.

32
CHAPTER 2  APPLIANCE REMOTE CONTROL

Figure 2-13. Serial monitor in Arduino IDE
Now for the moment of truth! Enter the value 1 into the text input area on the right and click Send or
press Enter, and you should immediately see your Arduino send you a response saying that it received
the command and is activating output 1, followed almost immediately by notification that it is turning
the output off again. If everything is working as expected your appliance should turn on, and sending a
value of 2 to the Arduino should turn it off again. You can see this at work in Figure 2-14.

33
CHAPTER 2  APPLIANCE REMOTE CONTROL

Figure 2-14. Arduino and shield using an appliance remote control to activate a lamp
Variations
Wireless Link
Rather than having the Arduino tethered to a computer, you could replace the USB connection with a
wireless link such as an XBee or 433MHz wireless module or even with an Ethernet shield to provide you
with a web-services interface to your appliances. WiFi and Ethernet connectivity are discussed in later
projects.
Automatic Trigger
The example programs rely on messages being sent to the Arduino via a serial connection. By
connecting an Arduino I/O line as an input and checking the status of a device, such as a motion

detector, it could instead trigger outputs based on events such as a motion detector being triggered, a
shop door-minder beam being broken, or a window being opened. Connecting to various devices
including security sensors is covered later in the book.
34
CHAPTER 2  APPLIANCE REMOTE CONTROL
35
Socket Connections
Using the serial monitor in the Arduino IDE is fine for testing, but to make this project useful you
probably want to be able to control devices from a scripting language such as Python, Perl, or PHP so
that events can be triggered automatically rather than manually through the IDE. A utility such as
ser2net (on Linux) or serproxy (on MacOS and Windows) will take a serial connection and expose it as a
network socket so that it can be accessed over a network. This is also a huge help when working with
scripts running on the computer directly connected to the Arduino because most scripting languages are
great at making socket connections but terrible at connecting to serial ports. Using a serial-to-network
proxy allows you to use any scripting language that can open a network socket and have it talk to your
Arduino via the USB connection as easily as if it were a network service.
There is more information on serial-to-netw
ork proxies on the Arduino web site at
www.arduino.cc/playground/Interfacing/Flash.

C H A P T E R 3

  

Time-Lapse Camera Controller
Simple digital cameras can produce remarkably good quality photos and are now cheap enough that it
doesn’t hurt the wallet too much to buy one with the intention of modifying it for use in a project. You
may even have an old digital camera lying around that you don’t mind sacrificing for a good cause!
Modifying a camera to control it from an Arduino opens up a world of possibilities. This project lets
your Arduino take control of the camera to take photos at regular intervals so they can be reconstructed

as a time-lapse movie. Set your frame interval to suit your subject and you could make a movie of plants
growing, or a house being painted, or a house being built, or flowers blooming. Time lapse movies can
be spectacular and this project will give you the tools to let your imagination run wild.
Parts Required
1 Digital camera
1 Arduino Duemilanove, Arduino Pro, Seeeduino, or equivalent
1 Prototyping shield
2 Reed relay
2 1N4001 diode or equivalent
1 3.5mm stereo socket
1 Light-dependent resistor (optional)
1 10K resistor (optional)
Camera connection for Canon:
2 3.5mm stereo line plug
50cm shielded stereo cable
Camera connection for Panasonic:
1 3.5mm stereo line plug
1 2.5mm 4-connection line plug
1 1K8 resistor
1 27K resistor
1 33K resistor
37
CHAPTER 3  TIME-LAPSE CAMERA CONTROLLER
50cm shielded mono cable
Camera connection via infrared: 1 IR LED
Source code available from www.practicalarduino.com/projects/time-lapse-
camera-controller.


Figure 3-1. Parts required for Time-Lapse Camera Controller

38

×