PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Zeiten ohne Delay



Spongebob85
14.10.2007, 20:25
Moin!
Da ich mein letztes Problem schon nicht hinbekommen habe (Servo-Steuerung) will ich mich gleich mal dem nächsten Problem zuwenden. 8-[ Ich hab jetzt die werte für den Servo eingegeben und lass den servo über eine Variable hin und dann wieder zurück fahren. (Auf dem Servo ist ein GP2D12). Nun hab ich das aber mit delays gemacht und mein restliches Programm läuft in der bearbeitungszeit nicht weiter. Das heißt alles andere Wird auch verzögert (bis jetzt zwar nur eine Lichtmessung, aber das ist schon nervig genug.)

Hier mal mein Code. Hab mal alles was nicht direkt mit dem Servo zu tun hat, sondern nur Delay-mäßig gestört wird, gelöscht. Die Struktur is auch ganz schön hässlich, bekomme das aber irgendwie nich besser hin :-(



#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#ifndef F_CPU
#define F_CPU 16000000
#endif

#define Scheinwerfer 0
#define Rueckleuchten 1
#define PWM_ServoPort 5

//-------------------------------------IR_Servosteuerung---------------------------------------
void IR_Servosteuerung(void)
{
uint8_t a, b, i;
uint16_t x;
a=1;
b=0;
x=450;

while (a)
{
OCR1A=x;
for (i=0; i<=3; i++)
{
_delay_ms(10);
}
x++;
if (x>=480)
{
a=0;
b=1;
}
}

while (b)
{
OCR1A=x;
for (i=0; i<=3; i++)
{
_delay_ms(10);
}
x--;
if (x<=450)
{
a=1;
b=0;
}
}
}

//-------------------------------------initialisierungen---------------------------------------


void Initial_IR_Servo(void)
{
TCCR1A = ((1<<WGM11)|(1<<COM1A1)|(1<<COM1A0)); //9-Bit PWM, Inverted Mode
TCCR1B = (1<<CS12); //Prescaler 256
DDRD |= (1<<PWM_ServoPort);
PORTD |= (1<<PWM_ServoPort);
}

//---------------------------------------Hauptprogramm---------------------------------
int main(void)
{
Initial_IR_Servo();

while(1)
{
IR_Servosteuerung();
}
}



Hoffe es kann wieder jemand helfen.

MfG Jan

Dirk
14.10.2007, 20:58
Hallo Spongebob85,

dein Servo wird ja den IR-Distanzsensor in bestimmte Richtungen stellen, danach wird gemessen und eine neue Position angefahren.
Ich würde deshalb in der Servoansteuerung keine Delays einbauen. Die wirst du ja in deiner Hauptschleife zwischen den Messungen brauchen.

Um in der Hauptschleife keine blockierenden Delays einzubauen, könntest du auch die PWM nutzen: Wenn der Counter bei TOP angekommen ist, wird ein Interrupt ausgelöst, in der ISR eine Zählvariable inkrementiert. Erreicht die einen bestimmten Wert, erfolgt die nächste Messung (natürlich nach dem Anfahren der neuen Position durch das Servo).

Oder habe ich da bei deinem Projekt etwas falsch verstanden?

Gruß Dirk

Hubert.G
14.10.2007, 21:09
Das Problem ist das wärend eines Delay der µC nichts (sinnvolles ausser warten) macht. Du kannst das nur über die Timer lösen.
Siehe hier unter: www.mikrocontroller.net/articles/AVR-GCC-Tutorial
Die Timer/Counter des AVR

Spongebob85
15.10.2007, 01:32
@Dirk


Oder habe ich da bei deinem Projekt etwas falsch verstanden?

Ne, hast du genau richtig verstanden. Glaub langsam verstehe ich diese ganze Zählergeschichte immer besser... Naja, komme wohl auch nicht drum herum.
Ich werde mich dann sicher noch mal melden, wenn ich wieder nicht weiter komme.

MfG Jan

Spongebob85
16.10.2007, 22:15
So, ich hab jetzt was Programmiert. Es kamen natürlich erstmal extrem viele Fehlermeldungen :-(

Das sieht so aus:



int main(void)
{
Initial_ADC0();
Initial_IR_Servo();
uint8_t a; //Global?
a=0; //Global?
uint8_t i; //Global?
i=0; //Global?

while(1)
{
helligkeitsmessung();
IR_Servosteuerung();
}
}

unter Initial... (wo ich ADC und PWM krams initialisiere)
hab ich a und i deklariert. Is das nicht Global?

Dann hab ich das hier geschrieben, damit bei jedem Overflow von Timer1 eine Variable endweder hoch- oder runtergezählt wird:


ISR(TIMER1_OVF) //Diese Routine soll bei Overflow von Timer1 ausgeführt werden
{
if(a=0)
{
IR_Servosteuerung(i);
i++;
if (i>=50)
{
a=1;
}
}
if (a=1)
{
IR_Servosteuerung(i);
i--;
if (i<=0)
{
a=0;
}
}
}


und diese Variable will ich auch gleich verwenden um den OCR1A zu beeinflussen. Das hab ich mir so vorgestellt:


extern void IR_Servosteuerung(uint8_t count)
{
OCR1A=(count+440); //440=min, 490=max
}


Der meckert aber irgendwie wegen den Variablen a und i rum und die Funktion IR_Servosteuerung in main in der Whileschleife gefällt ihm nicht.
Hoffe mir kann jemand helfen. Ach ja. Wo müsste ich dann sei() und cli() hinsetzen? Meine C-Kenntnisse sind wohl nicht so die dollsten... Aber was nicht is kann ja noch kommen :-)

Pierce466
16.10.2007, 23:22
Hallo,

globale Variablen wertden vor der main-Funktion deklariert. also nicht wie die es gemacht hast in der main.

#asm("sei")

kommt in die main Funktion vor deine while-schleife.

Pierce

Spongebob85
17.10.2007, 02:08
Hab die Variablen jetzt unter die #define x y sachen geschrieben und IR_Servosteuerung aus der main-Function komplett rausgenommen.

Mein kompletter Code


#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>
//#include <util/delay.h>

#ifndef F_CPU
#define F_CPU 16000000
#endif

#define Scheinwerfer 0
#define Rueckleuchten 1
#define PWM_ServoPort 5


//Globale Variablen
uint8_t a;
uint8_t i;

//---------------------------------Interrupt-routinen---------------------------------
ISR(TIMER1_OVF) //(c:20)Diese Routine soll bei Overflow von Timer1 ausgeführt werden
{
if(a=0) //(c:22)
{
IR_Servosteuerung(i); //(c:24)
i++;
if (i>=50)
{
a=1;
}
}
if (a=1) //(c:31)
{
IR_Servosteuerung(i);
i--;
if (i<=0)
{
a=0;
}
}
}

//---------------------------------Helligkeitsmessung---------------------------------
void helligkeitsmessung(void)
{
uint16_t LDR;

ADCSRA |= (1<<ADSC);
while (ADCSRA & (1<<ADSC))
{
;
}
LDR = ADCL;
LDR += (ADCH<<8);

if (LDR<150)
{
PORTD |= (1<<Scheinwerfer);
PORTD |= (1<<Rueckleuchten);
}
if (LDR>160)
{
PORTD &= ~(1<<Scheinwerfer);
PORTD &= ~(1<<Rueckleuchten);
}
}

//-------------------------------------IR_Servosteuerung---------------------------------------
void IR_Servosteuerung(uint8_t count)
{ //(c:69)
OCR1A=(count+440); //440=min, 490=max
}

//-------------------------------------initialisierungen---------------------------------------
void Initial_ADC0(void)
{
ADMUX = 0x00; //AREF, resultat rechtsbündig, ADC-Eingang ADC0
ADCSRA = ((1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)); //ADC eingeschaltet, Teilungsfaktor..
DDRD |= ((1<<Scheinwerfer) | (1<<Rueckleuchten));
}

void Initial_IR_Servo(void)
{
TCCR1A = ((1<<WGM11)|(1<<COM1A1)|(1<<COM1A0)); //9-Bit PWM, Inverted Mode
TCCR1B = (1<<CS12); //Prescaler 256
DDRD |= (1<<PWM_ServoPort);
PORTD |= (1<<PWM_ServoPort);
}

//---------------------------------------Hauptprogramm---------------------------------
int main(void)
{
Initial_ADC0();
Initial_IR_Servo();
a=0;
i=0;

sei();
while(1)
{
helligkeitsmessung();
// IR_Servosteuerung();
}
cli();
} //(c:104:2)


und das sind die ganzen Fehlermeldungen:



main.c:20: warning: `TIMER1_OVF' appears to be a misspelled signal handler
main.c: In function `TIMER1_OVF':
main.c:22: warning: suggest parentheses around assignment used as truth value
main.c:24: warning: implicit declaration of function `IR_Servosteuerung'
main.c:31: warning: suggest parentheses around assignment used as truth value
main.c: At top level:
main.c:69: error: conflicting types for 'IR_Servosteuerung'
main.c:24: error: previous implicit declaration of 'IR_Servosteuerung' was here
main.c:104:2: warning: no newline at end of file


Hab mal die Zeilenzahlen kommmentiert drangeschrieben.
Freu mich über jeden Tipp!

MfG Jan

Hubert.G
17.10.2007, 10:40
Ich glaube du solltest mal das GCC-Tutorial durcharbeiten. Die Fehler die da angezeigt werden sind relativ banal.
#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>
//#include <util/delay.h>

#ifndef F_CPU
#define F_CPU 16000000
#endif

#define Scheinwerfer 0
#define Rueckleuchten 1
#define PWM_ServoPort 5


//Globale Variablen
uint8_t a;
uint16_t i;
uint16_t count;
void IR_Servosteuerung(uint16_t i);
//---------------------------------Interrupt-routinen---------------------------------
ISR(TIMER1_OVF_vect) //(c:20)Diese Routine soll bei Overflow von Timer1 ausgeführt werden
{
if(a==0) //(c:22)
{
IR_Servosteuerung(i); //(c:24)
i++;
if (i>=50)
{
a=1;
}
}
if (a==1) //(c:31)
{
IR_Servosteuerung(i);
i--;
if (i<=0)
{
a=0;
}
}
}

//---------------------------------Helligkeitsmessung---------------------------------
void helligkeitsmessung(void)
{
uint16_t LDR;

ADCSRA |= (1<<ADSC);
while (ADCSRA & (1<<ADSC))
{
;
}
LDR = ADCL;
LDR += (ADCH<<8);

if (LDR<150)
{
PORTD |= (1<<Scheinwerfer);
PORTD |= (1<<Rueckleuchten);
}
if (LDR>160)
{
PORTD &= ~(1<<Scheinwerfer);
PORTD &= ~(1<<Rueckleuchten);
}
}

//-------------------------------------IR_Servosteuerung---------------------------------------
void IR_Servosteuerung(uint16_t count)
{ //(c:69)
OCR1A=(count+440); //440=min, 490=max
}

//-------------------------------------initialisierungen---------------------------------------
void Initial_ADC0(void)
{
ADMUX = 0x00; //AREF, resultat rechtsbündig, ADC-Eingang ADC0
Ich habe die Fehler behoben, bei den globalen Variablen sind zwei Zeilen eingfügt, sonst hat sich in der Struktur nichts geändert, so kannst du deine Fehler selbst kontrollieren. Ob das Programm auch richtig läuft habe ich nicht getestet.

Spongebob85
17.10.2007, 12:03
Danke erstmal!!!
Jetzt kommen auf jeden Fall keine Fehlermeldungen mehr.
Mein Servo sagt aber irgendwie auch nichts mehr. Hab also auch noch einen Logik-fehler eingebaut. :-( Dann hab ich ja jetzt erstmal wieder was zu tun.

MfG Jan

Spongebob85
17.10.2007, 23:14
Ich könnte echt durchdrehen.
kann das sein das man den Interrupt wieder löschen muss?
Der Servo bleibt in einer Stellung stehen. Und zwar immer in der wo (Count+440) steht zB. bei 440. wenn man Count+490 eingibt fährt er auf 490.
Das heißt Count wird nicht hochgezählt.
Ich weiß nicht warum.
Hab das Programm nochmal leicht umgeschrieben.
Hier der Code:


#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>
//#include <util/delay.h>

#ifndef F_CPU
#define F_CPU 16000000
#endif

#define Scheinwerfer 0
#define Rueckleuchten 1
#define PWM_ServoPort 5


//Globale Variablen
uint8_t a;
uint16_t i;
//uint16_t count; //hier geändert (wegkommentiert)
//void IR_Servosteuerung(uint16_t i); //hier geändert (wegkommentiert)

//---------------------------------Interrupt-routinen---------------------------------
ISR(TIMER1_OVF_vect) //Diese Routine soll bei Overflow von Timer1 ausgeführt werden
{
while (a==0)
{
//IR_Servosteuerung(i); //hier geändert (wegkommentiert)
i=i+1;
if (i==50)
{
a=1;
}
}
while (a==1)
{
//IR_Servosteuerung(i); //hier geändert (wegkommentiert)
i=i-1;
if (i==0)
{
a=0;
}
}
}

//---------------------------------Helligkeitsmessung---------------------------------
void helligkeitsmessung(void)
{
uint16_t LDR;

ADCSRA |= (1<<ADSC);
while (ADCSRA & (1<<ADSC))
{
;
}
LDR = ADCL;
LDR += (ADCH<<8);

if (LDR<150)
{
PORTD |= (1<<Scheinwerfer);
PORTD |= (1<<Rueckleuchten);
}
if (LDR>160)
{
PORTD &= ~(1<<Scheinwerfer);
PORTD &= ~(1<<Rueckleuchten);
}
}

//-------------------------------------IR_Servosteuerung---------------------------------------
void IR_Servosteuerung(uint16_t count) //hierher wird der Wert von i
//übergeben
{
OCR1A=(count+440); //440=min, 490=max
}

//-------------------------------------initialisierungen---------------------------------------
void Initial_ADC0(void)
{
ADMUX = 0x00; //AREF, resultat rechtsbündig, ADC-Eingang ADC0
ADCSRA = ((1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)); //ADC eingeschaltet, Teilungsfaktor..
DDRD |= ((1<<Scheinwerfer) | (1<<Rueckleuchten));
}

void Initial_IR_Servo(void)
{
TCCR1A = ((1<<WGM11)|(1<<COM1A1)|(1<<COM1A0)); //9-Bit PWM, Inverted Mode
TCCR1B = (1<<CS12); //Prescaler 256
DDRD |= (1<<PWM_ServoPort);
PORTD |= (1<<PWM_ServoPort);
}

//---------------------------------------Hauptprogramm---------------------------------
int main(void)
{
Initial_ADC0();
Initial_IR_Servo();
a=0;
i=0;

while(1)
{
cli(); //hier geändert
helligkeitsmessung();
IR_Servosteuerung(i); //hier geändert
sei(); //hier geändert
}
}


Aus dem AVR-GCC-Tutorial werde ich irgendwie auch nicht schlau.

MfG Jan

Hubert.G
18.10.2007, 10:19
Ich habe jetzt nicht gerade viel Zeit um genau nachzusehen, aber hast du nicht einen Konflikt zwischen PWM-Compare-Match und Timer-Overflow. Du wirst da zwei getrennte Timer verwenden müssen.
Verwendest du einen Mega8?

Spongebob85
18.10.2007, 15:58
Ich verwende einen Mega32. Warum meinst du das es einen Konflikt gibt? Kommt es bei dem Timer in der Verwendungsart vielleicht gar nicht zum Overflow? Timer/Counter0 und Timer/Counter2 wollt ich für die Motorsteuerung nehmen, weil das beides 8-Bit Timer sind.

MfG Jan

Hubert.G
18.10.2007, 17:32
Du arbeitest im PWM-Mode, da kommt es zu keinem Überlauf.

SprinterSB
18.10.2007, 18:24
hi, hier mal ein link in meine hp, wie ich solche timing-aufgaben löse

http://www.gjlay.de/pub/index.html#c-code und dann "Countdown"

bei fragen fragen :-)

ist natürlich nur 1 ansatz von vielen

Spongebob85
19.10.2007, 00:55
Oh man!
Jetzt hab ich wieder was dazugelernt... Aber klingt logisch, das es zu keinem Überlauf kommt.

Das is alles so umständlich!!!
Ich hab schon versucht irgendwelche Interrupt-Flags zu benutzen oder so. Mit den normalen Interrups funktioniert das auch nicht. Es muss doch irgend ein Ereigniss geben, was ich nehmen kann, damit eine Variable hoch bzw. runtergezählt wird, damit mein blöder Servo sich hin- und herdreht ](*,) Die Zeit is mir auch fast egal. Aber Top oder Bottom würde denke ich echt gut passen mit ca. 16ms periodendauer.

MfG Jan

PS.: @SprinterSB: Deine Seite is echt gut! Hab sie mir erstmal in die Favoriten gepackt.

Spongebob85
20.10.2007, 18:14
Hat echt keiner mehr einen Tipp für mich?
Würde mich echt freuen.

MfG Jan

Hanni
20.10.2007, 19:27
Nen Hinweis ... hmm ....

Versuch mal das folgende:
nimm einen Timer um sämtliche Zeiten darüber laufen zu lassen (kleinsten gemeinsamen Nenner suchen - danach die Zeit bis zum Überlauf wählen - entsprechende Variablen eins hochzählen lassen - und diese Auswerten und ggf nen Flag setzen)
nimm nen weiteren Timer für die Erzeugung der PWM für den Servo (am besten nen 16 Bit Timer und Hardware PWM)
werte die Flags deines Zeit Timers im Hauptprogramm aus und starte danach weitere Aktionen ... z.B. das Auslesen deines Sensors ...

der Rest ergibt sich dann von alleine ...

Grpße,
Hanni

Spongebob85
21.10.2007, 15:10
Das Problem ist leider das ich dann 4 Seperate Timer bräuchte. Hab aber nur 3. (Timer0, Timer1, wo man 2 wo man 2 PWMs mit erzeugen kann und Timer2)
Ich will ja nachher auch noch meine Antriebs-Motoren über PWM steuern.

zu 1.:


kleinsten gemeinsamen Nenner suchen - danach die Zeit bis zum Überlauf wählen - entsprechende Variablen eins hochzählen lassen - und diese Auswerten und ggf nen Flag setzen

Kleinsten gemeinsamen Nenner? Das versteh ich nicht so ganz.

zu 2.:


(am besten nen 16 Bit Timer und Hardware PWM)

über Hardware PWM muss ich mich mal informieren...

MfG Jan

Hanni
21.10.2007, 16:49
Kleinsten gemeinsamen Nenner? Das versteh ich nicht so ganz.

Okay, nehmen wir mal an, du hast 4 verschiedene Aufgaben die periodisch erledigt werden müssen. Natürlich jede in einem anderem Intervall.

Ich nehme einfach mal die folgenden Intervalle:

Aufgabe 1: 40ms
Aufgabe 2: 50ms
Aufgabe 3: 80ms
Aufgabe 4: 20ms

Möchte man diese Zeiten nun mit nur einem Timer realisieren, muss man schauen, welche Zeit bei diesen Aufgaben nun den kleinsten gemeinsamen Nenner darstellt.
In diesem Fall sind das klar 10 ms aus denen du alle anderen Zeiten errechnen kannst.

Zur PWM:
Bei Servos bietet es sich vielleicht in der Tat an, das via Software PWM zu lösen, allerdings brauchst du dann gerade bei vielen Servos eine recht ausgeklügelte Programmlogik. Nicht zu vergessen dabei ist, das Software PWM immer sehr viel Rechenzeit benötigt.
Allerdings hättest du dann immer noch die Hardware PWM für deine Motoren zur Verfügung.

Grüße,
Hanni

radbruch
21.10.2007, 17:27
Hallo

Scheinbar boomen die Servos grad, sind ja auch geile Teile. Mit einem 8bit-Timer im CTC-Mode steuert mein 8Mhz-ATMega32 zur Zeit 3 Servos:

https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=322236#322236
https://www.roboternetz.de/phpBB2/viewtopic.php?p=322293#322293

Gruß

mic

Spongebob85
22.10.2007, 01:08
Ich hab mir jetzt folgendes überlegt.
Ich nehme einfach den OCR1B mit dazu und bei jedem Compare soll eine interrupt-routine ausgelöst werden, die meine Variable einen hochzählt. Hab die Funktion umgeschrieben. Die gibt jetzt einen Wert zurück.
Mein Programm gibt auch keine Fehlermeldung raus, nur mein Servo zuckt jetzt ganz schnell in mittelstellung hin und her, aber nur immer paar millimeter in jede richtung.
Kann sich vielleicht noch mal jemand meinen neuen Code ansehen?


#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>

#ifndef F_CPU
#define F_CPU 16000000
#endif

#define Scheinwerfer 0
#define Rueckleuchten 1
#define PWM_ServoPort 5


//Globale Variablen
uint8_t a;
uint16_t count;


//---------------------------------Helligkeitsmessung---------------------------------
void helligkeitsmessung(void)
{
uint16_t LDR;

ADCSRA |= (1<<ADSC);
while (ADCSRA & (1<<ADSC))
{
;
}
LDR = ADCL;
LDR += (ADCH<<8);

if (LDR<150)
{
PORTD |= (1<<Scheinwerfer);
PORTD |= (1<<Rueckleuchten);
}
if (LDR>160)
{
PORTD &= ~(1<<Scheinwerfer);
PORTD &= ~(1<<Rueckleuchten);
}
}

//-------------------------------------IR_Servosteuerung---------------------------------------
int IR_Servoposition(void)
{
ISR(TIMER1_COMPB_vect);

if (a==0)
{
count++;
if (count==50)
{
a=1;
}
}
if (a==1)
{
count--;
if (count==0)
{
a=0;
}
}
return (count+440); //440=min, 490=max
}


//-------------------------------------initialisierungen---------------------------------------
void Initial_ADC0(void)
{
ADMUX = 0x00; //AREF, resultat rechtsbündig, ADC-Eingang ADC0
ADCSRA = ((1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)); //ADC eingeschaltet, Teilungsfaktor..
DDRD |= ((1<<Scheinwerfer) | (1<<Rueckleuchten));
}

void Initial_IR_Servo(void)
{
TCCR1A = ((1<<WGM11)|(1<<COM1A1)|(1<<COM1A0)); //9-Bit PWM, Inverted Mode OC1A
TCCR1A |= ((1<<COM1B1)|(1<<COM1B0)); //Inverted Mode OC1B
TCCR1B = (1<<CS12); //Prescaler 256
DDRD |= (1<<PWM_ServoPort);
PORTD |= (1<<PWM_ServoPort);
OCR1B=500; //beliebige zeit (irgendwas unter ner ms)
}

//---------------------------------------Hauptprogramm---------------------------------
int main(void)
{
Initial_ADC0();
Initial_IR_Servo();
a=0;
count=0;

while(1)
{
sei();
helligkeitsmessung();
OCR1A = IR_Servoposition();
cli();
}
}


Wenigstens tut sich jetzt schon mal was :-)

MfG Jan

Spongebob85
22.10.2007, 01:22
Habs grade rausgefunden. Die Frequenz war einfach viel zu hoch.
Jetzt klappts!!!
Nur eins kann ich mir jetzt echt nicht erklähren. Warum flackern die Scheinwerfer und Rückleuchten jetzt???
Das liegt doch nicht an dem Interrupt, oder? Wie kann ich das denn (falls es so ist) ändern?

MfG Jan