delay mit C bei AVR-Programmierung

Im Unterforum Microcontroller - Beschreibung: Hardware - Software - Ideen - Projekte

Elektronik Forum Nicht eingeloggt       Einloggen       Registrieren




[Registrieren]      --     [FAQ]      --     [ Einen Link auf Ihrer Homepage zum Forum]      --     [ Themen kostenlos per RSS in ihre Homepage einbauen]      --     [Einloggen]

Suchen


Serverzeit: 27 12 2025  15:32:22      TV   VCR Aufnahme   TFT   CRT-Monitor   Netzteile   LED-FAQ   Oszilloskop-Schirmbilder            


Elektronik- und Elektroforum Forum Index   >>   Microcontroller        Microcontroller : Hardware - Software - Ideen - Projekte


Autor
delay mit C bei AVR-Programmierung

    







BID = 393126

Humus

Aus Forum ausgetreten
 

  


Hey,

da ich zurzeit dabei bin von Bascom auf C umzusteigen bzw. mein wissen zu erweitern bei der Programmierung meiner AVRs ist natürlich gleich ein großes Problem auf getreten, und zwar kann ich mit "_delay_ms()" auch länger als 100ms warten? Hab mir nämlich mal den Code angeschaut der hinter der header datei <avr/delay.h> steht. und da steht dann nur etwas mit knapp 100ms.

Gibt es da eine möglichkeit, oder muss ich mir mein delay selber stricken? d.h. mit schleifen?

BID = 393149

DonComi

Inventar



Beiträge: 8604
Wohnort: Amerika

 

  

Da das abhängig von der CPU-Taktung ist, kann man deine Frage pauschal nicht beantworten.

Wenn Warteschleifen wirklich eingesetzt werden sollen, dann kann man das am besten und saubersten mit Assembler, in diesem Fall also mit Inline-Assembler machen:

Man zählt dazu z.b. ein 16-Bit-Register von einem Startwert bis 0:

sbiw xl, 1
brne pc-1

Da man weis, dass sowohl sbiw als auch brne je zwei Taktzyklen brauchen und die Taktfrequenz auch bekannt ist, kann man sich die Zahl im Register X ausrechnen:

XH:XL = f_cpu * T/4 (T ist die Periodendauer, also der Kehrwert von der Frequenz, die verzögert werden soll, angegeben in S. Wenn du mit Millisekunden rechnest, hast du einen Bruch durch 4000.

Dadurch ergibt sich ein Maximaler Wert für X. Wenn man also eine höhere Verzögerung haben will, muss man zusätzlich mit irgendwelchen Befehlen oder sogar einer Schleife in der Schleife einen höheren Teiler erreichen:

ldi r16, 0xff
dec r16
brne pc-1
sbiw xl, 1
brne pc-4


Damit erhält man einen recht hohen Teiler -> Die Verzögerung wird recht groß.

PS: Sowas macht man aber nur für rel. kurze Verzögerungen, wenn man größere Will, nimmt man am besten den Timer, weil dann das Programm noch weiterlaufen kann. Wenn man das nicht will, macht man halt 'ne Schleife und pollt das Timer-Flag.

_________________

BID = 393257

Humus

Aus Forum ausgetreten

Kann man das auch mit C einigermaßen genau lösen, oder muss ich das mit Assembler lösen?

Es geht um ein einfaches Blinklicht, dass mir einfach nur simbolisieren soll, dass mein AVR noch Arbeitet und sich nicht aufgehängt hat!


Wenn ich ein Blinklicht mit genau 1 Hz haben will muss ich mit Assembler arbeiten, oder?

Aber wie schaut es oben bei meiner Anwendung aus? Kann ich das nicht auch schön mit C lösen und eine ca. zeit errechnen? Oder geht das mit C gar nicht das man da eine ca. Zeit errechnen kann?


BID = 393311

DonComi

Inventar



Beiträge: 8604
Wohnort: Amerika

Doch, klar geht das. Wenn man weis, wie lange die CPU braucht, um einen Befehl zu verarbeiten.

Das Problem ist, dass ein Befehl nicht exakt einen Taktzyklus braucht (in der Regel nicht), wenn z.b. eine Variable hochgezählt wird, muss immer ein kleines Makro diesen Ablauf steuern (RAM in Register laden, Register vorher auf Stack sichern, Operation durchführen, RAM zurückschreiben, Register wieder herstellen,...)

Das dauert viel länger als ein

inc r16.

Deshalb sollten kleinere Schleifen reichen, wie man dass im Endeffekt exakt berechnen kann, kann ich dir nicht genau sagen, da ich sowas so noch nicht gemacht habe; ich nutze dafür meist Assembler.

Aber du kannst es ja mal so machen:

(unsigned short i=0;)



for(i=0; i<=100; i++)
{}

Je nach Taktung erhält man da schon eine "sehbare" Verzögerung. Sonst nimmst du halt noch einen größeren Wert für i<=100. Mit dem Simulator kannst du die Zeit ablesen, die der codeschnipsel braucht: Vorher die "Watch resetten" und dann mit F11 die For-Schleife anspringen.

Das gelbe vom Ei ist das aber definitiv nicht, da muss man dann wissen, wie der Compiler das macht, also wie langer er exakt für einen Durchlauf braucht. Das kannst du am besten bei der Disassemblierung feststellen. Ich habe übrigens extra Short genommen, da das 16-Bit-große Zahlen sind, das dauert dan länger .

_________________

BID = 393312

Humus

Aus Forum ausgetreten

Das mit der for-schleife ist ja klar... =)

