Hallo
Ich habe den Code etwas umgestrickt. Der Impuls wird nun über einen 8bit-Timer per Interrupt erzeugt. In der Servo-ISR wird zum richtigen Zeitpunkt (der ist extrem wichtig!) das einmalige Wandeln des ADC angestoßen. Wenn die Wandlung beendet ist, wird in einer ADC-ISR das Ergebniss in adc_servo gespeichert. In der Hauptschleife wird dieser Wert mit LEDs ausgegeben (für den RP6):
Hier noch eine Anwendung für einen 8MHz-Mega32 ohne RP6-Funktionen:Code:// Servo-Lastmessung am Steuerpin 9.2.2008 mic // In der 20ms-Signalpause wird die Spannung am Steuerpin des Servos gemessen // und ausgewertet. #include "rblib.h" #include "rblib.c" uint8_t adc_pos; // Position des Servos uint16_t adc_servo; // Messwert der Signalleitung void servo_ON(void) // Servo-ISR starten { cli(); TCCR0 = (0 << WGM00) | (1 << WGM01); // CTC-Mode TCCR0 |= (0 << COM00) | (0 << COM01); // ohne OCR-Pin TCCR0 |= (0 << CS02) | (0 << CS01) | (1 << CS00); // prescaler /1 TIMSK = (1 << OCIE0); // Interrupt ein OCR0 = 105; // 5V-Referenz, Kanal 0 ADMUX = (0<<REFS1) | (1<<REFS0) | 0; // Interrupt ein, ADC enable, prescal /16, altes Flag löschen ADCSRA = (1<<ADIE) | (1<<ADEN) | (1<<ADPS2) | (1<<ADIF); sei(); } int main(void) { rblib_init(); adc_pos=100; // Position der Servos adc_servo=0; // Startwerte setzen servo_ON(); // Servo-ISR starten while(1) { setLEDs(adc_servo); } return 0; } ISR(ADC_vect) { adc_servo=ADC; // jetzt messen wir die Spannung! } ISR(TIMER0_COMP_vect) { static uint16_t count=0; // Zykluszähler if (count>adc_pos) // Servoimpuls senden? { DDRA &= ~1; // nein: auf Eingang ohne PullUp PORTA &= ~1; if (count == adc_pos+100) // seit 100 Takten auf Eingang gesetzt, { ADCSRA |= (1<<ADSC); // ADC starten } } else { DDRA |= 1; // Impuls senden, Pin auf Ausgang PORTA |= 1; // und high } if(count<2000) count++; else count=0; // Zyklus fertig? }
und das Video dazu:Code:// Servo-Lastmessung am Steuerpin mit einem 8MHz-ATMega32 10.2.2008 mic // In der 20ms-Signalpause wird die Spannung am Steuerpin des Servos gemessen // und ausgewertet. Servoimpuls wird mit einem 8bit-Timer im CTC-Mode per ISR // erzeugt. Kurz nach Ende des Impulses wird der ADC gestartet und der Messwert // in einer ADC-ISR eingelesen. #include <avr/io.h> // I/O Port definitions #include <avr/interrupt.h> // Interrupt macros // Position des Servos, Belastungszähler uint8_t servo_pos; // Messwert der Signalleitung, Verzögerung volatile uint16_t servo_adc, servo_count, pause; void init_servo(void) // Servo-ISR starten { cli(); TCCR0 = (0 << WGM00) | (1 << WGM01); // CTC-Mode TCCR0 |= (0 << COM00) | (0 << COM01); // ohne OCR-Pin TCCR0 |= (0 << CS02) | (0 << CS01) | (1 << CS00); // prescaler /1 TIMSK = (1 << OCIE0); // Interrupt ein OCR0 = 105; // Servomitte=100? // 5V-Referenz, Kanal 0 ADMUX = (0<<REFS1) | (1<<REFS0) | 0; // Interrupt ein, ADC enable, prescaler /16, altes Flag löschen ADCSRA = (1<<ADIE) | (1<<ADEN) | (1<<ADPS2) | (1<<ADIF); sei(); } void wait(uint8_t p) { pause=p; while(pause); } int main(void) { servo_pos=100; // Position des Servos servo_adc=-1; // Startwerte setzen init_servo(); // Servo-ISR starten wait(20); while(1) { weiter2: servo_pos+=2; servo_count=0; while((servo_pos++ < 200)) { wait(1); while(servo_count > 8) { if (servo_count > 15) goto weiter1; } } weiter1: servo_pos-=2; servo_count=0; while((servo_pos-- > 30)) { wait(1); while(servo_count > 8) { if (servo_count > 15) goto weiter2; } } } return 0; } ISR(ADC_vect) { servo_adc=ADC; // ADC-Messung beendet, Wert speichern if (servo_adc) servo_count++; else servo_count /=2; } ISR(TIMER0_COMP_vect) { static uint16_t count=0; // Zykluszähler if (count>servo_pos) // Servoimpuls senden? { DDRA &= ~1; // nein: auf Eingang ohne PullUp PORTA &= ~1; if (count == servo_pos+100) // seit 100 Takten auf Eingang gesetzt, { ADCSRA |= (1<<ADSC); // ADC starten } } else { DDRA |= 1; // Impuls senden, Pin auf Ausgang PORTA |= 1; // und high } if(count<2000) count++; else { // Zyklus fertig? count=0; if (pause) pause--; } }
Bild hier
http://www.youtube.com/watch?v=39tOx0IxQ40
Der Steuerpin hängt dabei ohne weitere Beschaltung direkt am ADC-Pin. Gemessen habe ich Werte bis über 30. Direkt nach dem Impuls messe ich noch für einige Zyklen das High des Impulses, gegen Ende des Zyklus bleibt der Wert immer bei 0. Gut funktioniert's um 100, sogar mit diesem Müll-Code...
Gruß
mic







Zitieren

Lesezeichen