www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik mega 8 läuft zu langsam?


Autor: max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
moin,
ich habe nen mega 8 aufm stk500 und will ihn mit quarz auf 8mhz laufen 
lassen.
ich habe alles angeschlossen auch die fuses gesetzt doch wenn ich mitm 
ossi messe habe ich gerade mal rund 2mhz.
ich habe folgendes zum messen in der hauptschleife:

 while(1)
 {
 PORTB=~PINB;
 }

warum ist das so langsam?
es wird ja wohl kaum so stark durch c ausgebremst werden, oder?

mfg max

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schau im Assemblerlisting (der vom C Compiler ggf. erzeugten *.LST oder 
der *.LSS Datei oder im AVR Studio Disassembler) nach, wieviele 
Assemblerbefehle der C-Compiler aus diesem Mini-C-Code gemacht hat.

Der AVR lann pro Trakt im günstigsten Fall einen Befehl abarbeiten, bei 
manchen Befehlen sind sogar mehr Takte notwendig... Die Takte pro Befehl 
stehen iM Assembler Instruction Set Manual.

2 MHz am IO-Pin bei 8 MHz CPU-Takt sind bei dem Hintergrund nicht übel.

Autor: jens (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Du wolltest sicher schreiben:
while(1)
 {
 PORTB=~PORTB;
 }
Was hast du gegen 2Mhz. Da ist ein Vergleich und eine Zuweisung bei. 
Kenne mich nicht mit Assembler aus, sonst könnte man sicher die Takte 
ermitteln. Besser du stellst den Takt über einen Timer fest. Der läuft 
über die Hardware und ist von Programmlaufzeiten unabhängig.

Gruß

Jens

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>ich habe nen mega 8 aufm stk500 und will ihn mit quarz auf 8mhz laufen
>lassen.

Die Quarzfrequenz misst du am Quarzoscillator (XTAL1/XTAL2)

Autor: max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich werde leider nicht schlau aus dieser datei...

wie kann ich denn am besten messen wie schnell er wirklich läuft?
ich habe jetzt mal nen 20mhz quarz draufgesteckt und messe jetzt 5mhz an 
portb
kommt ja eigendlich hin:
(20mhz_gequarzt/8mhz_gequarzt)*2mhz_gemessen=5mhz_gemessen
ich glaube ich probier mich mal in assembler...

vielen dank

wenn trotzdem jemand noch ne idee hat wäre das toll.
ich will eigendlich nur ausloten wie schnell ich mit dem timer1 
interupts
machen kann und wieviel zeict ich dazwischen habe.

Autor: max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
der quarz schwingt wunderbar.
ich habe mich nur gewundert das ich mit dem timerinterupt so komische 
zeiten hatte.
wenn ich jetzt über die kommentare nachdenke scheint es vielleicht 
normal zu sein.

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>wie kann ich denn am besten messen wie schnell er wirklich läuft?

Du kannst Dir z. B. ein Mini-Assemblerprogramm schreiben, dass Dir einen 
Pin alle exakt 10 Taktzyklen toggelt:
   [PORTB als Ausgang konfigurieren]

Loop:
   com r16
   out PORTB, r16
   nop
   nop
   nop
   nop
   nop
   nop
   rjmp Loop

ich habe jetzt mal nen 20mhz quarz draufgesteckt und messe jetzt 5mhz an
portb
kommt ja eigendlich hin:
(20mhz_gequarzt/8mhz_gequarzt)*2mhz_gemessen=5mhz_gemessen

Du wirst mit Deinem C-Programm am Pin immer ein Viertel der 
Quarzfrequenz messen. Ist ja auch klar: Dein Controller führt 
wahrscheinlich
Loop:
   com r16
   out PORTB, r16
   rjmp Loop

aus, und das sind 4 Taktzyklen von out bis zum nächsten out (com und out 
benötigen je 1 Zyklus, rjmp 2 - siehe Datenblatt).

>wenn trotzdem jemand noch ne idee hat wäre das toll.

Ne Idee für was??

>ich will eigendlich nur ausloten wie schnell ich mit dem timer1
>interupts machen kann und wieviel zeict ich dazwischen habe.

Wie schnell brauchst Du es denn?

Autor: max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich weiss auch nicht was ich gemacht habe aber jetzt ists besser
habe jetzt:

SIGNAL(SIG_OVERFLOW1)
{
PORTB=~PORTB;
TCNT1=65000;
}

und ich messe ca 70µs, das ist top (mit 8mhz quarz)

vielen dank ihr füchse :)

mfg max

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wie jetzt, vorhin warst du mit 2MHz unzufrieden und jetzt reichen dir 
14kHz?

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>TCNT1=65000;

Kleiner Hinweis: Das mit dem Reload von TCNT1 im Overflowinterrupt 
funktioniert zwar, allerdings kannst Du nicht wissen, wann genau der 
Interrupthandler aufgerufen wird, weil die Instruktionen nicht alle 
gleich viel Taktzyklen beanspruchen (clr: 1, rjmp: 2, rcall: 3, ret: 4), 
oder auch, weil es noch andere Interrupts oder critical sections geben 
kann.

