PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Ständig Interrupt Probleme



Spongebob85
24.10.2007, 23:20
Moin!
Ich hab mein Programm mal ein bisschen weiter endwickelt.
Ich hab einen Servo, der sich hin und her bewegt. Auf den ist ein GP2D12 montiert. Dann hab ich einen LDR, der über ADC "ausgelesen" wird. Und 2 H-Brücken (mit Relais) bei denen 2 Antriebsmotoren über PWM gesteuert werden und über 2 Ausgänge werden die Drehrichtungen geändert. Das alles auf einem Modellpanzer.
Mein Problem war erst das meine Scheinwerfer, die ja über den kontroller eingeschaltet werden wenn´s dunkel ist, geflakert haben, weil die Interruptroutine zu lang war. Das hab ich jetzt hinbekommen. Nur jetzt wo ich die Motorsteuerung programmiert habe, fängt plözlich mein Servo an zu rucken, oder bleibt einfach stehen und zuckt dann rum, läuft dann aber nach ner zeit wieder weiter. Dachte zuerst Hardware-Problem. Hab also ein bisschen rumgemessen und so, aber nichts gefunden. Dann hab ich meinen ganzen Motorkram aus meinem Programm genommen und das Programm wieder auf meinen Mega32 geladen. So funktioniert wieder alles ohne Problem. Mein Servo bewegt sich ganz normal und meine Helligkeitsmessung macht auch kein Problem.

Hier mal mein Programm MIT Motorkram.


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

#ifndef F_CPU
#define F_CPU 16000000
#endif

#define Scheinwerfer PD0
#define Rueckleuchten PD1
#define PWM_ServoPort PD5
#define IR_Servo OCR1A
#define Motor_Links PB3
#define Motor_Rechts PD7
#define Motor_Links_Rueck PC0
#define Motor_Rechts_Rueck PC1

//---------------------------------Globale Variablen----------------------------------
uint8_t a=0, posi=25, count=0;

//---------------------------------Interruptroutinen----------------------------------
ISR(TIMER1_COMPB_vect)
{
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>190)
{
PORTD &= ~(1<<Scheinwerfer);
PORTD &= ~(1<<Rueckleuchten);
}
}

//-------------------------------------IR_Servosteuerung---------------------------------------
int IR_Servoposition(void)
{
if ((count==2)&&(a==0))
{
count=0;
posi++;
if (posi==50)
{
a=1;
}
}

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

//--------------------------------------Motorsteuerung-----------------------------------------
void Motorsteuerung(void)
{
OCR0=50; //255=Max (Links)
OCR2=50; //255=Max (Rechts)
}

//-------------------------------------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
TIMSK |= (1<<OCIE1B);
DDRD |= (1<<PWM_ServoPort);
PORTD |= (1<<PWM_ServoPort);
OCR1B=500; //beliebige zeit (irgendwas unter ner ms)
}

void Initial_Motoren(void)
{
//Ausgang Initialisieren (OC0)
DDRB |= (1<<Motor_Links); //Setzen als Ausgang
PORTB |= (1<<Motor_Links); //Pull-Up

//Ausgang Initialisieren (OC2)
DDRD |= (1<<Motor_Rechts); //Setzen als Ausgang
PORTD |= (1<<Motor_Rechts); //Pull-Up

//Initialisierung der Ausgänge für Rückwärtsfahren
DDRC |= ((1<<Motor_Links_Rueck)|(1<<Motor_Rechts_Rueck));

//Initialisierung PWM für OC0
TCCR0 |= ((1<<WGM01)|(1<<WGM00)); //Fast PWM
TCCR0 |= (1<<COM01); //Clear Output on Compare, Set on Top
TCCR0 |= ((1<<CS02)|(1<<CS00)); //CLK/1024 (15,625kHz, 64µs/periode)
//Compare Register ist OCR0

//Initialisierung PWM für OC2
TCCR2 |= ((1<<WGM21)|(1<<WGM20)); //Fast PWM
TCCR2 |= (1<<COM21); //Clear Output on Compare, Set on Top
TCCR2 |= ((1<<CS22)|(1<<CS21)|(1<<CS20)); //CLK/1024 (15,625kHz, 64µs/periode)
//Compare Register ist OCR2
}

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

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