Vielen dank! =)

Muss ich dann halt doch Assembler nehmen wenn ich es genau haben will!


BID = 393313

DonComi

Inventar



Beiträge: 8604
Wohnort: Amerika

Der Compiler erzeugt mir aus dem Teil

for(i=0; i<=100; i++)
{}

das hier:
+0000006D: 91800100 LDS R24,0x0100 Load direct from data space
+0000006F: 91900101 LDS R25,0x0101 Load direct from data space
+00000071: 3685 CPI R24,0x65 Compare with immediate
+00000072: 0591 CPC R25,R1 Compare with carry
+00000073: F450 BRCC PC+0x0B Branch if carry cleared
+00000074: 91800100 LDS R24,0x0100 Load direct from data space
+00000076: 91900101 LDS R25,0x0101 Load direct from data space
+00000078: 9601 ADIW R24,0x01 Add immediate to word
+00000079: 93900101 STS 0x0101,R25 Store direct to data space
+0000007B: 93800100 STS 0x0100,R24 Store direct to data space
+0000007D: CFEF RJMP PC-0x0010 Relative jump

Du kannst also jetzt, wenn du Lust dazu hast genau rausfinden, wie lange die CPU diesen Teil wiederholt. Dann kannst du die Formel oben auch hier anwenden, um deine Variable i mit dem richtigen Wert zu laden.


PS: Sry, ich bin grad etwas neben mir, meine Formulierungen sind wieder geil...
Ich meinte oben natürlich, dass nicht das ganze RAM neugeschireben wird sondern nur die entsprechende Adresse im RAM...

_________________

BID = 393429

photonic

Schreibmaschine



Beiträge: 1301
Wohnort: Zürich, Schweiz

Ein delay von mehr als 100 ms (mit delay.h, sehr ineffizienter Zeitverschwendungscode drin) geht nur mit einem CPU-Takt von weniger als 10 MHz.

Sonst machst du am besten eine Timer-Interruptroutine die eine ausreichend grosse Variable hochzählt und bei erreichen eines Schwellenwertes die LED toggelt. So kann der Prozessor in der Zwischenzeit noch andere Dinge erledigen anstelle bloss blöd vor sich hin zu warten. Man braucht keinen Assembler um sehr präzise zu programmieren, das geht mit C genauso gut, wenn du es unbedingt brauchst auch Taktzyklen-genau. Den Delay mit einer For-Schleife zu basteln ist ineffizient, für den Speicher und für die Rechenzeitverschwendung.




