===== Input capture based version =====
This uses the input capture function on timer1 (atmega168). The ICNC1 bit in the TCCR1B register need to be set to enable oversampling to give more noise tolerance. A second function running approx every 20ms is needed to decrement counter by two and check if counter>=30. If this is the case there is a valid pwm stream and the diff variable can be used to set the pwm output.
==== Header ====
void enable_ground_control(); //enables the input capture interrupt
void disable_ground_control(); //disables input capture interrupt
#define PULSE_MIN (s16)(0.001*(float)F_CPU/16.0) //pwm must be in the range 1 to 2 ms
#define PULSE_MAX (s16)(0.002*(float)F_CPU/16.0) //due to the bit shift we divide by 16
#define GROUND_LED_ON PORTD|=(1<<3)
#define GROUND_LED_OFF PORTD&=~(1<<3)
#define GROUND_LED_SET PORTD&(1<<3)
void run_ground_control();
====Main code===
#ifdef GROUND
#include "main.h"
extern volatile u08 counter; //globals
extern volatile u16 diff;
ISR(TIMER1_CAPT_vect)
{
static u16 start;
if(TCCR1B&0x40) //start of a pulse
{
TCCR1B&=~0x40; //set to trigger on falling edge
start=ICR1; //record start of the pulse
}
else
{
TCCR1B|=0x40; //set to trigger on rising edge
if(!(counter&0x80)) //the lock bit isn't set, so we are free to run
{
diff=ICR1; //set the global volatile s16 diff
if(start>diff) //our pwm pulse spans a timer overflow
{
diff+=TOP_COUNT;
}
diff-=start;
if(diff>PULSE_MIN && diff=28)
{
counter|=0x80; //lock the diff variable using the counter flag bit
OCR1B=diff;
counter&=~0x80;
GROUND_LED_ON;
}
else
{
GROUND_LED_OFF;
}
if(counter&~0x80) //if the counter variable >0, decrement by 2
counter-=2;
}
void enable_ground_control()
{
TIMSK1|=(1<
===== Pin change based version =====
This AVR code constantly checks the PWM input for pulse lenght. If a stream of 10 pulses are detected that match the criterion, the input PWM is routed to the output. A single failing PWM pulse will cause control to revert back to internal guidance. Useful for UAVs, allowing control to be regained from the ground in the event of a faulty control algorthym.
===== ground.h =====
#define pwm_record_factor ((float)F_CPU*0.0005/256.0) //500us
#define lower_pwm_bound (u08)(pwm_record_factor*4.25) //valid pwm limits
#define upper_pwm_bound (u08)(pwm_record_factor*1.75)
#define GROUND
#define check_input PORTC & 0x01
#define copy_pwm PORTB=(PORTB & ~0x03)|(PORTC & 0x03); //move PORTC 0,1 to PORTB 0,1
void enable_ground_control();
void disable_ground_control();
===== ground.c =====
#include "main.h"
#include "ground.h"
volatile u08 pwm_counter=0x00;
volatile u08 pwm_period=0x00;
ISR(PCINT1_vect)
{
if(pwm_counter==0x0A) //a stream of valid pwm
{
cbi(TCCR1A,COM1A1); //turn off PWM output to servo
copy_pwm;
}
static u08 pulse;
if(check_input) //start of pulse
{
TCNT0=0x00; //reset timer at start of C.0 pulse
pulse=TRUE;
}
else if(pulse) //end of C.0 pulse
{
pulse=FALSE;
if(TCNT0>upper_pwm_bound && TCNT0