This is a first proof of concept for a universal camera shutter control. The goal is to turn a camera on/off as well as controlling its shutter. Both functions are controlled with one radio channel (3 position switch) from an r/c receiver. The green LED signals that the camera has been turned on and the red LED that the shutter is operated with a predefined interval.
I want to trigger additional logic in an UAV when I flip a 3 position switch on my R/C transmitter. This sketch will decode a PPM signal from an R/C receiver and will turn on two LEDs depending on switch position.
The code compiles for a Sparkfun Pro Micro 16MHz and also on an ATtiny85:
/** * Read PPM signal * * Decode r/c receiver PPM servo signal and turn lights on * according to servo position. * * $Id$ */// from which pin to read.
#define PIN_PPM 9
#define PIN_POS1 10
#define PIN_POS2 16
unsignedlong duration, lastgood = 0;
intposition = 0;
voidsetup() {
pinMode(PIN_PPM, INPUT);
pinMode(PIN_POS1, OUTPUT);
pinMode(PIN_POS2, OUTPUT);
digitalWrite(PIN_POS1, LOW);
digitalWrite(PIN_POS2, LOW);
}
voidloop() {
// the length of the pulse (in microseconds) or 0 if no pulse // started before the timeout (unsigned long)
/**
* Pro Micro 5V / BlueSMiRF Test
*
* Pro Micro has 2 Serial adapters. One on the USB port (Serial), another on
* pin 11 (RX) and 12 (TX) (known as Serial1).
*
* This program will transmit data received on Serial to Serial1 and Serial1
* to Serial. This can be useful when a bluetooth adapter must be hooked up to
* an usb port.
*
* Pins
* VCC to VCC (3.3-6V)
* GND to GND
* TX-O to RX-I
* RX-I to TX-O
*
* LEDs
* Orange: USB receive, Bluetooth transmit
* Green: Bluetooth receive, USB transmit
*
* $Id$
*/voidsetup() {
Serial.begin(115200); // USBSerial1.begin(115200); // BlueSMiRF
}
voidloop() {
if (Serial.available())
Serial1.write(Serial.read());
if (Serial1.available())
Serial.write(Serial1.read());
}
The default baud rate of the BlueSMiRF Gold is 115'200 baud. Using an FTDI cable from sparkfun, 3V or 5V will do), the following pins must be connected:
FTDI connector:
BlueSMiRF Gold connector:
Wiring it up to the FTDI connector:
VCC to VCC (3.3-6V)
GND to GND
TX-O to RX-I
RX-I to TX-O
The BlueSMiRF is now power via the FTDI's VCC. So, it's time to
connect it to an USB port. Via /var/log/messages (on some linux systems
it's in /var/log/syslog?) you ca check the name of the device
$ grep tty /var/log/messages | tail -n1
Jul 4 20:31:58 shell1 kernel: [4027300.342679] usb 8-1: FTDI USB Serial Device converter now attached to ttyUSB0
This means it is connected to /dev/ttyUSB0 in m case.
Now it's time to use a serial terminal such as minicom, screen or in my case PuTTY:
Serial line: /dev/ttyUSB0
Speed: 115200
Connection type: Serial
That's it. You will be greeted with an empty prompt. At the prompt, enter '$$$' and hit the key. You should get an CMD
as response. Otherwise you most probably have chosen the wrong tty port
or baud rate. Also, you need to enter '$$$' in the first 60 seconds
after power up or the command won't be recognized.
Entering help will bring up the ist of available commands:
*** SET COMMANDS ***
SA,<1,0> - Authentication
SB, - Send Break
SC, - Service Class
SD, - Device Class
SE,<1,0> - Encryption
SF,1 - Factory Defaults
SI, - Inquiry Scan Window
SJ, - Page Scan Window
SL, - Parity
SM,<0-5> - Mode (0=slav,1=mstr,2=trig,3=auto,4=DTR,5=Any)
SN, - Name
SO, - conn/discon Status
SP, - Pin Code
SR, - Remote Address
SS, - Service Name
ST, - Config Timer
SU, - Baudrate
SW, - Sniff Rate
SX,<1,0> - Bonding
SY, - TX power
SZ, - Raw Baudrate
S7,<0-1> - 7bit data
S~,<0-3> - Profile (0=SPP,1=DCE,2=DTE,3=MDM,4=D&S
S?,<0-1> - role switch
S$, - CMD mode char
S@, - io port dir
S&, - io port val
S%, - io boot dir
S^, - io boot val
S*, - pio(8-11) set
S|, - low power timers
*** DISPLAY ***
D - Basic Settings
E - Extended Settings
G - Stored setting
GB - BT Address
GK - Connect Status
G& - I/O Ports
V - Firmare version
*** OTHER ***
C, - Connect
F,1 - Fast Mode
I,
All I needed to do was changing the name to something more specific to the device I was building (and wile I was at it, I changed the pin code needed for pairing):
I use gedit to write simple C programs. The External Tools plugin is really helpful for compiling and running them. Here is a simple example to invoke gcc and run the compiled file:
#!/bin/sh
EHOME=`echo $HOME | sed "s/#/\#/"`
DIR=$GEDIT_CURRENT_DOCUMENT_DIR
BASENAME=`echo "$GEDIT_CURRENT_DOCUMENT_NAME" | sed -e 's/\.c$//'`
cd "$GEDIT_CURRENT_DOCUMENT_DIR"
date
gcc -o "$BASENAME" "$GEDIT_CURRENT_DOCUMENT_NAME"
Yay the joy. I have just etched the PCBs for the final production Boards.
Update: it turns out that this is still a prototype (the hardware is not yet production ready).
What is it? This board (once finished) will be able to launch fireworks trough electric fuses controlled by a Bluetooth device (I plan to write an Android app).
I have found many long winded HOWTOs on doing this, I love mini howtos, here we go:
I am using an Arduino UNO with Arduino IDE 0022.
The Arduino IDE needs some hardware information to support the ATtiny45/ATTiny85. Download the following zip file, create a hardware folder in your sketches folder and unzip it into the newly created hardware folder (you should now have the following folder structure in your sketches folder: hardware/attiny45_85/). Restart the Arduino IDE.
Flash your Arduino with the ArduinoISP sketch (File » Examples » ArduinoISP, compile and upload).
Connect the ATtiny45 or ATtiny85 to your Arduino as shown below:
(use a 10 uF capacitor between reset and ground, - on the capacitor goes to GND).
Pin layout of ATtiny45/ ATtiny85
That's it. Select "Tools » Board » ATtiny45 (w/ Arduino as ISP)" as board and you are good to go. While uploading the Arduino IDE will show the error "avrdude: please define PAGEL and BS2 signals in the configuration file for part ATtiny45". This doesn't have an effect, just disregard it.
To check if it works you may connect a LED from pin0 to GND and upload the following blink sketch (the LED will also flash on activity during MOSI while uploading a sketch).
// Blink for ATtiny45/ATtiny85
#define PIN_LED 0
voidsetup() {
// initialize the digital pin as an output.// Pin 13 has an LED connected on most Arduino boards:pinMode(PIN_LED, OUTPUT);
}
voidloop() {
digitalWrite(PIN_LED, HIGH); // set the LED ondelay(1000); // wait for a seconddigitalWrite(PIN_LED, LOW); // set the LED offdelay(1000); // wait for a second
}
a little example in C on how to display an integer in hex an binary:
/**
* Name : bitwise.c
* Author : wus
* Version : $Id: bitwise.c 13 2012-04-23 15:37:41Z wus $
* Copyright : GPL
* Description : Print an 8-64 bit integer in hex and binary to stdout.
*
* NOTE: gcc needs the -lm option enabled to include the math library (must add
* -lm after the source file, WTF?)
* NOTE: compile flags: $ gcc -ofilename filename.c -lm
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
int int_size = 64; // num bits of integer
void usage(void) {
printf("Usage: bitwise <%d bit int>\n\n", int_size);
printf("Exit codes:\n");
printf(" 2 argument error\n");
printf(" 3 overflow error\n");
}
char dec2hex(int digit) {
if (digit < 10) return (digit + 48);
switch(digit) {
case 10: return 'A';
case 11: return 'B';
case 12: return 'C';
case 13: return 'D';
case 14: return 'E';
case 15: return 'F';
}
return '*';
}
/**
* generate binary and hex string from an integer
*
* loop bit for bit (MSB) over an integer, generate binary and hex string
*
* param num: the number
* param result: max. 64 bits + 7 spaces (pairs by 4 and an ending \0
* param hex: hex representation, 8 digits and one \0
* param int_size: number of bits to represent in the output
*/
void format_bin(uint64_t num, char result[78], char hex[9], int int_size) {
int pos_bit, pos_string = 0;
int pos_hex = int_size / 4 - 1;
int str_size = int_size + (int_size/4 - 1);
hex[pos_hex] = 0;
for(pos_bit=0; pos_bit < int_size; pos_bit++, pos_string++) {
// add spaces
if (pos_bit % 4 == 0 && pos_bit != 0) {
result[str_size - 1 - pos_string++] = ' ';
}
// check if current bit is set
int t = ((num & (1L<<pos_bit)) ? 1 : 0);
result[str_size - 1 - pos_string] = t + 48;
// handle hex
int pot = pos_bit % 4;
if (t) {
switch (pot) {
case 0: hex[pos_hex] += 1; break;
case 1: hex[pos_hex] += 2; break;
case 2: hex[pos_hex] += 4; break;
case 3: hex[pos_hex] += 8; break;
}
}
// next character
if (pot == 3) {
// make sure the int is a character and store it in the
// result hex string
hex[pos_hex] = dec2hex(hex[pos_hex]);
hex[--pos_hex] = 0;
}
} // end for loop
hex[int_size/4] = '\0';
result[str_size] = '\0';
}
/**
* generate binary and hex representation of an integer value
*/
int main(int argc, char* argv[]) {
if (argc != 2) {
usage();
exit(2);
}
int arg1 = atoi(argv[1]);
// check overflow
if (arg1 > (pow(2, int_size) - 1)) {
printf("Overflow detected, we can handle max. %d bit integers!\n\n",
int_size);
usage();
exit(3);
}
uint8_t input = arg1;
char str[78];
char hex[9];
format_bin(input, str, hex, int_size);
printf("\n0x%s - %s\n", hex, str);
return EXIT_SUCCESS;
}
#include <math.h> in gcc will not automatically pull in the math implementation only the header. To make a file with this include compile you need to add -lm on the command line (linker option). To make it a bit more convenient, in my case I had to add the option after the source file on the command line.
Automating tasks is what I do now and then and keep forgetting. This is the reason I keep a log of interesting information (interesting to me). My primary platform is Debian, most things here will work out of the box on Debian.