This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
code:ground_control [2008/04/19 17:15] laurenceb |
code:ground_control [2008/11/13 09:50] (current) laurenceb |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | 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 in 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. | + | ===== 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 ==== | ||
+ | <code c> | ||
+ | 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(); | ||
+ | </code> | ||
+ | |||
+ | |||
+ | ====Main code=== | ||
+ | |||
+ | <code c> | ||
+ | #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<PULSE_MAX) //test against criterion | ||
+ | { | ||
+ | if((counter&(~0x80))<30) //30 consecutive pulses | ||
+ | { | ||
+ | counter+=3; //the 20ms timer1 overflow subtracts 2 from counter | ||
+ | } | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | counter&=0x80; //set the last 7 bits to zero | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void run_ground_control() | ||
+ | { | ||
+ | if((~0x80&counter)>=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<<ICIE1); | ||
+ | counter=0; | ||
+ | } | ||
+ | |||
+ | void disable_ground_control() | ||
+ | { | ||
+ | TIMSK1&=~(1<<ICIE1); | ||
+ | GROUND_LED_OFF; | ||
+ | counter=0; | ||
+ | diff=0; | ||
+ | } | ||
+ | #endif | ||
+ | </code> | ||
+ | |||
+ | |||
+ | |||
+ | ===== 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 ===== | ===== ground.h ===== | ||
- | <code c>#define pwm_record_factor (u08)F_CPU/500.0/256.0 | + | <code c>#define pwm_record_factor ((float)F_CPU*0.0005/256.0) //500us |
- | #define lower_pwm_bound pwm_record_factor*4.25 //valid pwm limits | + | #define lower_pwm_bound (u08)(pwm_record_factor*4.25) //valid pwm limits |
- | #define upper_pwm_bound pwm_record_factor*1.75 | + | #define upper_pwm_bound (u08)(pwm_record_factor*1.75) |
#define GROUND | #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 enable_ground_control(); | ||
Line 14: | Line 112: | ||
===== ground.c ===== | ===== ground.c ===== | ||
- | <code c> | + | <code c>#include "main.h" |
- | #include "main.h" | + | |
#include "ground.h" | #include "ground.h" | ||
+ | |||
volatile u08 pwm_counter=0x00; | volatile u08 pwm_counter=0x00; | ||
volatile u08 pwm_period=0x00; | volatile u08 pwm_period=0x00; | ||
+ | |||
ISR(PCINT1_vect) | ISR(PCINT1_vect) | ||
{ | { | ||
- | if(PORTC & 0x01) //start of C.0 pulse | + | 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 | TCNT0=0x00; //reset timer at start of C.0 pulse | ||
+ | pulse=TRUE; | ||
} | } | ||
- | else //end of C.0 pulse | + | else if(pulse) //end of C.0 pulse |
{ | { | ||
+ | pulse=FALSE; | ||
if(TCNT0>upper_pwm_bound && TCNT0<lower_pwm_bound) //valid pwm | if(TCNT0>upper_pwm_bound && TCNT0<lower_pwm_bound) //valid pwm | ||
{ | { | ||
Line 45: | Line 150: | ||
pwm_counter=0x00; | pwm_counter=0x00; | ||
} | } | ||
- | } | ||
- | if(pwm_counter==0x0A) //a stream of valid pwm | ||
- | { | ||
- | cbi(TCCR1A,COM1A1); //turn off PWM output to servo | ||
- | PORTB=(PORTB & ~0x03)|(PORTC & 0x03); //move PORTC 0,1 to PORTB 0,1 | ||
} | } | ||
} | } | ||
+ | |||
ISR(TIMER0_OVF_vect) | ISR(TIMER0_OVF_vect) | ||
{ | { | ||
Line 58: | Line 158: | ||
pwm_counter=0x00; //with valid pwm, there will be no overflows | pwm_counter=0x00; //with valid pwm, there will be no overflows | ||
} | } | ||
+ | |||
void enable_ground_control() | void enable_ground_control() | ||
{ | { | ||
Line 64: | Line 164: | ||
sbi(PCICR, PCIE1); //Pin change interrupts on | sbi(PCICR, PCIE1); //Pin change interrupts on | ||
} | } | ||
+ | |||
void disable_ground_control() | void disable_ground_control() | ||
{ | { |