PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : AtMega32 mit Timer0 Servo ansteuern, nur wie?



marc2100
08.08.2009, 17:01
Hi,

wir sind so langsam am verzweifeln, da die von uns durchdachte Servoansteuerung nicht funktioniert.

Wir arbeiten mit einem AtMega32 8MHz

Plan war es das Signal für die Servosteuerung durch Interrupts zu erstellen (Interrupts alle 10µs)

Nur leider ist das Ergebnis nicht das von uns Gewünschte 1,5ms(High) zu 17,5ms(Low) Verhältnis. wir bekommen eine Highzeit von ca. 9ms und demenstprechender Lowzeit.

Der Fehler tritt sowohl bei der Benutzung des internen, als auch bei der Benutzung eines Externen Taktes auf.

Der Timer scheint zu langsam zu sein, aber warum? woran kann das liegen




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

// volatile Interupt Zugriff
volatile int s_AnZeit = 150; // "Lenkzeit" in microsecond
volatile int s_AnZeit_tmp = 150; // Sicherheits Zwischenspeicher für Lenkzeit
volatile long int s_Counter = 0; // Zählervariable für den Servo
PORTD =0x00; // PORTD auf Low setzen



ISR(TIMER0_OVF_vect)
{
TCNT0 = 176;

if (s_Counter == 0)
{
PORTD =0x40; // PORTD6 auf High setzen
}

if (s_Counter == s_AnZeit_tmp)
{
PORTD =0x00; // PORTD auf Low setzen
}

s_Counter++;

if (s_Counter == 2000)
{
s_AnZeit_tmp = s_AnZeit; // Holen der neuen "Lenkzeit"
s_Counter = 0; // Zurücksetzen der Zählervarible
}

}



int main ()
{


DDRD=0xff; // PORTD6 auf Ausgang
PORTD =0x00; // PORTD vorsichtshalber mal auf Low gesetzt


TCCR0 |= (0<<WGM01)|(1<<WGM00)|(0<<COM01)|(0<<COM00)|(1<<CS00);
TCNT0 = 176;
TIMSK |= (1<<TOIE0);

sei();

do
{


}
while (1);

}


Habt ihr eine Idee?

gruß marcus

PicNick
08.08.2009, 17:22
Ob der Mega mit dem 8-MHZ quartz arbeitet, wird durch die Fuses entschieden. Das ist in deinem Beispiel natürlich nicht ersichtlich.

Remark:
Sowas ist natürlich sinnlos, Null verschieben gibt wieder Null
(0<<WGM01)

marc2100
08.08.2009, 17:29
Ja weiß ich doch, ich nutze das STK500 und hab da halt den Quarz bz. den internen Takt benutzt, aber bei beiden war das Ergebniss gleich, also muss der AVR wohl auf 8Mhz laufen.
Das mit der 0 auf 0 schieben, ist noch drin da wir verschieden Einstellungen getestet haben.

Der Punkt ist aber der, das der Timer ja so (also 8Mhz AVR takt) das gewünschte Ergebnis liefern sollte, macht er aber leider nicht, nur warum?

PicNick
08.08.2009, 17:48
Ich hab in eine Prog von mir nachgesehen, ich schreibe in TCCR0 nur den Prescaler rein, alles andere auf NULL (also KEIN WGMxx).

marc2100
08.08.2009, 18:10
Ok das habe ich jetzt mal Versuch, dann müsste die Zeile also so sein:
TCCR0 |= (1<<CS00); //Prescaler auf 1
und halt den Vorladewert TCNT0 = 176;

Aber er macht immernoch genau das selbe

PicNick
08.08.2009, 18:55
Muss annehmen, dass der Mega mit dem internen Oszillator läuft.
d.h. die STK und auch der Quartz sind ihm völlig egal, daher auch das gleiche Ergebnis.

TImer0 ist in der Grundfunktion wirklich nix mystisches.

http://www.rn-wissen.de/index.php/Bascom_-_Erstes_Programm_in_den_AVR_Controller_%C3%BCbertr agen#Das_erste_Programm

Ich nehm aber lieber das Ponyprog (for free), das scheint mir persönlich intuitiver.

Erstmal die Fuses lesen, dann schauen, was eingestellt ist. sind nur zwei Häkchen.

marc2100
08.08.2009, 20:12
Hi,
Ja da der Timer in normaler Grundfunktion ist, dachten wir ja auch, kann nicht so schwer sein. Aber es geht nicht richtig, er ist ein Stück zu langsam, also der Takt zu lange.
Das mit dem Quarz ist auch nicht das Problem, die Fuse-Bits sind jetzt auf extern gesetzt, wenn ich den Quarz rausnehme, generiert er überhaupt kein Signal, von daher denke ich, läuft der Quarz wie es sein sollte.
Kann der Interupt-betrieb eine so lange "Störung" erzeugen, also anstatt 1,5mS ganze 9mS?
Ich habe auch mal den AtMega getauscht, aber keine Besserung.

Hat noch jemand einen Tipp was ich versuchen kann?

PicNick
08.08.2009, 20:14
Ich hab immer erstmal ein Testprogramm am Laufen, das jede Sekunde einmal blinkt.
Da kann man schon mit freiem Auge abschätzen, ob die Speed passt.

