/* Landside KAP Controls, based on AtMega168 & Xbee Licensed under The MIT License Copyright (c) 2007-2008 Ben Peoples - ben@benpeoples.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Assumes Xbee is already configured via other interface. Serial commands: L = Rotate "left" (Servo = 1000) R = Rotate "right" (Servo = 2000) X = Stop rotating S = Take picture T + Byte = Set tilt to byte, 0 = Horizontal, 255 = Vertical M = Set mode to manual (all functions manual control) I = Set mode to Intervalometer (all functions manual, shutter triggers every INTERVAL or INTERVAL*6 (see switches) -- responds to all commands (including "S") A = Set mode to Autokap (Manual tilt, shutter & 350ms Pan every INTERVAL) N = "New Mode" Undefined as yet. Autokap Timeout: The TX should send "X" or mode commands periodically to the RX -- if no signal is recieved within 5 seconds, it will go into autokap mode assuming it is out of range of the receiver. HOWEVER if SW2 is on, the RX will not do this. Debounce: This program's debounce routine polls the switches on a F_CPU/64 interval (about 1/990th of a second), it increments or decrements a counter by one. When that counter hits an end value (0 or 20) the switch is consered thrown. As long as the switch doesn't sit in the wrong state for more than 20ms, it should debounce just fine. Overall Theory: I developed this program for my own controller, but bits of it could be useful to someone else, of course. The idea is to have a controller than can adapt between autokap, intervalometer, and fully manual -- including the option to swtich to autokap if it loses contact with the reciever. It's got pins for a software uart for LCD. ToDo List: - Watchdog Timer Please note that I only code casually, and have actually written quite a bit more in lisp than in C. I'm still a bit afraid of pointers, so some things are written less efficiently than possible. Feel free to offer code snippets and bugfixes & reports back. */ #include #include "device.h" #include #include #include "uart.h" #include "bitfield.h" #include "analog.h" #include "math.h" #include // Global Variables & defines uint8_t shuttermode=0, panmode=0, tiltsetting=0, mode=0, switches=0; uint16_t interval_counter=0; uint8_t sh1bounce=0, sh2bounce=0, pan1bounce=0, pan2bounce=0, mode1bounce=0, mode2bounce=0, tilt=0; // Prototypes void blink(unsigned char i); // Blink just blinks the LED the specified # of times void longsleep(unsigned char time); // 10ths of a second to sleep void pollswitches(); // Polls switches and spits out the uart the changes int blinkalt(unsigned int i); // blinks 10's and 100's out the LED void ledon(void); void ledoff(void); int main (void) { uint8_t c=0; uint8_t alt=0; // Initialize the Inputs _DDRC.B0 = 0; // tilt pot _DDRC.B1 = 0; _DDRC.B2 = 0; _DDRC.B3 = 0; _DDRC.B4 = 0; _DDRD.B6 = 0; _DDRD.B7 = 0; _DDRB.B4 = 0; _DDRB.B5 = 0; _PORTC.B1 = 1; // Internal pull-ups _PORTC.B2 = 1; _PORTC.B3 = 1; _PORTC.B4 = 1; _PORTD.B6 = 1; _PORTD.B7 = 1; _PORTB.B4 = 1; _PORTB.B5 = 1; // Use servo_set(servo, position); // Initialize Uart (Xbee or FTDI) uartInit(); uartSetBaudRate(115200); analog_init(); cli(); TIMSK0 |= _BV(TOIE0); TCNT0 = 0; TCCR0B = 3; sei(); blink(2); for(;;) { pollswitches(); //uartGetByte(); } return 0; } int blinkalt(unsigned int i) { int count, delay; for(count = 0; count < i; count++) // 150ms flash for digit { LED_PORT |= (1 << LED0); for(delay = 0; delay < 25; delay++) { _delay_ms(10); } LED_PORT &= ~(1 << LED0); for(delay = 0; delay < 10; delay++) { _delay_ms(10); } } if(i == 0) // 50ms flash for 0 { LED_PORT |= (1 << LED0); for(delay = 0; delay < 5; delay++) { _delay_ms(10); } LED_PORT &= ~(1 << LED0); for(delay = 0; delay < 15; delay++) { _delay_ms(10); } } for(delay = 0; delay < 35; delay++) // 350ms delay between digits { _delay_ms(10); } return 0; } void pollswitches() { // Globals: uint8_t shuttermode=0, panmode=0, tiltsetting=0, mode=0, switches=0; // More: uint8_t sh1bounce=0; sh2bounce=0; pan1bounce=0; pan2bounce=0; mode1bounce=0; mode2bounce=0, tilt=0; /* Command Summary: T + byte = Set tilt to sent byte, 0-255, which is @ controller translated to a time. (tiltsetting = last byte) S = take a picture (shuttermode = 0 if no picture taken, 1 if picture taken to keep from sending multiple, controller blacks out during picture. May need to debounce switch in this loop) L = pan left R = pan right X = stop panning Modes: M = 00 = Full manual I = 01 = Intervalometer A = 10 = Autokap N = 11 = Reserved Switches: 00 = 01 = 10 = 11 = */ if(tilt != tiltsetting) { // ledon(); tiltsetting = tilt; uartSendByte('T'); uartSendByte(tilt); } // Begin Shutterblock (Works!) if(shuttermode == 0) { if(sh1bounce == 20) { shuttermode=1; uartSendByte('S'); } else if(sh2bounce == 20) { shuttermode=1; uartSendByte('S'); } else if(sh1bounce == 0 && sh2bounce == 0) { shuttermode=0; } } else if(shuttermode == 1 && sh1bounce == 0 && sh2bounce == 0) { shuttermode = 0; } // End Shutterblock (works!) if(pan1bounce == 20 && panmode == 'X') { panmode = 'L'; uartSendByte('L'); //ledon(); } if(pan2bounce == 20 && panmode == 'X') { panmode = 'R'; uartSendByte('R'); //ledon(); } if(pan1bounce == 0 && pan2bounce == 0 && panmode != 'X') { panmode = 'X'; uartSendByte('X'); //ledoff(); } if(mode1bounce == 0 && mode2bounce == 0 && mode != 'M') { mode = 'M'; uartSendByte('M'); } else if (mode1bounce == 20 && mode2bounce == 0 && mode != 'I') { mode = 'I'; uartSendByte('I'); } else if (mode1bounce == 0 && mode2bounce == 20 && mode != 'A') { mode = 'A'; uartSendByte('A'); } else if (mode1bounce == 20 && mode2bounce == 20 && mode != 'N') { mode = 'N'; uartSendByte('N'); } /* Future DIP switches */ } void blink(unsigned char i) { unsigned char c; unsigned int delay; for(c=0;c0) { sh1bounce--; } } if(sh2==0) { if(sh2bounce<20) { sh2bounce++; } } else { if(sh2bounce>0) { sh2bounce--; } } if(pan1==0) { if(pan1bounce<20) { pan1bounce++; } } else { if(pan1bounce>0) { pan1bounce--; } } if(pan2==0) { if(pan2bounce<20) { pan2bounce++; } } else { if(pan2bounce>0) { pan2bounce--; } } if(mode1==0) { if(mode1bounce<20) { mode1bounce++; } } else { if(mode1bounce>0) { mode1bounce--; } } if(mode2==0) { if(mode2bounce<20) { mode2bounce++; } } else { if(mode2bounce>0) { mode2bounce--; } } }