Ich weiß echt nicht mehr weiter. Wurde mich freuen wenn mal jemand ein Auge drauf wirft, der sich auskennt. Is auch das erste mal das ich was mit Interrupt mache. Hab also nicht wirklich erfahrung, aber denke der is schuld an meinem spinnenden Roboter.

MfG Jan

Ampfing
25.10.2007, 09:48
Hi Spongebob,

gleich mal vorneweg, ich habe mir das Programm nicht im Detail angeschaut und weiß auch nicht, ob alle Register richtig initialisiert werden.
Aber eines ist mir aufgefallen: Du sperrst als letztes in Deiner while(1) alle Interrupts. Dann rufst Du die Funktion helligkeitsmessung(), die auf ein Wandlerergebnis(?) wartet. Das heißt aber auch, dass wenn der Timer überläuft, während Du auf das Ergebnis wartest die ISR nicht angesprungen wird. Das passiert erst, wenn die Funktion helligkeitsmessung() beendet wurde. Je nachdem, wie schnell Dein Timer überläuft kann es passieren, dass Du einen Interrupt nicht mitbekommst (nämlich genau dann, wenn Dein Timer zweimal überläuft, während Du auf den AD-Wandler wartest).
Würde Dir folgendes empfehlen:
1. Nach der Interruptfreigabe (vor while(1)) sperre den Interrupt nicht mehr!
2. Überprüfe in der TimerISR, ob Dein Counter schon 2 ist, wenn ja, setzte ein globales Flag, das Du in der while(1) abfrägst, und nur wenn dieses gesetzt ist rufst Du die Funktion IR_Servoposition().

Hoffe mal, das hilft etwas, ansonsten schreib halt nochmal. Wie gesagt, ob Deine Initialisierungen stimmen kann ich nicht beurteilen, dafür kenne ich die AVRs zu wenig...

Viele Grüße

Spongebob85
25.10.2007, 11:12
Überprüfe in der TimerISR, ob Dein Counter schon 2 ist, wenn ja, setzte ein globales Flag


Heißt das ich soll eine Globale Variable deklarieren, die in der ISR immer bis 2 hochzählen und jedes mal wenn die 2 ist in der main funktion was auslösen?
Das würde doch aber heißen das mein Interrupt wieder länger braucht. Ein "count++" braucht 16ms das heißt doch ich hätte eine verzögerung von 32ms, oder?
Die Register sind meiner meinung nach richtig gesetzt. Einzelnd klappt ja alles. Nur nicht im zusammenspiel.

MfG Jan

Ampfing
25.10.2007, 12:08
Hi,

wie kommst Du darauf, dass ein count++ schon 16 ms braucht? Das wäre nämlich ne ganze Menge für einen Befehl!
Wie schnell taktest Du Deinen Controller denn?

Du brauchst halt ne Möglichkeit zu merken, wann Du den Wert 2 von count erreicht hast (außerhalb der ISR).
Andere Möglichkeit die mir gerade noch einfällt: Wenn Du statt auf den Wandler zu warten einfach abfrägst, ob er fertig ist (also ein if statt dem while) blockierst Du den Controller auch nicht so lange.

Viele Grüße

Spongebob85
25.10.2007, 12:22
Also:
Ich takte mit 16MHz. dann hab ich einen prescaler von 256 eingestellt und einen 9Bit PWM gewählt.
das macht eine Periodendauer von 1/(16MHz/256/512)=0,008192s
da der Zähler ein mal hoch und einmal runter zählt sind das dann 16,384ms.
Ich löse ja den interrupt jedes mal bei Compare von OCR1B aus. der ja immer nur einmal in diesen 16ms kommt.
Aber ich brauche ja auch eine so verhältnissmäßig lange Zeit, da mein Servo ja auch ne gewisse Zeit braucht um sich zu bewegen.
Wenn dir ne bessere möglichkeit einfallen würde, würde ich mich aber auch freuen.