marc2100
08.08.2009, 22:40
Da muss ich dir recht geben, habe mal eine 1S blinkende LED mit dem Timer gemacht, das funktioniert wie es sollte.
Danach habe ich mich nochmal an mein Programm oben gesetzt und einfach den Port in der ISR auf High und dann sofort wieder auf Low gesetzt...
ISR (Timer0) {
PORTD=0x04;
PORTD=0x00;}
Der Port bleibt für ca. 9mS high.
Woran kann das liegen, Rest-Kapazität die den Pegel oben hält?
Oder einfach am 8 Bit-Timer?

steg14
08.08.2009, 23:47
ich kenne mich mit dem mega32 nicht so aus, aber ist es nicht so, dass
du hier TCCR0 |= (0<<WGM01)|(1<<WGM00) in den PWM-Modus schaltest
statt: TCCR0 |= (0<<WGM01)|(0<<WGM00) für Normalmodus.
Ist auch glaube ich das was PicNick meinte.

marc2100
09.08.2009, 06:42
Ja, der Code oben stimmt nicht mehr ganz, hier der Versuch, nur den Port so kurz wie möglich auf High zu schalten



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

ISR(TIMER0_OVF_vect)
{
TCNT0 = 176;
PORTD =0x40; // PORTD6 auf High setzen
PORTD =0x00; // PORTD auf Low setzen
}

int main ()
{
DDRD=0xff; // PORTD6 auf Ausgang
PORTD =0x00; // PORTD vorsichtshalber mal auf Low gesetzt

TCCR0 |= (1<<CS00);
TCNT0 = 176;
TIMSK |= (1<<TOIE0);

sei();

do
{


}
while (1);

}


Nur bleibt der Port halt wie gesagt für ca. 9mS High, und da ich bis jetzt noch nie ein Signal selbst erzeugen wollte, weiß ich nicht ob das jetzt normal ist, sprich das Umschalten der Ports wirklich so lange dauert, oder ob ich hier einfach etwas übersehen habe.
Weil bei "längeren" Signalen gehts ja, nur nicht unter 9mS, was ich halt seltsam finde, da ich denke am Umschalten kanns doch nicht liegen, eine PWM z.B. kann den Port ja auch so schnell schalten, nur auf meine manuelle Art klappt es einfach nicht.

steg14
09.08.2009, 08:31
Dein Programm funktioniert bei mir. Atmel defekt?

McJenso
09.08.2009, 09:25
Hallo,

kannst du an einen anderen PORT eine LED anschließen, die du gleich am Anfang der Main über ein High Signal einschaltest? Nur einschalten, nichts anderes, der Rest des Programms und der weitere Aufbau bleiben wie sie sind. Jetzt beobachte an der LED mit dem Oszi das Signal. Ohne den Schaltplan zu kennen, mich beschleicht der Gedanke nach einem Reset, ausgelöst durch ein Hardwareproblem.

Gruß

Jens

marc2100
09.08.2009, 10:25
So, jetzt hab ichs hinbekommen, ich habe zwar keine Ahnung warum es jetzt funktioniert aber es geht auf einmal nach mehrmaligem brennen.

Ich habe langsam den Verdacht das mein PC der Übeltäter ist...

Also Danke für euren ganzen Tipps, damit kann ich jetzt schonmal das STK500 + AVR als Fehlerquelle ausschließen O:)

Jetzt für alle die Interessiert sind, hiermit bekomme ich ein ca. 1mS High + 19mS Low



#define F_CPU 8000000L
#include <avr/io.h>
#include <avr/interrupt.h>
volatile int time=0;

ISR(TIMER0_OVF_vect)
{
TCNT0 = 176;
time++;
if (time<=80)
{
PORTD =0x40; // PORTD6 auf High setzen
}

if (time>=80 && time<=1600)
{
PORTD=0x00;
}
if(time>=1600)
{
time=0;
}
}

int main ()
{
DDRD=0xff; // PORTD6 auf Ausgang

TCCR0 |= (1<<CS00);
TCNT0 = 176;
TIMSK |= (1<<TOIE0);

sei();
do
{
}
while (1);
}

steg14
09.08.2009, 10:25
OK. aber da ändert sich nichts
PORTC0 ist 1 , auf PORTD6 sind kurze Impulse

---------------

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

ISR(TIMER0_OVF_vect)
{
TCNT0 = 176;
PORTD =0x40; // PORTD6 auf High setzen
PORTD =0x00; // PORTD auf Low setzen
}

int main ()
{
DDRD=0xff; // PORTD6 auf Ausgang
PORTD =0x00; // PORTD vorsichtshalber mal auf Low gesetzt

TCCR0 |= (1<<CS00);
TCNT0 = 176;
TIMSK |= (1<<TOIE0);

DDRC =1; //so?
PORTC =1;


sei();

do
{


}
while (1);

}

McJenso
09.08.2009, 10:53
Hallo,

wenn der Controller sich ständig resetet hätte, würde man das an dem Signal der LED erkennen können. Aber nun geht es ja.

Gruß

Jens

steg14
09.08.2009, 11:55
gut.
Und nun such mal den Fehler in deinem alten Programm, sonst hast du nichts dazu gelernt, sondern nur rumprobiert.