Continued from last post
I have covered the project scope, the hardware involved, and the digital patterns we have to reproduce. What's left is the code to make it all happen. I have two sketches, Arduino parlance for source code. The first was written without using the motion detector. Instead, the user is prompted to input an "a" or "b" at the keyboard. An "a" transmits the code to take a picture. Pressing "b" is like pushing the camera exposure button halfway down. The second sketch, presented in the next post, incorporates the motion detector and eliminates the keyboard input.
I am using the Arduino IDE (Integrated Development Environment) to write the sketch, compile the sketch, verify the C code, and upload the machine code to the microcontroller. The only IDE function we cannot use is its serial monitor which provides screen output and keyboard input. The IDE's serial monitor requires a USB connection (as would be used with an actual Arduino product). The Gertboard has no USB. If we wish to send and receive data from the microcontroller, we need an alternative.
That alternative is a terminal program called Minicom. It's like the old DOS Telex program used to talk over the modems we used in the old days. The Gertboard User Manual talks us through its installation and configuration. Minicom communicates through the UART(Universal Asynchronous Receiver/Transmitter) port. This two pin port is signified by the pins TX and RX, both on the microcontroller and the Pi/Gertboard. See the block diagram two posts ago. TX of the Pi is connected to RX of the microconroller, while RX of the Pi connects to TX of the microcontroller. The stdio program we usually use for the Raspberry Pi is LXTerminal. Even though it has "Terminal" in its name it's really a command line program. If fact, as we do with most programs, we launch Minicom from LXTerminal.
Let's take a look at the script:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*This script will contol the remote control for the Canon camera. | |
Uses WRL-10534 433MHz transmitter | |
Gertboard Connections: | |
Connect J25 PB5 to J3 B1 and jumper P2 B1 output. | |
Data in to transmitter connects to J10 BUF 1 | |
This version does not use the motion detector. | |
Pattern to the transmitter is controlled by user input. | |
Martin Lyon, thepiandi.blogspot.com | |
August 15, 2013 | |
*/ | |
int inByte = 0; | |
unsigned int one_pulse = 415; //In Microseconds | |
char prompt[ ] = "Press A to take picture. Press B to press half way: "; | |
char pattern_1[ ] = "LHLHLEAABBAAAAAABABAABBABBBABBBBBBBABBLT"; | |
char pattern_2[ ] = "LHLHLEAABBAAAAAABABAABBABBABBBBBBBABBBLT"; | |
boolean good_input; | |
// Digital output connected to digital 13 (PB5). | |
int outpin = 13; | |
void transmit(boolean is_high, unsigned int pulses1, unsigned int pulses2) | |
{ | |
if (is_high) // if is_high is true, initial pulse is high | |
{ | |
digitalWrite(outpin, LOW); | |
} | |
else | |
{ | |
digitalWrite(outpin, HIGH); | |
} | |
delayMicroseconds(pulses1 * one_pulse); | |
if (pulses2 > 0) | |
{ | |
if (is_high) | |
{ | |
digitalWrite(outpin, HIGH); | |
} | |
else | |
{ | |
digitalWrite(outpin, LOW); | |
} | |
delayMicroseconds(pulses2 * one_pulse); | |
} | |
} | |
void send_bits(char pattern[ ]) | |
{ | |
for (int i = 0; i < 40; i++) | |
{ | |
switch(pattern[i]) // true in below means first pulse is a high | |
{ | |
case 'L': // Pulse low, 1 pulse width duration | |
transmit(false, 1, 0); | |
break; | |
case 'H': // Pulse high, 1 pulse width duration | |
transmit(true, 1, 0); | |
break; | |
case 'A': // Pulse low, 1 pulse width; followed by pulse high, 3 pulse widths long | |
transmit(false, 1, 3); | |
break; | |
case 'B': // Pulse high, 3 pulse widths; followed by pulse low, 1 pulse width long | |
transmit(false, 3, 1); | |
break; | |
case 'E': // Pulse high for 8 pulse widths duration | |
transmit(true, 8, 0); | |
break; | |
case 'T': | |
transmit(true, 34, 0); // Final long high, 34 pulse widths duration | |
} | |
} | |
} | |
void setup() | |
{ | |
//Start Serial Port at 9600 bps: | |
Serial.begin(9600); | |
Serial.print(prompt); | |
//Initialize digital PB5 as an output | |
pinMode(outpin, OUTPUT); | |
} | |
void loop() | |
{ | |
// Main Part of Program | |
//Set output low. | |
digitalWrite(outpin, LOW); | |
//Prompt for user input | |
Serial.print(prompt); | |
//Look for keyboard input | |
good_input = false; | |
do | |
{ | |
if (Serial.available() > 0 ) | |
{ | |
//get input | |
inByte = Serial.read(); | |
Serial.println(char(inByte)); | |
if (char(inByte) == 'A' || char(inByte) == 'a' || char(inByte) == 'B' || char(inByte) == 'b') | |
{ | |
good_input = !good_input; | |
} | |
else | |
{ | |
Serial.println(" Please - A or a or B or b"); | |
Serial.print(prompt); | |
} | |
} | |
}while(!good_input); | |
// Send bits to output pin | |
for (int i = 0; i < 3; i++) // repeat pattern three times | |
{ | |
if (char(inByte) == 'A' || char(inByte) == 'a') | |
{ | |
send_bits(pattern_1); | |
} | |
else | |
{ | |
send_bits(pattern_2); | |
} | |
} | |
} | |
Thanks to the Arduino IDE, writing the script (C code) and getting the code onto the microcontroller is simplified. The functions for serial communications, time delays, and handling digital and analog inputs and outputs to the ATmega device are available without adding libraries. There are not even any #include statements in my script. Once you write the script, you don't worry about makefiles. One click handles compiling the code and uploading the machine code to the microcontroller. All of the built-in functions as well as basic C language is included in a very useful help reference. There are other libraries included in the software, as well, that you can include in your scripts. For example, there is a library for the 16x2 LCD displays, and a 1 Wire library (see my temperature sensor posts).
My script is divided into three parts: variable assignments, functions I have written, and the main part of the program. The main part of the program is divided into two parts: a "setup:, and "loop", as required by the IDE. "setup" runs when you first apply power, or first upload the code. It establishes the UART baud rate at 9600 bps and makes the ATmega pin we connect to the RF transmitter an output. "loop" runs continuously after that.
Looking at the variable assignments, there is something I do not understand. You see the variable "one_pulse", it establishes the minimum pulse width in microseconds. This is the time for the "H" or "L" pulse (see below), the time for all other characters are multiples of the time for "H" and "L". From the Audacity display, using the camera remote control transmitter, I calculated the time for "one_pulse" to be 284 microseconds. The time in my script, after altering "one_pulse" to match the patterns, is 415 microseconds, a difference of 46%. I've done a bunch of testing, and it's a mystery to me. If anyone has an idea please let me know.
The heart of the script is the two functions, "send_bits" and "transmit". As we cycle through the pattern we send the characters to "send_bits" then "send_bits" passes the definition of each character to "transmit". "transmit" sends the pattern to the microcontroller. I've repeated the diagram from the last post here to make it clearer how the characters, "H", "L", "E", "A", "B", and "T" are defined:
An important note: The 434 MHz transmitter inverts the bit logic. If I send a low pulse from the microcontroller, to the RF transmitter, the RF transmitter sends a high pulse. That is why a low is written to outpin when the variable "is_high" is true. I think the rest of the code should be pretty straight forward.
No comments:
Post a Comment