Das mit dem "if" wäre auch noch ne möglichkeit. Aber das braucht je im gegensatz zu dem Interrupt gar nicht so lange.

MfG Jan

Ampfing
25.10.2007, 12:54
Hi,

okay, jetzt weiß ich, was Du mit den 16 ms meintest. Dein Interrupt wird alle 16 ms ausgelöst, das hat aber nix mit der Dauer der ISR zu tun! Wenn Du mit 16 MHz taktest braucht Dein count++ definitiv keine 16 ms (weiß nicht, wie viele Maschinenzyklen ein ADD braucht, aber wenn wir mal von 4 ausgehen wären das 250 ns für den ADD, dann kommt noch a bisserl was für das PUSH und POP dazu, also wenn ganz schlimm kommt sagen wir mal 5 µs)!

Deine Motorsteuerung alleine klappt auch, oder hast Du das noch nicht versucht?
Wie lange braucht denn Dein AD-Wandler, bis seine Wandlung durchgeführt ist?

Noch was: Wenn Du in mehr als einer Funktion auf Variablen zugreifst solltest Du diese als volatile anlegen. Das bewirkt, dass der Compiler nicht mit irgendwelchen lokal gespeicherten Werte arbeiten darf, sondern jedesmal auf die Speicheradresse, an der die Variable liegt, zugreift. Das wäre bei Dir z.B. bei count der Fall. (Konkret heißt das also dann "volatile uint8_t count = 0")

Und wie gesagt, lass mal das cli() in der while(1) weg, das gehört da nicht hin (stört ja nicht weiter, wenn das Warten auf die Wandlung durch den Timer Interrupt unterbrochen werden sollte).
Dann würde ich auch in der Funktion IR_Servoposition auf count >= 2 abfragen und nicht auf count == 2.

Viele Grüße

SprinterSB
25.10.2007, 20:01
die aktualisierung des motors wird durch die hellmessung blockiert. ist das ik?

evtl posi auf >= 50 und <= 0 testen (muss signed sein)

schreib LDR = ADC anstatt mit teilregs rumzufummeln

Spongebob85
27.10.2007, 18:57
Ich bin jetzt wieder zu Hause.
Hab eben eure ganzen Vorschläge mal in mein Prog eingearbeitet
das sieht jetzt so aus:


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

#ifndef F_CPU
#define F_CPU 16000000
#endif

#define Scheinwerfer PD0
#define Rueckleuchten PD1
#define PWM_ServoPort PD5
#define IR_Servo OCR1A
#define Motor_Links PB3
#define Motor_Rechts PD7
#define Motor_Links_Rueck PC0
#define Motor_Rechts_Rueck PC1

//---------------------------------Globale Variablen----------------------------------
volatile uint8_t a=1, count=0, x=0;
volatile int8_t posi=25;

//---------------------------------Interruptroutinen----------------------------------
ISR(TIMER1_COMPB_vect)
{
count++;
if (count>=2)
{
x=1; //Globales Flag???
}
}

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

ADCSRA |= (1<<ADSC);
while (ADCSRA & (1<<ADSC))
{
;
}
LDR = ADC;

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

//-------------------------------------IR_Servosteuerung---------------------------------------
int IR_Servoposition(void)
{
if (a>=1)
{
posi++;
if (posi>=50)
{
a=0;
}
}
else
{
posi--;
if (posi<=0)
{
a=1;
}
}
return ((posi)+440); //440=min, 490=max
}

//--------------------------------------Motorsteuerung-----------------------------------------
void Motorsteuerung(void)
{
OCR0=0; //255=Max (Links)
OCR2=0; //255=Max (Rechts)
}

//-------------------------------------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
TIMSK |= (1<<OCIE1B);
DDRD |= (1<<PWM_ServoPort);
PORTD |= (1<<PWM_ServoPort);
OCR1B=500; //beliebige zeit (irgendwas unter ner ms)
}

