2 ADC und 2 Servos

OP #3190071
Lesenswert?
• ▲
▼
Hi

Ich hab wieder mal ein Problem...

Ich möchte 2 Servos ansteuern und dazu 2 Potis verwenden, die Position 
des Servos soll von den Potis mittels ADC Wandlung kommen.

Mir ist (hoffentlich) so halbwegs klar was ich machen muss, aber 
irgendwie funktioniert das ganze nicht, ich schätz mal der Code passt 
nicht.

Mein Plan war folgender:
Ich führe eine ADC Wandlung durch,
sende den Wert an die PWM1
wechsle das Bit im ADMUX Register,
führe ADC Wandlung durch,
sende an PWM 2 usw

Wenn ich das ganze mit einem ADC und einem Servo mache funktioniert es, 
bei zwei leider nicht, da wackeln die Servos von eine Endstellung in die 
andere und fahren wieder zurück...

Ich hoffe ihr könnt mir bitte helfen, oder mir nen Tipp geben

Danke
lg

Hier der Code
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#define ADATE 5                     // Definition is missing in                                 
4
void pwm_init()                // some Versions of AVR Studio
5
{
6
    TCCR1A = _BV(COM1A1)           // _BV Bit Values      
7
                | _BV(COM1B1)      // Inverted Mode   
8
                | _BV(WGM11) ;     
9
    TCCR1B = _BV(WGM13) 
10
                | _BV(WGM12)    // Fast PWM
11
                | _BV(CS00);    // Prescaler
12
    ICR1 = 20000;              
13
    OCR1A = 1500;
14
  OCR1B = 1500;        
15
    DDRD = _BV(PD4)| _BV(PD5);     
16
}                                  
17
int main(void)
18
{
19
  DDRB |= (1 << 0); // Set LED as output
20
  
21
    ADMUX |= (1<<REFS0)|(1<<MUX0);           // Set reference to AVcc
22
    ADCSRA |= (1<<ADEN)|(1<<ADATE)|          // Enable ADC, Enable auto Triggering
23
            (1<<ADPS1)|(1<<ADPS0)|(1<<ADSC); // Prescaler = 8 --> DIGITAL
24
    pwm_init();      // initialize timer in PWM mode
25
    while(1)      // run forever
26
    {
27
      if((ADMUX&(1<<MUX0))){        // Check if MUX0=1
28
        while(!(ADCSRA&(1<<ADSC)));    // Wait until a conversion is finished
29
        OCR1A =ADC*2+1000;        // Calculate value for Servo
30
        ADMUX &= ~(1<<MUX0);      // Delete MUX0        
31
        }  
32
                
33
      if((ADMUX&(1<<MUX0))==0){  
34
        while(!(ADCSRA&(1<<ADSC)));    // Wait until conversion is finished  
35
        OCR1B =ADC*0.975+1000;       // Calculate value for Servo   
36
        ADMUX |= (1<<MUX0);         // Set MUX0 to 1  
37
        }  
38
   } 
39
}
#3190129
Lesenswert?
• ▲
▼
Herbert Huber schrieb:

>     ADCSRA |= (1<<ADEN)|(1<<ADATE)|          // Enable ADC, Enable auto
> Triggering

vergiss den Autotrigger.
Du weißt sonst nie, ob dein Umsetzen des MUX-Registers bei nächsten 
Wandlungsergebnis schon erfolgt ist oder nicht. Denn der Zeitpunkt, ab 
dem das Wandlungsergebnis korrekt dem ADC-Kanal zugeordnet werden kann, 
hängt davon ab, ob zum Zeitpunkt der Bit-Setzens bereits eine Wandlung 
im Gange ist oder nicht. Das kannst du aber nicht brauchen.

Lass den Autotrigger weg und starte jede Messung einzeln nachdem du die 
MUX Bits korrekt gesetzt hast.
1
int main()
2
{
3
  pwm_init();
4

5
  ADMUX |= (1<<REFS0);
6
  ADCSRA |= (1<<ADEN)|
7
            (1<<ADPS1)|(1<<ADPS0)|(1<<ADSC);
8

9
  while( 1 )
10
  {
11
    // Servo 1
12
    ADMUX = ADMUX & ~0x03 | 0;    // Kanal 0 aktivieren
13
    ADCSRA |= (1<<ADSC);          // Wandlung starten
14
    while((ADCSRA&(1<<ADSC)))    // aufs Ergebnis warten
15
      ;
16
    OCR1A = ADC*2 + 1000;         // und setzen
17

18
    // Servo 2
19
    ADMUX = ADMUX & ~0x03 | 1;    // Kanal 1 aktivieren
20
    ADCSRA |= (1<<ADSC);          // Wandlung starten
21
    while((ADCSRA&(1<<ADSC)))    // aufs Ergebnis warten
22
      ;
23
    OCR1B = ADC*2 + 1000;         // und setzen
24
  }
25
}

Die ganze ADC Abfragerei könntest du sinnvollerweise noch in eine 
Funktion auslagern, so das deine Hauptschleife abmagert zu
1
  while( 1 )
2
  {
3
    // Servo 1
4
    OCR1A = ADC_Read( 0 ) * 2 + 1000;
5

6
    // Servo 2
7
    OCR1B = ADC_Read( 1 ) * 2 + 1000;
8
  }
9
}

Und beachte: Die ADC Wandlung ist im Gange, SOLANGE das ADSC Bit gesetzt 
ist! Die Logik ist ganz einfach: Du setzt das Bit um die Wandlung zu 
starten und der ADC löscht es wieder wenn er fertig ist. Solange es also 
auf 1 ist, ist das Ergebnis noch NICHT fertig und du musst warten.
#3190141
Lesenswert?
• ▲
▼
Stefan Ernst schrieb:
> Karl Heinz Buchegger schrieb:
>> Lass den Autotrigger weg und starte jede Messung einzeln
>
> Du hast allerdings aus seinem Code einen entscheidenden Fehler in deinen
> übernommen. Schau dir nochmal das ADSC-Polling an. ;-)

Ja, habs gerade gemerkt und nachgetragen.

Nichts desto trotz: mit mehreren Kanälen kann man den Autotrigger nicht 
sinnvoll in dieser Form benutzen.

Ich werde sowieso nie verstehen, warum jeder immer wieder das Rad neu 
erfinden muss, wenn es im AVR-GCC-Tutorial fix&fertige Funktionen 
dafür gibt.

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.