Tip: Wenns genau sein soll, lass den Timer besser im CTC-Mode laufen 
(siehe Datenblatt).  Dann wird bei Überschreiten eines wählbaren Wertes 
ein OutputCompareMatch-Interrupt ausgelöst und der Timer automatisch 
sofort wieder auf Null gesetzt.

Autor: max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vielen dank für den tip ich hab mich schon gefragt wie das mit der 
gleichmäßigkeit dann ist. was ist denn wenn der interupt kommtn wärend 
ich noch im handler bin?

Autor: mehrfacher STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>was ist denn wenn der interupt kommtn wärend ich noch im handler bin?

Die werden erst nach Verlassen der ISR angesprungen, sonfern man die 
anderen Interruptquellen nicht explizit in der ISR wieder frei gibt.
Der AVR besitzt keine Interrupt-Prioritäten, wie der 8051.

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>was ist denn wenn der interupt kommtn wärend ich noch im handler bin?

Der gleiche Interrupt A sollte selbstverständlich niemals auftreten, 
während das Programm noch im Interrupthandler von A verweilt.  Das würde 
das Konzept der Interrupts zunichte machen (Erklärungen dazu weiter 
unten).  Es gilt ja die Regel, dass alle Interrupthandler so kurz wie 
möglich zu halten sind, damit der µC immer genug Luft hat, alle 
auftretenden Interrupts abzuarbeiten.

Was man natürlich nicht verhindern kann, ist das Auftreten einer 
Interruptbedingung B, während sich das Programm gerade im 
A-Interrupthandler aufhält. Viele Interrupts werden schließlich von 
externen Ereignissen ausgelöst, und wenn Du z. B. ein Zeichen von Deinem 
PC über die serielle Schnittstelle abschickst, weißt Du nicht, womit 
Dein Programm in dem Moment beschäftigt ist, in dem die 
UARTDataRxComplete-Interruptbedingung zutrifft.

Dann passiert folgendes. Grundsätzlich wird beim Auftreten einer 
Interruptbedingung immer augenblicklich das zugehörige Interrupt-Flag 
von der Interruptlogik gesetzt.  Diese Flags stecken in den 
I/O-Registern Deines Controllers (z. B. ICF1, TOV1, RXC, TXC, ACI). 
Damit ist der Interrupt "vorgemerkt" (engl. pending interrupt).  Wann 
jedoch der Sprung auf den Interruptvektor (und von dort aus in den 
Interrupthandler) erfolgt, hängt vom I-Flag im SREG (globales 
Interrupt-Freigabeflag) ab.  Solange es gelöscht (alle Interrupts 
gesperrt) ist, erfolgt kein Sprung - der Interrupt bleibt vorgemerkt.

Ist es gesetzt, wird in jedem Fall noch die gerade ausgeführte 
Instruktion zuende verarbeitet, und dann erfolgt der Sprung auf den 
Interruptvektor.  Mit diesem Sprung wird automatisch gleichzeitig das 
spezifische Interruptflag gelöscht (*) und ebenso das I-Flag. 
Interrupthandlers können also nicht durch andere Interrupts 
geinterrupted werden (außer Du setzt das I-Flag am Anfang des Handlers 
durch ein "sei" - das solltest Du aber wegen des Risikos eines 
Stacküberlaufs niemals tun). Das Wieder-Setzen des I-Flags geschieht i. 
a. mit dem "reti" am Ende eines Interruptshandlers, wobei dies dem 
Programmierer obliegt.

(*) Meistens, aber es gibt spezielle Fälle, wo es anders geregelt ist.

Das I-Flag kann man auch selbst löschen und wieder setzten (mit "cli" 
und "sei"), wenn man möchte, dass bestimmte kritische Programmabschnitte 
aus irgendeinem Grund nicht von einem Interrupt unterbrochen werden. Das 
nennt man eine Critical Section.  Auch solche Abschnitte sollten 
möglichst kurz gehalten werden.

Und klar, es kann sogar sein, dass im Moment des Wieder-Setzens des 
I-Flags zufällig mehrere Interrupts anstehen. Dann wird derjenige 
davon ausgeführt, der am weitesten "oben" in der Interruptvektor-Tabelle 
steht, während die anderen natürlich pending bleiben.  Das ist dann so 
eine Art Interrupt-Priorität (aber keine "echte" wie bei anderen 
Controllerfamilien).

Bei lange dauernden Interrupts würde man Gefahr laufen, Interrupts zu 
"verlieren".  Das wäre dann der Fall, wenn ein Interruptflag gesetzt 
würde, welches schon gesetzt ist.  Hält man dagegen alle 
Interrupthandler und alle critical sections wie gesagt kurz, kann das 
nicht passieren, weil alle Pending-Flags schnell wieder gelöscht werden.

Man kann diesen Mechanismus übrigens auch im Simulator vom AVRStudio in 
allen Einzelheiten nachverfolgen.  Gegebenenfalls viel Spaß ;-)

Autor: max (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
joa danke!!!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
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.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.