void Initial_Motoren(void)
{
//Ausgang Initialisieren (OC0)
DDRB |= (1<<Motor_Links); //Setzen als Ausgang
PORTB |= (1<<Motor_Links); //Pull-Up

//Ausgang Initialisieren (OC2)
DDRD |= (1<<Motor_Rechts); //Setzen als Ausgang
PORTD |= (1<<Motor_Rechts); //Pull-Up

//Initialisierung der Ausgänge für Rückwärtsfahren
DDRC |= ((1<<Motor_Links_Rueck)|(1<<Motor_Rechts_Rueck));

//Initialisierung PWM für OC0
TCCR0 |= ((1<<WGM01)|(1<<WGM00)); //Fast PWM
TCCR0 |= (1<<COM01); //Clear Output on Compare, Set on Top
TCCR0 |= ((1<<CS02)|(1<<CS00)); //CLK/1024 (15,625kHz, 64µs/periode)
//Compare Register ist OCR0

//Initialisierung PWM für OC2
TCCR2 |= ((1<<WGM21)|(1<<WGM20)); //Fast PWM
TCCR2 |= (1<<COM21); //Clear Output on Compare, Set on Top
TCCR2 |= ((1<<CS22)|(1<<CS21)|(1<<CS20)); //CLK/1024 (15,625kHz, 64µs/periode)
//Compare Register ist OCR2
}

//---------------------------------------Hauptprogramm---------------------------------
int main(void)
{
Initial_ADC0();
Initial_IR_Servo();
Initial_Motoren();
sei(); //Globales Interrupt gesetzt

while(1)
{
helligkeitsmessung();
if (x>=1)
{
IR_Servo = IR_Servoposition();
x=0;
count=0;
}
Motorsteuerung();
}
}

Das problem ist, das der Servo immer noch solche macken macht, aber glaub nicht mehr so doll. Mal fährt er bis links dann in die mitte und wieder nach links, mal zuckt der etc.
Hab eben mal den ganzen Motorkram mal kommentiert, so das das programm ohne den kram abläuft. Da hat der Servo gar nicht gesponnen. Müsste also denke ich was mit dem Motorkram nicht richtig sein. Ich Finde aber nichts. Das mit dem "if statt weil" beim ADC weiß ich auch nicht richtig wie ich das machen soll. Müsste ja dann so sein if (ADCSRA !& (1<<ADSC))
{
LDR = ADC;
}
aber dann bekomme ich fehlermeldungen.
Das mit dem Globalen Flag weiß ich auch nicht was das bringt, außer ne zusätzliche Variable. Hab die x genannt.
Hoffe ihr habt noch tipps.

MfG Jan

Hubert.G
27.10.2007, 19:37
Warum machst du den ADC nicht auch mit Interrupt, die Helligkeitsabfrage ist doch nicht wichtig. Starten würde ich sie mit dem Timer, wenn der ADC-Interrupt kommt nur ein Flag setzen, die Auswertung dann im main. So wie es jetzt ist startest du den ADC bei jedem while-Durchlauf und wartest bis die Convertion fertig ist. Du verlierst viel Zeit und wenn du noch so etwas machst ist es leicht möglich das du Timing-Probleme bekommst.

Spongebob85
28.10.2007, 00:41
Ich verstehe das echt nicht.
Meine Interrupt-Routine sieht so aus:


ISR(ADC_vect)
{
conv=1;
}


Conv ist global deklariert:


volatile uint8_t count=0, conv=0;


und meine Helligkeitsmessung sieht jetzt so aus:


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

ADCSRA |= (1<<ADSC);
//while (ADCSRA & (1<<ADSC))
//{
//;
//}
if (conv >= 1)
{
LDR = ADC;
conv=0;
}

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


das licht bleibt jetzt dauerhaft an ](*,)
viel euch das alles beim ersten Roboter auch alles so schwer?

MfG Jan