BID = 393439

Midnight

Stammposter



Beiträge: 256

Hallo,

vielleicht habe ich auch einfach das ganze nicht genau verstanden.
Die LED soll also symbolisieren das der AVR noch läuft.
Bei der Steuerung mit dem Delay wäre es aber doch egal ob der AVR noch läuft oder sich aufgehangen hat. Ob er nun hängt oder 100% seiner Rechenzeit zum blinken einer LED aufbringt wäre doch gleich, was anderes kann er eh nicht mehr machen.
Besser wäre da wohl dann echt ein Timer oder aber den Watchdog (je nach AVR) zu bemühen.

Gruß

Simon

BID = 393486

Humus

Aus Forum ausgetreten

Genau die LED soll mir anzeigen, dass mein AVR noch läuft und sich nicht aufgeängt hat.

Also das ganze soll folgendermaßen ausschauen:

-LED Bit gesetzt
-Eingaben
-Ausgaben

LED Bit zurück gesetzt
-Eingaben
-Ausgaben

So in der Art, vielleicht auch immer zwischen Eingabe/Ausgbae bzw Ausgabe/Eingabe!

Somit sehe ich dann gleich ob mein AVR sich an irgendetwas aufgehängt hat und wo ich suchen kann bzw. ohne langes rumprobieren an was es vielleicht am PC (Hyperterminal) etc. liegen kann.

Oder gibt es dafür eine bessere Lösung?

BID = 393511

DonComi

Inventar



Beiträge: 8604
Wohnort: Amerika

Ja, wie gesagt wurde, auch schon von mir, den internen Timer.

Wie das geht, steht im Datenblatt.

_________________

BID = 393605

Humus

Aus Forum ausgetreten

Die Timer sind schon alle eingebunden!


BID = 393616

photonic

Schreibmaschine



Beiträge: 1301
Wohnort: Zürich, Schweiz

Du hast keinen freilaufenden Timer dem du noch einen Interrupt abzwacken könntest?

Sonst machst du halt dasselbe im Mainloop falls dieser mit einer konstanten Geschwindigkeit läuft.

Oder du nimmst den Watchdog gegen Controllerabstürze, dann resettet er sich von selbst wenn er sich aufgehängt haben sollte. So sollte die Blinkled überflüssig sein.

BID = 393705

Humus

Aus Forum ausgetreten

Gut das du den Watchdog erwähnst... Irgndwie hab ich gar nicht an den gedacht. Den gibt es ja auch noch! =) Was doch so alles in einem Controller steckt!

Denn müsste ich mir mal genauer anschauen, aber wenn du das schon so erwähnst das der dafür geeignet ist =) Muss ich mich dann mal ein lesen. =D

Dankeschön!!


Zurück zur Seite 0 im Unterforum          Vorheriges Thema Nächstes Thema 


Zum Ersatzteileshop


Bezeichnungen von Produkten, Abbildungen und Logos , die in diesem Forum oder im Shop verwendet werden, sind Eigentum des entsprechenden Herstellers oder Besitzers. Diese dienen lediglich zur Identifikation!
Impressum       Datenschutz       Copyright © Baldur Brock Fernsehtechnik und Versand Ersatzteile in Heilbronn Deutschland       

gerechnet auf die letzten 30 Tage haben wir 17 Beiträge im Durchschnitt pro Tag       heute wurden bisher 6 Beiträge verfasst
© x sparkkelsputz        Besucher : 187976119   Heute : 6431    Gestern : 28182    Online : 233        27.12.2025    15:32
5 Besucher in den letzten 60 Sekunden        alle 12.00 Sekunden ein neuer Besucher ---- logout ----viewtopic ---- logout ----
xcvb ycvb
0.0493130683899