PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : servoposition über adc(poti) steuern



rocketman123
16.02.2008, 17:24
Hallo.
ich hab bis jetzt mit bascom gearbeitet. ich hab mit bascom als letztes die positionen von zwei servos über zwei potis gesteuert. jetzt bin ich gerade am c++ erlernen. die ersten versuche sind auch gut gelaufen. doch jetzt hab ich gerade ein Problem. ich möchte nun in c++ die Servoposition über den adc-eingang (über poti regelbar) steuern.
ich hab auch schon einiges über adc-programmierung gelesen doch ich komm nicht weiter.
ich muss den adc wert ja irgendwie auslesen. der rest sollte dann kein problem mehr sein. da ich das dann mit einer switch oder if-anweisung lösen kann.
hat mir jemand ein beispielprogramm zum auslesen des adc. vielleicht noch mit ein paar beschreibungen.
danke schon mal

Ceos
16.02.2008, 21:52
studiere gründlich das datenblatt, das ist eigentlich sehr aufschlussreich aber hart im lesen

versuch mal mittels datenblatt folgendes zu verarbeiten

SIGNAL (SIG_OVERFLOW2)
{
if ((TCCR2 & (BV(COM21) | BV(COM20))) != 0) TCCR2 &= ~(BV(COM21) | BV(COM20));
else if (Count%32 == 0) TCCR2 |= BV(COM21) | BV(COM20);
if ((PIND & BV(PD6)) && !(PIND & BV(PD7))) OCR2 = -55-16;
else if ((PIND & BV(PD7)) && !(PIND & BV(PD6))) OCR2 = -55+16;
else {
diff = ADCL + (ADCH << 8);
diff = (diff/32)-16;
OCR2 = -47+(diff);
}
}

SIGNAL (SIG_OUTPUT_COMPARE2)
{
// TCCR2 &= ~(BV(COM21) | BV(COM20));
}

int main(void)
{
Count = 0;
diff = 0;
dir = 4;
cli();
ADCL = 0;
ADCH = 0;
DDRB = BV(PB4) | BV(PB5) | BV(PB3);
PORTB = BV(PB4);
TCNT2 = 0;
OCR2 = -55;
TCCR2 = BV(WGM21) |
BV(WGM20) |
BV(COM21) |
BV(COM20) |
BV(CS22) |
BV(CS21);
TIMSK = BV(TOIE2);// | BV(OCIE2);
sei();
PORTB = BV(PB5);
ADCSRA = BV(ADFR) | BV(ADPS2) | BV(ADPS1);
ADMUX = BV(REFS0);
ADCSRA |= BV(ADEN);
ADCSRA |= BV(ADSC);
while (1){
}
}

Atmega8 mit 8Mhz intern getaktet, das oszi hat ne saubere 1ms +-0.5ms flanke angezeigt und der servo reagiert auch wie erwartet