Hubert.G
28.10.2007, 08:27
Hast du im ADCSRA auch das ADIE gesetzt, ich sehe auch keine Referenzspannung REF im ADMUX, oder verwendest du extere Referenz.
Hast du das Licht mit einem Oszi angesehen, es kommt sehr oft vor das das Licht flimmert und du es nicht bemerkst.

oberallgeier
28.10.2007, 09:29
... Hast du das Licht mit einem Oszi angesehen, es kommt sehr oft vor das das Licht flimmert und du es nicht bemerkst ...
"...mit einem Oszi angesehen..." Kann ich nur wärmstens empfehlen. ICH (bin nach 8 Wochen µC - "Erfahrung" am tiny13 ja noch immer in der Anfängerklasse) und ich hatte die seltsamsten Probleme beim Programmieren mit Interrupt+Timer+ADC+Ports - bis ich einen Oskar genommen hatte und mal den/die Port/s nachgemessen habe. Auf einmal läuft meine Programmiererei erheblich schneller, weil ich die Reaktionen des µC auf mein Programm VIEL besser mitbekomme. Was ich will ist ja leider nicht immer das, was ich mit meinem Programm dem µC auftrage (sozusagen Verständigungsprobleme) . . . [-( ](*,) und das merke ich mit dem Oszilloskop einfach VIEL schneller.

@Spongebob85: Viel Erfolg

Spongebob85
28.10.2007, 17:04
Hatte das ADIE Bit echt noch nicht gesetzt. Hab ich eben erstmal gemacht.
Der Sevo spinnt immernoch. Irgendwie glaub ich das das ein HardwareProblem sein könnte. Wüsste nur nicht warum das dann immer nur zum tragen kommt wenn ich meinen Motorkram programmiere. Theoretisch kann das doch irgend ein kleiner Metallspan auslösen, oder?
Ich kann mir nämlich überhaupt nicht mehr vorstellen, das meine Software fehler macht.
Ich kann programmieren was ich will. Nichts klappt ](*,)



und das merke ich mit dem Oszilloskop einfach VIEL schneller.


Ach ja, wie gerne hätte ich doch ein oszilloskop aber ich komm nirgendwo an sowas ran. Muss ich wohl mein Weihnachtsgeld opfern :-k

Ich werde gleich erstmal ein Layout endwerfen. Mit meinem zusammengebrutzelten kram bin ich immer unglücklicher.

MfG Jan

Hubert.G
28.10.2007, 17:23
Poste doch mal noch den gesamten Code, vielleicht kann man dann etwas erkennen, bei Teile davon ist das immer etwas schwer, weil die Zusammenhänge fehlen.

