DIY PIXHAWK APM等飞控用的PPM转接板
需要的硬件
一块arduino pro mini(推荐这个,比较小,当然如果你没有USB转转口的烧写工具买个ardunio nano板也是不错的,直接用USB线连接电脑就可以,用nano板要注意。它的usb口是大一点的mini usb口,而不是我们手机那种micro usb)
一个USB的串口刷写模块,用于更新arduino pro mini,用nano板的请无视
直接上图和代码
在arduino的ide里面代码:
先建立一个名为 buzz_8pwm_to_ppm328的目录,然后在目录下建立两个文本文件 :
buzz_8pwm_to_ppm328.ino
PPM_Encoder.h
用arduino的IDE打开buzz_8pwm_to_ppm328.ino 烧写进板子就可以了
两个文件的内容如下
buzz_8pwm_to_ppm328.ino
#include "Arduino.h" #include "ppm_encoder.h" #include <util/delay.h> #include <avr/io.h> #define ERROR_THRESHOLD 2 // Number of servo input errors before alerting #define ERROR_DETECTION_WINDOW 3000 * LOOP_TIMER_10MS // Detection window for error detection (default to 30s) #define ERROR_CONDITION_DELAY 500 * LOOP_TIMER_10MS // Servo error condition LED delay (LED blinking duration) #define PASSTHROUGH_MODE_ENABLED // Comment this line to remove CH8 radio passthrough mode support (hardware failsafe for Arduplane) #define PASSTHROUGH_CHANNEL 8 * 2 // Channel for passthrough mode selection #define PASSTHROUGH_CHANNEL_OFF_US ONE_US * 1600 - PPM_PRE_PULSE // Passthrough off threshold #define PASSTHROUGH_CHANNEL_ON_US ONE_US * 1800 - PPM_PRE_PULSE // Passthrough on threshold #define THROTTLE_CHANNEL 3 * 2 // Throttle Channel #define THROTTLE_CHANNEL_LED_TOGGLE_US ONE_US * 1200 - PPM_PRE_PULSE // Throttle Channel Led toggle threshold #define LED_LOW_BLINKING_RATE 125 * LOOP_TIMER_10MS // Led blink rate for low throttle position (half period) // Timers #define TIMER0_10MS 156 // Timer0 ticks for 10 ms duration #define TIMER1_10MS 20000 // Timer1 ticks for 10 ms duration #define TIMER2_100MS 1562 // Timer2 ticks for 100 ms duration #define LOOP_TIMER_10MS 10 // Loop timer ticks for 10 ms duration // LED Code #define SPACE_SHORT_DURATION 40 * LOOP_TIMER_10MS // Space after short symbol #define SPACE_LONG_DURATION 75 * LOOP_TIMER_10MS // Space after long symbol #define SYMBOL_SHORT_DURATION 20 * LOOP_TIMER_10MS // Short symbol duration #define SYMBOL_LONG_DURATION 100 * LOOP_TIMER_10MS // Long symbol duration #define INTER_CODE_DURATION 150 * LOOP_TIMER_10MS // Inter code duration #define INTER_CODE 0 // Symbols value for coding #define SHORT_SYMBOL 1 #define LONG_SYMBOL 2 #define SHORT_SPACE 3 #define LONG_SPACE 4 #define LOOP 5 // ------------------------------------------------------------------------------------------------------------------------------------------------------------ // PPM ENCODER INIT AND AUXILIARY TASKS // ------------------------------------------------------------------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------------------------------------------------------------------ // LOCAL VARIABLES // ------------------------------------------------------------------------------------------------------------------------------------------------------------ bool localinit = true; // We are inside init sequence bool mux_passthrough = false; // Mux passthrough mode status Flag : passthrough is off uint16_t led_acceleration; // Led acceleration based on throttle stick position bool servo_error_condition = false; // Servo signal error condition static uint16_t servo_error_detection_timer=0; // Servo error detection timer static uint16_t servo_error_condition_timer=0; // Servo error condition timer static uint16_t blink_led_timer = 0; // Blink led timer #ifdef PASSTHROUGH_MODE_ENABLED static uint8_t mux_timer = 0; // Mux timer static uint8_t mux_counter = 0; // Mux counter static int8_t mux_check = 0; static uint16_t mux_ppm = 500; #endif static uint16_t led_code_timer = 0; // Blink Code Timer static uint8_t led_code_symbol = 0; // Blink Code current symbol // ------------------------------------------------------------------------------------------------------------------------------------------------------------ // LOCAL FUNCTIONS // ------------------------------------------------------------------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------ // Led blinking (non blocking) function // ------------------------------------------------------------------------------ uint8_t blink_led ( uint16_t half_period ) // ( half_period max = 65 s ) { blink_led_timer++; if ( blink_led_timer < half_period ) // If half period has not been reached { return 0; // Exit timer function and return 0 } else // half period reached - LED Toggle { PPM_PORT ^= ( 1 << PB0 ); // Toggle status LED blink_led_timer = 0; // Blink led timer reset return 1; // half period reached - Exit timer function and return 1 } } // ------------------------------------------------------------------------------ // Led code (non blocking) function // ------------------------------------------------------------------------------ void blink_code_led ( uint8_t code ) { const uint8_t coding[2][14] = { // PPM_PASSTROUGH_MODE { INTER_CODE, LONG_SYMBOL, LONG_SPACE, SHORT_SYMBOL, SHORT_SPACE, SHORT_SYMBOL, LOOP }, // JETI_MODE { INTER_CODE, LONG_SYMBOL, LONG_SPACE, SHORT_SYMBOL, SHORT_SPACE, SHORT_SYMBOL, SHORT_SPACE, SHORT_SYMBOL,LOOP } }; led_code_timer++; switch ( coding [ code - 2 ] [ led_code_symbol ] ) { case INTER_CODE: if ( led_code_timer < ( INTER_CODE_DURATION ) ) return; else PPM_PORT |= ( 1 << PB0 ); // Enable status LED break; case LONG_SYMBOL: // Long symbol if ( led_code_timer < ( SYMBOL_LONG_DURATION ) ) return; else PPM_PORT &= ~( 1 << PB0 ); // Disable status LED break; case SHORT_SYMBOL: // Short symbol if ( led_code_timer < ( SYMBOL_SHORT_DURATION ) ) return; else PPM_PORT &= ~( 1 << PB0 ); // Disable status LED break; case SHORT_SPACE: // Short space if ( led_code_timer < ( SPACE_SHORT_DURATION ) ) return; else PPM_PORT |= ( 1 << PB0 ); // Enable status LED break; case LONG_SPACE: // Long space if ( led_code_timer < ( SPACE_LONG_DURATION ) ) return; else PPM_PORT |= ( 1 << PB0 ); // Enable status LED break; case LOOP: // Loop to code start led_code_symbol = 0; return; break; } led_code_timer = 0; // Code led timer reset led_code_symbol++; // Next symbol return; // LED code function return } // ------------------------------------------------------------------------------ // ppm reading helper - interrupt safe and non blocking function // ------------------------------------------------------------------------------ uint16_t ppm_read( uint8_t channel ) { uint16_t ppm_tmp = ppm[ channel ]; while( ppm_tmp != ppm[ channel ] ) ppm_tmp = ppm[ channel ]; return ppm_tmp; } // ------------------------------------------------------------------------------------------------------------------------------------------------------------ // INITIALISATION CODE // ------------------------------------------------------------------------------------------------------------------------------------------------------------ void setup() { // ------------------------------------------------------------------------------ // Reset Source checkings // ------------------------------------------------------------------------------ if (MCUSR & 1) // Power-on Reset { MCUSR=0; // Clear MCU Status register // custom code here } else if (MCUSR & 2) // External Reset { MCUSR=0; // Clear MCU Status register // custom code here } else if (MCUSR & 4) // Brown-Out Reset { MCUSR=0; // Clear MCU Status register brownout_reset=true; } else // Watchdog Reset { MCUSR=0; // Clear MCU Status register // custom code here } // ------------------------------------------------------------------------------ // Servo input and PPM generator init // ------------------------------------------------------------------------------ ppm_encoder_init(); // ------------------------------------------------------------------------------ // Outputs init // ------------------------------------------------------------------------------ PPM_DDR |= ( 1 << PB0 ); // Set LED pin (PB0) to output PPM_DDR |= ( 1 << PB1 ); // Set MUX pin (PB1) to output PPM_DDR |= ( 1 << PPM_OUTPUT_PIN ); // Set PPM pin (PPM_OUTPUT_PIN, OC1B) to output // ------------------------------------------------------------------------------ // Timer0 init (normal mode) used for LED control and custom code // ------------------------------------------------------------------------------ TCCR0A = 0x00; // Clock source: System Clock TCCR0B = 0x05; // Set 1024x prescaler - Clock value: 15.625 kHz - 16 ms max time TCNT0 = 0x00; OCR0A = 0x00; // OC0x outputs: Disconnected OCR0B = 0x00; TIMSK0 = 0x00; // Timer 1 interrupt disable // ------------------------------------------------------------------------------ // Enable global interrupt // ------------------------------------------------------------------------------ sei(); // Enable Global interrupt flag // ------------------------------------------------------------------------------ // Disable radio passthrough (mux chip A/B control) // ------------------------------------------------------------------------------ PPM_PORT |= ( 1 << PB1 ); // Set PIN B1 to disable Radio passthrough (mux) } void loop() { // ------------------------------------------------------------------------------------------------------------------------------------------------------------ // AUXILIARY TASKS // ------------------------------------------------------------------------------------------------------------------------------------------------------------ PWM_LOOP: // SERVO_PWM_MODE while( 1 ) { _delay_us (950); // Slow down while loop } // PWM Loop end } // main lopo function end
PPM_Encoder.h
// ------------------------------------------------------------- #ifndef _PPM_ENCODER_H_ #define _PPM_ENCODER_H_ #include <avr/io.h> // ------------------------------------------------------------- #include <avr/interrupt.h> #include <avr/wdt.h> #include <util/delay.h> // ------------------------------------------------------------- // SERVO INPUT FILTERS // ------------------------------------------------------------- // Using both filters is not recommended and may reduce servo input resolution // #define _AVERAGE_FILTER_ // Average filter to smooth servo input capture jitter // #define _JITTER_FILTER_ // Cut filter to remove 0,5us servo input capture jitter // ------------------------------------------------------------- #ifndef F_CPU #define F_CPU 16000000UL #endif #ifndef true #define true 1 #endif #ifndef false #define false 0 #endif //#ifndef bool //#define bool boolean //#endif // 328 does not define PBX but defines an equivalent as PORTBX, comment these lines out if you already have a PB2 defined. #define PB2 PORTB2 #define PB1 PORTB1 #define PB0 PORTB0 // ------------------------------------------------------------- // SERVO INPUT MODE - !EXPERIMENTAL! // ------------------------------------------------------------- #define SERVO_PWM_MODE 1 // Normal 8 channel servo (pwm) input // Servo input mode (jumper (default), pwm, ppm, jeti or spektrum) volatile uint8_t servo_input_mode = SERVO_PWM_MODE; // ------------------------------------------------------------- // Number of Timer1 ticks in one microsecond #define ONE_US F_CPU / 8 / 1000 / 1000 // 400us PPM pre pulse #define PPM_PRE_PULSE ONE_US * 400 // ------------------------------------------------------------- // SERVO LIMIT VALUES // ------------------------------------------------------------- // Servo minimum position #define PPM_SERVO_MIN ONE_US * 900 - PPM_PRE_PULSE // Servo center position #define PPM_SERVO_CENTER ONE_US * 1500 - PPM_PRE_PULSE // Servo maximum position #define PPM_SERVO_MAX ONE_US * 2100 - PPM_PRE_PULSE // Throttle default at power on #define PPM_THROTTLE_DEFAULT ONE_US * 1100 - PPM_PRE_PULSE // Throttle during failsafe #define PPM_THROTTLE_FAILSAFE ONE_US * 900 - PPM_PRE_PULSE // CH5 power on values (mode selection channel) //#define PPM_CH5_MODE_4 ONE_US * 1555 - PPM_PRE_PULSE // ------------------------------------------------------------- // Number of servo input channels #define SERVO_CHANNELS 8 // PPM period 18.5ms - 26.5ms (54hz - 37Hz) #define PPM_PERIOD ONE_US * ( 22500 - ( 8 * 1500 ) ) // Size of ppm[..] data array ( servo channels * 2 + 2) #define PPM_ARRAY_MAX 18 // Data array for storing ppm (8 channels) pulse widths. volatile uint16_t ppm[ PPM_ARRAY_MAX ] = { PPM_PRE_PULSE, PPM_SERVO_CENTER, // Channel 1 PPM_PRE_PULSE, PPM_SERVO_CENTER, // Channel 2 PPM_PRE_PULSE, PPM_THROTTLE_DEFAULT, // Channel 3 (throttle) PPM_PRE_PULSE, PPM_SERVO_CENTER, // Channel 4 PPM_PRE_PULSE, PPM_SERVO_CENTER, // Channel 5 PPM_PRE_PULSE, PPM_SERVO_CENTER, // Channel 6 PPM_PRE_PULSE, PPM_SERVO_CENTER, // Channel 7 PPM_PRE_PULSE, PPM_SERVO_CENTER, // Channel 8 PPM_PRE_PULSE, PPM_PERIOD }; // ------------------------------------------------------------- // SERVO FAILSAFE VALUES // ------------------------------------------------------------- const uint16_t failsafe_ppm[ PPM_ARRAY_MAX ] = { PPM_PRE_PULSE, PPM_SERVO_CENTER, // Channel 1 PPM_PRE_PULSE, PPM_SERVO_CENTER, // Channel 2 PPM_PRE_PULSE, PPM_THROTTLE_FAILSAFE, // Channel 3 (throttle) PPM_PRE_PULSE, PPM_SERVO_CENTER, // Channel 4 PPM_PRE_PULSE, PPM_SERVO_MAX, // Channel 5 PPM_PRE_PULSE, PPM_SERVO_MAX, // Channel 6 PPM_PRE_PULSE, PPM_SERVO_CENTER, // Channel 7 PPM_PRE_PULSE, PPM_SERVO_CENTER, // Channel 8 PPM_PRE_PULSE, PPM_PERIOD }; // ------------------------------------------------------------- // AVR parameters for ArduPilot MEGA v1.4 PPM Encoder (ATmega328P) #if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega328__) #define SERVO_DDR DDRD #define SERVO_PORT PORTD #define SERVO_INPUT PIND // PCIE2 PC Interrupt enable 2 is for Arduino Pins (D0-D7), also called PORTD. #define SERVO_INT_VECTOR PCINT2_vect #define SERVO_INT_MASK PCMSK2 #define SERVO_INT_CLEAR_FLAG PCIF2 #define SERVO_INT_ENABLE PCIE2 #define SERVO_TIMER_CNT TCNT1 #define PPM_DDR DDRB #define PPM_PORT PORTB #define PPM_OUTPUT_PIN PB2 #define PPM_INT_VECTOR TIMER1_COMPB_vect #define PPM_COMPARE OCR1B #define PPM_COMPARE_FLAG COM1B0 #define PPM_COMPARE_ENABLE OCIE1B #else #error NO SUPPORTED DEVICE FOUND! ( ATmega328/p) #endif // Used to indicate invalid SERVO input signals //volatile uint8_t servo_input_errors = 0; // Used to indicate missing SERVO input signals volatile bool servo_input_missing = true; // Used to indicate if PPM generator is active volatile bool ppm_generator_active = false; // Used to indicate a brownout restart volatile bool brownout_reset = false; // ------------------------------------------------------------------------------ // PPM GENERATOR START - TOGGLE ON COMPARE INTERRUPT ENABLE // ------------------------------------------------------------------------------ // this starts OUTGOING PPM stream on PPM_PORT (PORTB, Arduino D8-D13) at PPM_OUTPUT_PIN (PB2, arduino pin D10) void ppm_start( void ) { // Prevent reenabling an already active PPM generator if( ppm_generator_active ) return; // Store interrupt status and register flags uint8_t SREG_tmp = SREG; // Stop interrupts cli(); // Make sure initial output state is low PPM_PORT &= ~(1 << PPM_OUTPUT_PIN); // Wait for output pin to settle //_delay_us( 1 ); // Set initial compare toggle to maximum (32ms) to give other parts of the system time to start SERVO_TIMER_CNT = 0; PPM_COMPARE = 0xFFFF; // Set toggle on compare output TCCR1A = (1 << PPM_COMPARE_FLAG); // Set TIMER1 8x prescaler TCCR1B = ( 1 << CS11 ); // Enable output compare interrupt TIMSK1 |= (1 << PPM_COMPARE_ENABLE); // Indicate that PPM generator is active ppm_generator_active = true; // Restore interrupt status and register flags SREG = SREG_tmp; } // ------------------------------------------------------------------------------ // PPM GENERATOR STOP - TOGGLE ON COMPARE INTERRUPT DISABLE // ------------------------------------------------------------------------------ void ppm_stop( void ) { // Store interrupt status and register flags uint8_t SREG_tmp = SREG; // Stop interrupts cli(); // Disable output compare interrupt TIMSK1 &= ~(1 << PPM_COMPARE_ENABLE); // Reset TIMER1 registers TCCR1A = 0; TCCR1B = 0; // Indicate that PPM generator is not active ppm_generator_active = false; // Restore interrupt status and register flags SREG = SREG_tmp; } // ------------------------------------------------------------------------------ // Watchdog Interrupt (interrupt only mode, no reset) // ------------------------------------------------------------------------------ ISR( WDT_vect ) // If watchdog is triggered then enable missing signal flag and copy power on or failsafe positions { // Use failsafe values if PPM generator is active or if chip has been reset from a brown-out if ( ppm_generator_active || brownout_reset ) { // Copy failsafe values to ppm[..] for ( uint8_t i = 0; i < PPM_ARRAY_MAX; i++ ) { ppm[ i ] = failsafe_ppm[ i ]; } } // Set missing receiver signal flag servo_input_missing = true; // Reset servo input error flag //servo_input_errors = 0; } // ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------ // SERVO/PPM INPUT - PIN CHANGE INTERRUPT, for any Arduino pin D0 -> D7 // ------------------------------------------------------------------------------ ISR( SERVO_INT_VECTOR ) { // Servo pulse start timing static uint16_t servo_start[ SERVO_CHANNELS ] = { 0, 0, 0, 0, 0, 0, 0, 0 }; // Missing throttle signal failsafe static uint8_t throttle_timeout = 0; // Servo input pin storage static uint8_t servo_pins_old = 0; // Used to store current servo input pins uint8_t servo_pins; // Read current servo pulse change time uint16_t servo_time = SERVO_TIMER_CNT; // ------------------------------------------------------------------------------ // SERVO PWM MODE // ------------------------------------------------------------------------------ CHECK_PINS_START: // Start of servo input check // Store current servo input pins servo_pins = SERVO_INPUT; // Calculate servo input pin change mask uint8_t servo_change = servo_pins ^ servo_pins_old; // Set initial servo pin and channel uint8_t servo_pin = 1; uint8_t servo_channel = 0; CHECK_PINS_LOOP: // Input servo pin check loop // Check for pin change on current servo channel if( servo_change & servo_pin ) { // if (( servo_pin == 1 ) && ( ppm_generator_active = false) ) ppm_start(); // if (( servo_pin == 8 ) && ( ppm_generator_active = true) ) ppm_stop(); // High (raising edge) if( servo_pins & servo_pin ) { servo_start[ servo_channel ] = servo_time; } else { // Get servo pulse width uint16_t servo_width = servo_time - servo_start[ servo_channel ] - PPM_PRE_PULSE; // Calculate servo channel position in ppm[..] uint8_t _ppm_channel = ( servo_channel << 1 ) + 1; // Check that servo pulse signal is valid before sending to ppm encoder if( servo_width > PPM_SERVO_MAX ) goto CHECK_PINS_ERROR; if( servo_width < PPM_SERVO_MIN ) goto CHECK_PINS_ERROR; goto CHECK_PINS_NOERROR; CHECK_PINS_ERROR: // on width input error, use defailt/failsave value, OR previous value // choose the error handling type here! #define FAILHOLD 1 #ifdef FAILCENTRE servo_width = failsafe_ppm[ _ppm_channel ]; // failsafe defaults, most channels centred, throttle lowered. #endif #ifdef FAILHOLD servo_width = ppm[ _ppm_channel ]; // all channels hold their previous position! #endif CHECK_PINS_NOERROR: //Reset throttle failsafe timeout if( _ppm_channel == 5 ) throttle_timeout = 0; #ifdef _AVERAGE_FILTER_ // Average filter to smooth input jitter servo_width += ppm[ _ppm_channel ]; servo_width >>= 1; #endif #ifdef _JITTER_FILTER_ // 0.5us cut filter to remove input jitter int16_t ppm_tmp = ppm[ _ppm_channel ] - servo_width; if( ppm_tmp == 1 ) goto CHECK_PINS_NEXT; if( ppm_tmp == -1 ) goto CHECK_PINS_NEXT; #endif // Update ppm[..] ppm[ _ppm_channel ] = servo_width; } } CHECK_PINS_NEXT: // Select next servo pin servo_pin <<= 1; // Select next servo channel servo_channel++; // Check channel and process if needed if( servo_channel < SERVO_CHANNELS ) goto CHECK_PINS_LOOP; goto CHECK_PINS_DONE; // All servo input pins has now been processed CHECK_PINS_DONE: // Reset Watchdog Timer wdt_reset(); // Set servo input missing flag false to indicate that we have received servo input signals servo_input_missing = false; // Store current servo input pins for next check servo_pins_old = servo_pins; // Start PPM generator if not already running if( ppm_generator_active == false ) ppm_start(); // Throttle failsafe if( throttle_timeout++ >= 128 ) { // Reset throttle timeout throttle_timeout = 0; // Set throttle failsafe value ppm[ 5 ] = PPM_THROTTLE_FAILSAFE; } //Has servo input changed while processing pins, if so we need to re-check pins if( servo_pins != SERVO_INPUT ) goto CHECK_PINS_START; // Clear interrupt event from already processed pin changes PCIFR |= (1 << SERVO_INT_CLEAR_FLAG); } // ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------ // PPM OUTPUT - TIMER1 COMPARE INTERRUPT // ------------------------------------------------------------------------------ ISR( PPM_INT_VECTOR ) { // Current active ppm channel static uint8_t ppm_channel = PPM_ARRAY_MAX - 1; // Update timing for next compare toggle PPM_COMPARE += ppm[ ppm_channel ]; // Select the next ppm channel if( ++ppm_channel >= PPM_ARRAY_MAX ) { ppm_channel = 0; } } // ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------ // PPM READ - INTERRUPT SAFE PPM SERVO CHANNEL READ // ------------------------------------------------------------------------------ /* uint16_t ppm_read_channel( uint8_t channel ) { // Limit channel to valid value uint8_t _channel = channel; if( _channel == 0 ) _channel = 1; if( _channel > SERVO_CHANNELS ) _channel = SERVO_CHANNELS; // Calculate ppm[..] position uint8_t ppm_index = ( _channel << 1 ) + 1; // Read ppm[..] in a non blocking interrupt safe manner uint16_t ppm_tmp = ppm[ ppm_index ]; while( ppm_tmp != ppm[ ppm_index ] ) ppm_tmp = ppm[ ppm_index ]; // Return as normal servo value return ppm_tmp + PPM_PRE_PULSE; } */ // ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------ // PPM ENCODER INIT // ------------------------------------------------------------------------------ void ppm_encoder_init( void ) { // SERVO/PPM INPUT PINS // ------------------------------------------------------------------------------ // Set all servo input pins to inputs SERVO_DDR = 0; // Activate pullups on all input pins SERVO_PORT |= 0xFF; // SERVO/PPM INPUT - PIN CHANGE INTERRUPT // ------------------------------------------------------------------------------ if( servo_input_mode == SERVO_PWM_MODE ) { // Set servo input interrupt pin mask to all 8 servo input channels SERVO_INT_MASK = 0xFF; } // Enable servo input interrupt PCICR |= (1 << SERVO_INT_ENABLE); // PPM OUTPUT PIN // ------------------------------------------------------------------------------ // Set PPM pin to output PPM_DDR |= (1 << PPM_OUTPUT_PIN); // ------------------------------------------------------------------------------ // Enable watchdog interrupt mode // ------------------------------------------------------------------------------ // Disable watchdog wdt_disable(); // Reset watchdog timer wdt_reset(); // Start timed watchdog setup sequence WDTCSR |= (1<<WDCE) | (1<<WDE ); // Set 250 ms watchdog timeout and enable interrupt WDTCSR = (1<<WDIE) | (1<<WDP2); } // ------------------------------------------------------------------------------ #endif // _PPM_ENCODER_H_