Link zu Youtube-Video (http://www.youtube.com/watch?v=ILdjzn6RHJs)

rocketman123
17.02.2008, 11:23
hi,
danke für die Antwort. sind ja nette filmchen. nicht schlecht.
ich wollt noch fragen was ich dafür für eine lib benötige. ich bekomm nämlich nur Fehlermeldungen

danke

Ceos
17.02.2008, 12:05
ahso die includes hab cih in ne headerfile gemacht sry XD


#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/timer.h>
#include <avr/signal.h>
#include <avr/sleep.h>


dateinamen sind bei mir

Atmega8Test.c / .h

auf timer und sleep kannste sicherlich pfeifen, die hab ich nur aus nem weiteren versuch einfach mitkopiert XD

rocketman123
18.02.2008, 19:52
also ich hab jetzt ein programm im internet gefunden. ich habs n bisschen verändert. ich möchte jetzt das die led's an portD leuchten wenn an PC0 ADC0 mehr als 2,5V (>512) anliegen. ist das so ok. bei mir passiert nämlich nichts.



#include <avr/io.h>


uint16_t auswertung (void);
volatile uint16_t wert=0;

int main (void)
{
uint16_t i=0,ergebnis=0;

//Ports initialisieren
DDRC = 0xFF; //Port C als Ausgang für die LED's
PORTC = 0XFF; //Pull Up's aktiviert


while(1)
{
ergebnis = auswertung();


if ( (ergebnis < 512) && (ergebnis > 1) )
{
PORTC = (0b00001111);
}
else PORTC = (0b10101010);

}
}



uint16_t auswertung (void)
{


//Initialisieren
ADCSRA = ((1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0));
ADMUX = ((1<<MUX0) | (1<<MUX1) | (1<<MUX2));

//Dummy Auslesung als Warm-Up wie im Tutorial
ADCSRA |= (1<<ADSC);
while (ADCSRA & (1<<ADSC));

//Messung
ADCSRA |= (1<<ADSC);
while (ADCSRA & (1<<ADSC));

wert = ADCL; //ERR
wert += (ADCH<<8); //Alternativ 'wert = ADCW;'

ADCSRA &= ~(1<<ADEN); //ADC Disable

return wert;

}

rocketman123
18.02.2008, 19:55
sorry war der falsche code. das war der urspüngliche #-o


#include <avr/io.h>


uint16_t auswertung (void);
volatile uint16_t wert=0;

int main (void)
{
uint16_t i=0,ergebnis=0;

//Ports initialisieren
DDRD = 0xFF; //Port C als Ausgang für die LED's
PORTD = 0XFF; //Pull Up's aktiviert


while(1)
{
ergebnis = auswertung();


if ( (ergebnis < 512) && (ergebnis > 1) )
{
PORTD = (0b11111111);
}
else PORTD = (0b00000000);

}
}



uint16_t auswertung (void)
{


//Initialisieren
ADCSRA = ((1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0));
ADMUX = (1<<MUX0) ;

//Dummy Auslesung als Warm-Up wie im Tutorial
ADCSRA |= (1<<ADSC);
while (ADCSRA & (1<<ADSC));

//Messung
ADCSRA |= (1<<ADSC);
while (ADCSRA & (1<<ADSC));

wert = ADCL; //ERR
wert += (ADCH<<8); //Alternativ 'wert = ADCW;'

ADCSRA &= ~(1<<ADEN); //ADC Disable

return wert;

}

Ceos
19.02.2008, 08:12
hast du denn den AVCC AGND unf AREF richtig beschaltet ?? also die versorgung für den AD-Wandler ?

rocketman123
19.02.2008, 19:19
agnd und avcc ist richtig beschaltet. aref hab ich nicht beschaltet hat aber bei bascom auch keine probleme gemacht.

radbruch
19.02.2008, 19:57
Hallo

Ist ADC0 nicht Kanal 0 und müste deshalb nicht ADMUX mit 0 geladen werden? (ADMUX=0)

Gruß

mic

Ceos
19.02.2008, 20:57
na du machst mir spass, schau mal bitte in das datenblatt, da steht wenn du aus dem ADMUX register refs1 UND refs2 = 0 hast wird AREF als REFERENZ benutzt!! Du MUSST es also beschalten!!!

MUX0 heisst das du ADC1 verwendest um zu messen und NICHT ADC0

einfach wie in meinem beispiel einen 100nF (geht auch größer) von AREF zu VCC und ADMUX = BV(REFS0); MEHR NICHT

bitte erst das datenblatt vernünftig lesen dann AREF unbeschaltet lassen ^^ (im datenblatt wird sogar ausdrücklich gebeten AREF nie unbeschaltet zu lassen wenn man ADC verwendet)


EDIT: wenn ich das kabel vom steckboard nehme was zum ADC0 führt und es in der luft hängt, kann ich mit dem finger näher kommen und der servo fährt allmählich in die endlage ... gut möglich das du bei deien ersten versuchen einfach nur glück hattest