oberallgeier
28.10.2007, 17:29
Sorry, Jan, ich denk ja, manchmal hätten andere die gleichen Probleme wie ich. Wie sieht es mit der Spannungsversorgung des Servos aus? Oder Strom? Ich hatte doch einige Probleme mit diesen Dingen :( - z.B. Netzteil auf max 200 mA gestellt und so.

Und der Oskar ist blos geliehen :( ich würd sowas teueres nie kaufen.

Spongebob85
28.10.2007, 18:04
@Hubert.G:
Mein Ganzer Code sieht jetzt so aus:


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

#ifndef F_CPU
#define F_CPU 16000000
#endif

#define Scheinwerfer PD0
#define Rueckleuchten PD1
#define PWM_ServoPort PD5
#define IR_Servo OCR1A
#define Motor_Links PB3
#define Motor_Rechts PD7
#define Motor_Links_Rueck PC0
#define Motor_Rechts_Rueck PC1

//---------------------------------Globale Variablen----------------------------------
volatile uint8_t count=0;
volatile int8_t posi=25, a=1;
volatile uint16_t LDR;

//---------------------------------Interruptroutinen----------------------------------
ISR(TIMER1_COMPB_vect)
{
count++;
}

ISR(ADC_vect)
{
LDR = ADC;
}

//---------------------------------Helligkeitsmessung---------------------------------
void helligkeitsmessung(void)
{
ADCSRA |= (1<<ADSC);

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

//-------------------------------------IR_Servosteuerung---------------------------------------
int IR_Servoposition(void)
{
if ((count>=2)&&(a>=1))
{
posi++;
count=0;
if (posi>=50)
{
a=0;
}
}
if ((count>=2)&&(a<=0))
{
posi--;
count=0;
if (posi<=0)
{
a=1;
}
}
return ((posi)+440); //440=min, 490=max
}

//--------------------------------------Motorsteuerung-----------------------------------------
void Motorsteuerung(void)
{
OCR0=0; //255=Max (Links)
OCR2=0; //255=Max (Rechts)
}

//-------------------------------------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..
ADCSRA |= (1<<ADIE);
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
TIMSK |= (1<<OCIE1B);
DDRD |= (1<<PWM_ServoPort);
PORTD |= (1<<PWM_ServoPort);
OCR1B=500; //beliebige zeit (irgendwas unter ner ms)
}

void Initial_Motoren(void)
{
//Ausgang Initialisieren (OC0)
DDRB |= (1<<Motor_Links); //Setzen als Ausgang
PORTB |= (1<<Motor_Links); //Pull-Up

//Ausgang Initialisieren (OC2)
DDRD |= (1<<Motor_Rechts); //Setzen als Ausgang
PORTD |= (1<<Motor_Rechts); //Pull-Up

//Initialisierung der Ausgänge für Rückwärtsfahren
DDRC |= ((1<<Motor_Links_Rueck)|(1<<Motor_Rechts_Rueck));

//Initialisierung PWM für OC0
TCCR0 |= ((1<<WGM01)|(1<<WGM00)); //Fast PWM
TCCR0 |= (1<<COM01); //Clear Output on Compare, Set on Top
TCCR0 |= ((1<<CS02)|(1<<CS00)); //CLK/1024 (15,625kHz, 64µs/periode)
//Compare Register ist OCR0

//Initialisierung PWM für OC2
TCCR2 |= ((1<<WGM21)|(1<<WGM20)); //Fast PWM
TCCR2 |= (1<<COM21); //Clear Output on Compare, Set on Top
TCCR2 |= ((1<<CS22)|(1<<CS21)|(1<<CS20)); //CLK/1024 (15,625kHz, 64µs/periode)
//Compare Register ist OCR2
}

//---------------------------------------Hauptprogramm---------------------------------
int main(void)
{
Initial_ADC0();
Initial_IR_Servo();
Initial_Motoren();
sei(); //Globales Interrupt gesetzt

while(1)
{
helligkeitsmessung();
IR_Servo = IR_Servoposition();
Motorsteuerung();
}
return 0; //wird nie erreicht
}

Irgendwie finde ich auch komisch das man für jeden Interrupt mindestens eine Globale Variable braucht. Oder gibts ne andere Möglichkeit?
Und die Struktur gefällt mir auch nicht wirklich. Ist halt aber mein erster Roboter und das erste mal das ich mehr als die Main funktion verwende.

@oberallgeier
Die Spannungsversorgung erfolgt über einen 7805. An dessen Eingang ein Akku hängt der 9,6V Nennspannung hat. Ist alles schon auf meinem Roboter.

Hab hier von dem Roboter noch ein paar Bilder angehängt:

oberallgeier
28.10.2007, 18:47
@oberallgeier
Die Spannungsversorgung erfolgt über einen 7805. An dessen Eingang ein Akku hängt der 9,6V Nennspannung hat. Ist alles schon auf meinem Roboter...

Hab gerade das Datenblatt des 7805 angesehen. ok, (9,6 - 2) V - also mit dem Dropout das ist ok. Im Datenblatt sind als Ausgang 1,5 A empfohlen, Reichelt hält sich da eher zurück: "1A positiv voltage regulator / Gehäuse: TO-220" . Wieviel zieht der "Rest" Deiner Schaltung aus dieser Quelle? Reicht das alles.

Ich hätte einfacher fragen sollen: hast Du mal die Spannung, am besten vorm Servo Vcc nachgemessen?

Noch schönen Sonntag

Hubert.G
28.10.2007, 19:03
In deiner while-Schleife startest du deine drei Unterprogramme dauernd, speziell den ADC. Wenn du alle 20mSec zuerst dein Servo, dann die Motorsteuerung und dann die Helligkeitsmessung startest, ist das doch schnell genug.
Bei einem Interrupt werden interne Variable nicht gesichert und daher auch schnell mal überschrieben.
Zur Stromversorgung noch, wenn so ein Servo wegläuft braucht es schnell mal 500mA, so ein Spannungszucker kann da ganz rasch was durcheinanderbringen.

Spongebob85
28.10.2007, 20:02
Wieviel zieht der "Rest" Deiner Schaltung aus dieser Quelle? Reicht das alles.

Der servo ist der einzige "Großverbraucher"
Die motoren laufen direkt über den Akku.



In deiner while-Schleife startest du deine drei Unterprogramme dauernd, speziell den ADC. Wenn du alle 20mSec zuerst dein Servo, dann die Motorsteuerung und dann die Helligkeitsmessung startest, ist das doch schnell genug.

Das verstehe ich nicht? Ist das also gut oder schlecht wie ich das mach? Und wie kann ich das verbessern?



Bei einem Interrupt werden interne Variable nicht gesichert und daher auch schnell mal überschrieben.

Was kann ich dagegen machen?



Zur Stromversorgung noch, wenn so ein Servo wegläuft braucht es schnell mal 500mA, so ein Spannungszucker kann da ganz rasch was durcheinanderbringen.

Gibt es noch ne andere Möglichkeit als den 7805? Was kann ich denn gegen diese Spannungsucker machen. Hab an ein und ausgängen vom 7805 Kondensatoren (100nF) über den µC auch einen 100nF kondi und die referenzspannung die von außen kommt ist mit einer 10µH Induktivität und einem 100nF Kondensator stabilisiert (so wie im Datenblatt beschrieben).

Euch auch noch nen schönen Sonntag!

MfG Jan

Hubert.G
28.10.2007, 20:34
Zur while-Schleife habe ich geschrieben: Wenn du alle 20mSec zuerst dein Servo, dann die Motorsteuerung und dann die Helligkeitsmessung startest, ist das doch schnell genug. Also deinen Timer1 zum starten nehmen.


while(1)
{
if(count){
count=0;
IR_Servo = IR_Servoposition();
Motorsteuerung();
helligkeitsmessung();
}
}
return 0; //wird nie erreicht
}

So würde ich die Aufrufe machen.
Zu den Variablen, entweder global oder als volatile kennzeichnen.
Stromversorgung: Das ist so ein Fall wo man ein Oszi braucht um so Grenzfälle festzustellen, ein normales Meßgerät ist nicht schnell genug. Wenn die Software nichts mehr bringt das Servo mal probeweise mit einem eigenen Regler versorgen.

oberallgeier
28.10.2007, 21:27
Hallo Jan,

Der servo ist der einzige "Großverbraucher" Die motoren laufen direkt über den Akku.

Kannst Du die Servos nicht direkt vom Akku fahren? Aber ich will natürlich nicht Dich zu irgendwelchen Klimmzügen verführen - dazu fehlt mir die breite Erfahrung.

Spongebob85
28.10.2007, 22:05
@Hubert.G
Jetzt klappt es!!! Eben hat der Servo auf jeden fall nicht geruckt oder komische sachen gemacht!!!
Bin dir echt dankbar!!! \:D/ =D> \:D/
Werde den gleich mal länger laufen lassen und ein bisschen beobachten.
Nur mit meiner Variablen deklaration bin ich noch ein bisschen unglücklich.

@oberallgeier
Das sind echt noch keine Klimmzüge ;-) Is nur nervig mit dem ständigen umlöten. Ich werde das auf meinem neuen Layout auf jeden fall berücksichtigen. Spendier dem Servo dann einfach einen eigenen 7805.
Danke für den Tipp!

MfG Jan
und schönen restlichen abend.