This code (for ATTiny microcontrollers) shows how to reverse a PPM servo signal. Feel free to use it in your own servo reverse controller.
// Reverses servo signal
// Tiny13 pinout:
// PB5 – /RESET / PCINT5
// PB3 – ADC3 – used to configure center point / PCINT3
// PB4 – Servo Output / PCINT4
// PB2 – SCK / PCINT2
// PB1 – MISO / PCINT1
// PB0 – Servo Input / MOSI / PCINT0
// AT Tiny13 Specs: http://www.atmel.com/Images/doc2535.pdf
// flashing with avrdude:
// avrdude -F -c stk500v2 -p t13 -P com10 -U flash:w:servo.hex
#include <avr/io.h>
// #include <avr/delay.h>
#include <avr/interrupt.h>
// CPU speed (Hz)
#define F_CPU 4800000L
volatile static uint8_t in_time = 0;
volatile static uint8_t out_time = 0;
// read ADC channel
// http://www.rn-wissen.de/index.php/ADC_(Avr)
uint16_t adc(void)
{
ADCSRA |= (1<<ADSC); // start conversion
while (ADCSRA & (1<<ADSC)); // wait to finish conversion
uint16_t val = ADCW;
return val;
}
volatile static uint8_t in_start = 0;
volatile static uint8_t timer = 0;
// input ppm pin signal change interrupt
ISR(PCINT0_vect)
{
timer = TCNT0;
if (PINB & (1<<PB0)) {// low->high
in_start = timer;
} else {
// high->low
in_time = timer – in_start;
}
}
volatile static uint8_t sethigh = 1;
// timer comparator interrupt
ISR(TIM0_COMPA_vect)
{
if (sethigh == 1){
PORTB |= (1<<PB4); // set output port high
OCR0A += out_time;
} else {
PORTB &= ~(1<<PB4); // set output port low
OCR0A=TCNT0-1; // wait max. possible time for next pulse
}
sethigh = !sethigh;
}
int main (void)
{
// configure ADC
ADMUX &= ~(1<<REFS0); // voltage reference (VCC)
ADMUX |= (1<<MUX1) | (1<<MUX0); // choose ADC3 mux
ADCSRA = ( 1 << ADPS2 ); // ADC speed (clk/16)
ADCSRA |= (1<<ADEN); // enable ADC
// configure timer0 (8bit)
// used to control servo pulse length
TCCR0A = 0; // normal operation
TCCR0B = (1 << CS01) | (1 << CS00); // timer speed clk/64 (75 kHz)
TIMSK0 |= (1 << OCIE0A); // enable timer comparator interrupt
//TIMSK0 |= (1 << TOIE0); // enable timer overflow interruptTCNT0 = 0;
OCR0A = 255;// configure I/O pins
DDRB |= (1<<PB4); // PB4 as output
DDRB &= ~(1<<PB0); // PB0 as input// configure PCINT0 change interrupt
PCMSK |= (1 << PCINT0);
GIMSK |= (1 << PCIE);sei(); // enable interrupts*/
// no-reverse ppm test
/*while (1){
PORTB = (PORTB & (~(1<<PB4))) | ((PINB & (1<<PB0)) << PB4);
} */// idea used:
http://homepages.which.net/~paul.hills/Circuits/ServoReverser/ServoReverser.html
while (1){
int16_t adcofs = ((int16_t) adc() – 512) >> 4;
// 225 tt entspricht 3ms
// weight time values:
// new value = x* last value + y* new value,
// x+y=1out_time = (((uint16_t)out_time) *2 + ((uint16_t)225-in_time +adcofs) * 1) / 3;
//delay_ms(50);
}
}
Download code: servoreverse.zip