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):
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?
}
Hier noch eine Anwendung für einen 8MHz-Mega32 ohne RP6-Funktionen:
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--;
}
}
und das Video dazu:
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
Lesezeichen