unsigned int serinp[8]; //servo positionsvoid setup_timer1(){//disable all interuptsTIMSK1 &= ~( _BV(TOIE1) | _BV(ICIE1) | _BV(OCIE1A) | _BV(OCIE1B));//set timer modeTCCR1A &= ~( _BV(WGM11) | _BV(WGM10) );TCCR1B &= ~( _BV(WGM12) | _BV(WGM13) | _BV(ICNC1));//capture raising edgeTCCR1B |= _BV(ICES1); //capture raising edge//prescaler 1/8TCCR1B |= _BV(CS11);TCCR1B &= ~( _BV(CS12) | _BV(CS10) );//disable outputsTCCR1A &= ~( _BV(COM1A0) | _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1));//enable capture interuptTIMSK1 |= (1<<ICIE1);}ISR(TIMER1_CAPT_vect){static unsigned int lasticr; //icr at last caputrestatic unsigned char cserinp; //current input servounsigned int licr;//TCCR1B ^= _BV(ICES1);licr=ICR1-lasticr;lasticr=ICR1;if(licr>5000){ //pulse too long, means start of new framecserinp=0;}else if(licr>1000){ //pulse good, take reading, go to next channelserinp[cserinp]=licr;if(cserinp<8){cserinp++;}}else{//too short, nothing to see here}}void setup()pinMode( 8, INPUT ); //sumsetup_timer1();}void loop(){//use serinp!!!}
it'll take a sum signal on pin 8. you can also connect the signal for a single servo, then just serinp[0] will be populated. the values in serinp are 2 times the microseconds, so between 2000-4000 (instead of 1000-2000), yes, there's extra accuracy in there!the timer-capture only works on digital pin 8!if you don't have access to the sum signal, a possible way to read multiple servos would be to connect them all to pin 8. since the receivers usually output the pulses one after the other, this should work (you'll have to adjust the code in the capture-interupt).
You need to be a member of diydrones to add comments!
Comments
Thanks for the ICR PPM capture code. I am attempting to use it but have hit a snag. I am also using the analogWrite() procedure to drive ESC's @ 488Hz and apparently timer1 which your code uses is also responsible for pins 9,10 which I need for the PWM drivers. Is there anyway that you can think of to modify your code so as to still allow pins 9 and 10 to be used to driver hardware PWM or should I just ditch the idea?
Thanks!
here's some understandable descrition of interupts:
http://www.uchobby.com/index.php/2007/11/24/arduino-interrupts/
the code first setups the timer1. this is the only 16bit timer on the atmega168/arduino. this means it counts from 0 to 65536 and then again from zero. the number is increased every 1/8 clock (arduino is 16mhz, so the number is increased every 8/16000000 = 1/2000000 second!!). the input capture is also setup, it "records" the time (the time (16bit counter) from timer1) when the signal goes high on the input capture pin (thats digital 8 on the arduino) to the internal register ICR1. this is completely done in hardware, no matter what else is going on!!! even if your software is crashed this will probably continue to work (including the following part). when signal goes high, an interupt (basicly a function) is called too, which reads ICR1 and subtracts the old ICR1 the get the pulse-length and decodes the ppm.
What do the numbers in serinp correspond to? Milliseconds? Clock cycles? Something else?
When I get back to my Arduino and RX, I'll test this out for myself and hopefully get some more understanding of this code. Sorry for such dumb questions-- if there's some resource I can use to learn this on my own, I'd be happy to do that. I understand you don't have all the time in the world. :]
Thanks for any and all help.