RCSwitch
From JimWIKI
this project is based on the Wag Switch by the RC Groups member 'AleG' (Alejandro Garcia) and discussed in this Thread
//********* Wag Switch *********//
// //
// Author : Alejandro Garcia //
// Target : ATTiny13V //
// Clk Speed: 9.6Mhz : //
// Version : 1.00 //
// Date : 26-12-08 //
//*******************************//
#define F_CPU 9600000UL // 9.6MHz
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
volatile unsigned int Tick; // Timer count variable
volatile unsigned char sPulse; // Incoming servo pulse measured length
volatile unsigned int sPulseIn; // Incoming servo pulse measurement
volatile unsigned char ServoCurrent; // Current position of the output servo
volatile unsigned char ServoTarget; // Target position of the output servo
unsigned char Right_1; // Stick on right position flag
unsigned char Left_1; // Stick on left position flag
unsigned int pRight; // Right sPulse threshold
unsigned int pLeft; // Left sPulse threshold
unsigned char window; // Window of opportunity to switch states
unsigned char restore_SREG; // SREG status temporary store
unsigned char ServoStep; // Step the servo in one direction
unsigned char ServoSubStep; // Controls speed of servo rotation
int main (void)
{
sei(); // Enable global interrupts
DDRB &= ~(1<<PB1); // PB1 as input
DDRB |= (1<<PB0) | (1<<PB2) | (1<<PB3) | (1<<PB4); // PB0 and PB2 as output
TCCR0A |= (1<<WGM01); // Configure timer 1 for CTC mode
TIMSK0 |= (1<<OCIE0A); // Enable CTC interrupt
OCR0A = 95; // Set CTC compare value
TCCR0B |= (1<<CS00); // No prescaler
GIMSK |= (1<<INT0); // Enable INT0 interrupt
MCUCR |= (1<<ISC00) | (1<<ISC01); // INT0 interrupt on rising edge
Tick = 0; // Initialize timer at 0
ServoCurrent = 100; // Initialize output servo at far left position
ServoTarget = 100; // Initialize output servo target at far left position
sPulse = 150; // Set initial state of pulse width
pRight = 175; // Long pulse threshold
pLeft = 125; // Short pulse threshold
window = 5; // Time window for stick motion
while(1)
{
sei(); // Enable interrupts
/*Monitor if stick is left or right*/
if(sPulse >= pRight) // True if stick right past threshold
{
Right_1 = 1;
}
if(sPulse <= pLeft) // True if stick left past threshold
{
Left_1 = 1;
}
/*Evaluate Right-Left-Right condition*/
while(Right_1) // While stick is right
{
Left_1 = 0;
for(int i = 0; i<=window; i++) // Wait for stick to move left (R-?-?)
{
PORTB |= (1<<PB2); // Wait loop, display blinking LED on pin 7
_delay_loop_2(10000);
PORTB &= ~(1<<PB2);
_delay_loop_2(10000);
if(sPulse <= pLeft) // If stick moved left before end of wait period
{
Left_1 = 1;
i=window; // Reset countdown variable
}
}
while(Left_1) // While stick is left (R-L-?)
{
Right_1 = 0;
for(int i = 0; i<=window; i++) // Wait for stick to move right again
{
PORTB |= (1<<PB2); // Wait loop
_delay_loop_2(10000);
PORTB &= ~(1<<PB2);
_delay_loop_2(10000);
if(sPulse >= pRight) // If stick moved right again then toggle output (R-L-R)
{
PORTB ^= (1<<PB3); // Toggle Output A, pin 2
if(ServoTarget != 200) // Toggle servo targe position
{
ServoTarget = 200; // Move to one extreme
}
else
{
ServoTarget = 100; // Move to the other
}
i=window; // Reset window time
}
}
Right_1 = 0; // Clear stick position flags
Left_1 = 0;
}
Right_1 = 0;
Left_1 = 0;
}
/*Evaluate Left-Right-Left condition*/
while(Left_1) // While stick is Left
{
Left_1 = 0;
for(int i = 0; i<=window; i++) // Wait for stick to move right (L-?-?)
{
PORTB |= (1<<PB2); // Wait loop
_delay_loop_2(10000);
PORTB &= ~(1<<PB2);
_delay_loop_2(10000);
if(sPulse >= pRight) // If stick moved right before end of wait period
{
Right_1 = 1;
i=window; // Reset countdown
}
}
while(Right_1) // While stick is right (L-R-?)
{
Left_1 = 0;
for(int i = 0; i<=window; i++) // Wait for stick to move left again
{
PORTB |= (1<<PB2);
_delay_loop_2(10000);
PORTB &= ~(1<<PB2);
_delay_loop_2(10000);
if(sPulse <= pLeft) // If stick moved left again then toggle output (L-R-L)
{
PORTB ^= (1<<PB4); // Toggle Output B, pin 3
i=window;
}
}
Right_1 = 0; // Clear stick position flags
Left_1 = 0;
}
Right_1 = 0;
Left_1 = 0;
}
}
}
ISR(TIM0_COMPA_vect) // 100KHz timer interrupt
{
restore_SREG = SREG; // Save register status
cli(); // Disable interrupts
/* Servo Out pulse generation */
if(Tick <= ServoCurrent) // While the Tick count is less than the maximum pulse length
{
PORTB |= (1<<PB0); // Keep pin 5 high
}
else
{
PORTB &= ~(1<<PB0); // Keep pin 5 low for the reminder of the servo frame
}
if(Tick >= 2000) // One servo frame (20ms) completed
{
Tick = 0; // Reset counter
}
Tick += 1; // Increment counter
sPulseIn += 1; // Increment the incoming servo pulse value
SREG = restore_SREG; // Restore status register
sei(); // Enable interrupts
}
/* Servo In pulse measurement and servo Out position setting */
ISR(INT0_vect) // Servo input interrupt
{
restore_SREG = SREG; // Save register status
cli(); // Disable interrupts
if(MCUCR & (1<<ISC00)) // If incoming servo pulse begins (rising edge)
{
sPulseIn = 0; // Start pulse count
/* Servo Out rotation speed*/
ServoSubStep += 1; // Increment servo position substep
if(ServoSubStep >= 3) // ServoSubStep >= *less faster, more slower*
{
ServoStep = 1;
ServoSubStep = 0;
}
/*Set interrupt sense to falling edge*/
MCUCR |= (1<<ISC01);
MCUCR &= ~(1<<ISC00);
}
else // If incoming servo pulse ends (falling edge)
{
if(ServoStep) // If it's time to step Servo Out in one direction
{
if(ServoCurrent < ServoTarget)
{
ServoCurrent += 1; // Step Servo Out right
}
if(ServoCurrent > ServoTarget)
{
ServoCurrent -= 1; // Step Servo Out left
}
ServoStep = 0; // Reset and wait for next servo step command
}
sPulse = sPulseIn; // Measure Servo In pulse length
/*Set interrupt sense to rising edge*/
MCUCR |= (1<<ISC00) | (1<<ISC01);
}
SREG = restore_SREG;
sei();
}
