Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ///////////////////////////////////////
- //
- // A17 = Input PPM, PWM Out on D2-D7
- //
- ///////////////////////////////////////
- #include <avr/io.h>
- #include <avr/interrupt.h>
- #include <util/delay.h>
- #define width_500 ((F_CPU * 5) / 10000) // calculates ticks for 0.5ms
- #define width_01 width_500 / 5 // calculates ticks for 0.1ms
- // pin and port renaming
- #define LED_PIN 13
- #define in_port PORTK
- #define in_pinin PINK
- #define in_ddr DDRK
- #define in_pin 6
- // global variables
- bool PWM_ENABLE = false;
- byte pwm_values[8];
- static volatile unsigned long ovf_cnt; // overflow counter
- static volatile unsigned char chan_cnt; // channel counter
- static volatile unsigned char mask_cnt; // used to determin next pin
- static volatile unsigned int chan_width[8]; // stores pulse width in clock ticks
- static volatile unsigned int chan_width_temp[8];
- static volatile unsigned int last_capt; // time of last capture, used to find difference
- static volatile unsigned char data_ready; // 1 if data is good, 0 if transmitter is off
- static volatile unsigned char next_mask; // next port mask to apply
- // input capture interrupt vector
- ISR(TIMER1_CAPT_vect)
- {
- mask_cnt++; // next pin
- unsigned long t_ovf = ovf_cnt; // store overflow counter in case another overflow occurs during interrupt
- ovf_cnt = 0;
- unsigned long t_icr = ICR1; // convert to unsigned long
- // calculate total time using overflows and time difference
- unsigned long t = ((t_icr | 0x10000) - last_capt) & 0xFFFF;
- if(t_icr < last_capt)
- {
- t_ovf--;
- }
- t += 0x10000 * t_ovf;
- last_capt = ICR1;
- // if pulse is longer than 3ms, then it's a sync pulse
- if(t > width_500 * 6)
- {
- chan_cnt = 0;
- if(data_ready == 0)
- {
- data_ready = 1;
- }
- }
- else // if pulse is shorter than 3ms, then it's a servo pulse
- {
- chan_width[chan_cnt] = t; // store time
- chan_width_temp[0] = chan_width[0]; chan_width_temp[1] = chan_width[1]; chan_width_temp[2] = chan_width[2]; chan_width_temp[3] = chan_width[3];
- chan_width_temp[4] = chan_width[4]; chan_width_temp[5] = chan_width[5]; chan_width_temp[6] = chan_width[6]; chan_width_temp[7] = chan_width[7];
- chan_cnt++; // next channel
- if(chan_cnt >= 4 && data_ready != 0) // last channel, data is now good, reset to first pin
- {
- data_ready = 2;
- mask_cnt = 0;
- }
- }
- }
- // timer overflow interrupt vector
- ISR(TIMER1_OVF_vect)
- {
- ovf_cnt++;
- if(ovf_cnt >= 7) // if too many, then transmitter is missing
- {
- data_ready = 0;
- }
- }
- void setup(){
- // initialize variables
- ovf_cnt = 0;
- chan_cnt = 0;
- mask_cnt = 0;
- data_ready = 0;
- MCUCR |= _BV(PUD); // no pull-ups
- // initialize ports
- in_ddr |= _BV(5) | _BV(4);
- in_ddr &= 0xFF ^ _BV(in_pin);
- // initialize timer
- TCCR1B = 1 | _BV(ICES1); // start timer, input capture on rising edge
- TIMSK1 = _BV(TOIE1) | _BV(ICIE1); // enable interrupts
- sei(); // enable global interrupts
- }
- void loop(){
- _delay_ms(10);
- if(data_ready == 2){
- // enable output if data is good, light LED
- digitalWrite(LED_PIN, HIGH);
- PWM_ENABLE = true;
- }
- else{
- // disable output if transmitter is missing, LED off
- digitalWrite(LED_PIN, LOW);
- PWM_ENABLE = false;
- }
- if (PWM_ENABLE){
- for (byte i = 0; i <= 7; i++){
- // min servo = 10 * width 0.1, max = 20 * width 0.1
- analogWrite((2 + i), ((( chan_width_temp[i] * width_01) / (( 20 * width_01) - (10 * width_01)) ) * 255));
- }
- }
- if (!PWM_ENABLE){
- for (byte i = 0; i <= 7; i++){
- analogWrite((2+i), 0);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment