www.mikrocontroller.net

Forum: Compiler & IDEs Impulse erzeugen


Autor: Norbert S. (norton)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich habe folgendes Problem:

Umgebung:
ATmega48
8000000 Hz interne Clock

Aufgabe:
3 Impulse mit einer Impulsdauer von 1 us
in einer Frequenz von 190 kHz erzeugen
Anschließend Daten verarbeiten und wieder von vorne.

1ter Ansatz waren "delays"
  PORTB |= (1 << PORTB1);
  _delay_us(1);

  PORTB &= ~(1 << PORTB1);
  _delay_us(4.26);

  PORTB |= (1 << PORTB1);
  _delay_us(1);

  PORTB &= ~(1 << PORTB1);
  _delay_us(4.26);

  PORTB |= (1 << PORTB1);
  _delay_us(1);

  PORTB &= ~(1 << PORTB1);
Funktioniert zwar einigermaße die Zeiten sind aber nicht sehr genau (mit 
Oszi nachgemessen.

2ter Ansatz "Timer"
Timer einstellen auf gewünschte Frequenz und Pulsbreite

Timer aktivieren
Im Interrup Impulse Zählen
Timer deaktivieren
Daten Verarbeiten

Der Code des Timersansatzes ist im Anhang.

Mein Problem besteht darin wie ich den Timer deaktiviere?
Oder gibt es für solch eine Anwendung eine elegantere Lösung.

Ich hoffe irgendjemand kann mir da weiterhelfen.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Den Timer deaktiviert man, indem man die CS-Bits alle zu 0 setzt.

Autor: Norbert S. (norton)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Danke für den Tipp @johnny-m
Nach ein par weiteren Fehlern die sich da noch eingeschlichen haben und 
deinem Tipp funktioniert das schon fast.

Jetzt wird allerdings der letzten Impuls nicht immer zurückgesetzt.
Gibt es da noch einen Lösungsansatz?

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Norbert S. (norton)

>Umgebung:
>ATmega48
>8000000 Hz interne Clock

>Aufgabe:
>3 Impulse mit einer Impulsdauer von 1 us
>in einer Frequenz von 190 kHz erzeugen

Ich hoffe dir ist klar dass

- der interen RC-Oszillator nur mässig genau ist (+/-5% wenn er 
kalibriert ist)
- der uC nur Pulse erzeugen kann, die einer ganzzahligen Anzahl Takte 
entspricht.

>1ter Ansatz waren "delays"

Guter Ansatz. hast du aber auch die Optimierung eingeschaltet?
Sonst sitmmen deine Zeiten hinten und vore nicht.

http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

>Funktioniert zwar einigermaße die Zeiten sind aber nicht sehr genau (mit
>Oszi nachgemessen.

Wie gross ist denn der Fehler? Denk dran dass die Befehle zum setzen der 
Ports und die Schleife auch Zeit brauchen, die du in deinen Wartezeiten 
abziehen musst.

MfG
Falk

Autor: Norbert S. (norton)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke @falk
Optimierung ist eingeschaltet

Vieleicht hab ich bei der Genauigkeit einfach ein wenig zu viel 
erwartet.
1 us --> 1,1
4,24 us --> 4,5 us
bei der Frequenz macht sich das allerdings sehr schnell bemerkbar.

Der Fehler wird sich wahrscheinlich aus den von dir schon genannten 
Gründen ergeben.

Funktioniert die _delay_us Funktion prinzipiell überhaupt mit 
Nachkommastellen, oder werden die sowieso weggeschnitten?

Ist ein Timer für solch eine Anwendung auch sinnvoll oder sollte man da 
bei den delays bleiben?

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Norbert S. (norton)

>1 us --> 1,1
>4,24 us --> 4,5 us

Das sind die Toleranzen des RC-Oszillators. Nimm einen Quarz.

>Funktioniert die _delay_us Funktion prinzipiell überhaupt mit
>Nachkommastellen,

Ja.

> oder werden die sowieso weggeschnitten?

Nein. Aber am Ende kann nur eine ganzzahligge Anzahl Takte rauskommen 
(Berechnung über F_CPU). Die wird grundet oder abgeschnitten, weiss ich 
jetzt nicht.

>Ist ein Timer für solch eine Anwendung auch sinnvoll oder sollte man da
>bei den delays bleiben?

Das dein uC nebenbei sowieso nichts anderes macht ist die Delayvarinate 
OK und ggf. sogar flexibler.

MFG
Falk

Autor: Michael Wilhelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei einem Systemtakt von 8MHz (wir nehmen mal an, dass der Oszillator 
genau ist), kannst du nur auf ein Vielfaches von 125nS kommen. Bei 1 µs 
(gemessen 1,1) denke ich mal entweder ein Messfehler oder sowas. Aber, 
4,25µs sollten machbar sein, 4,24 geht nicht.

MW

Autor: Jan M. (mueschel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falk Brunner wrote:
> @ Norbert S. (norton)
>
>>1 us --> 1,1
>>4,24 us --> 4,5 us
>
> Das sind die Toleranzen des RC-Oszillators. Nimm einen Quarz.

Sehe ich nicht so: 1us warten sind 8 Takte, plus einen zum Ausgeben der 
Daten  macht 1.125 ns.

4.26 us werden auf die nächsthöhere Taktanzahl aufgerundet, also 4.375 
us = 35 Takte plus einen Takt zum Ausgeben macht 4.5 us.

Ergo: 0.874 und 4.124 als Delay-Werte angeben (zur Sicherheit letzte 
Stelle abgerundet auf 4) und die Werte stimmen im Rahmen des möglichen 
und der Genauigkeit des RC-Oszillators.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Verzögerungsschleife _delay_loop_1 (die _delay_us zu Grunde liegt)
hat übrigens eine Granulariät von 3 Takten.  Ich bin mir gerade auch
nicht ganz sicher, wie viel Zeit sie zum Einrichten benötigt, auf
jeden Fall benötigen die Befehle dazwischen ja noch Zeit.  Das läuft
auf Erbsenzählen hinaus...

Eine reine Hardwarelösung (CPLD) wäre u. U. angebrachter.

Autor: Jan M. (mueschel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jörg Wunsch:
Gut zu wissen, ich hatte nicht nachgeschaut. Wenn für Norbert die 
erreichbare Frequenz von 190.5 (+- RC / Quartz-Ungenaugikeit) kHz genau 
genug ist, würde ich aber noch nicht zu einer Hardware-Lösung greifen. 
Zur Not, wenn sich zeigt, dass die Verwendung von delay-Funktionen nicht 
genau genug sind, sollte es auch ein kurzer inline-assembler-Abschnitt 
tun.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Jan M. (mueschel)

>> Das sind die Toleranzen des RC-Oszillators. Nimm einen Quarz.

>Sehe ich nicht so: 1us warten sind 8 Takte, plus einen zum Ausgeben der
>Daten  macht 1.125 ns.

Hast recht. Ein Quarz ist aber dennoch nicht verkehrt.

> Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite

>jeden Fall benötigen die Befehle dazwischen ja noch Zeit.  Das läuft
>auf Erbsenzählen hinaus...

>Eine reine Hardwarelösung (CPLD) wäre u. U. angebrachter.

Naja, voher würde ich einfach ASM nehem und die Ebsen, ähhh nops zählen.

MFG
Falk

Autor: neuer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
....- der uC nur Pulse erzeugen kann, die einer ganzzahligen Anzahl 
Takte
entspricht....


gibt es auch halbe takte???

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
neuer wrote:
> ....- der uC nur Pulse erzeugen kann, die einer ganzzahligen Anzahl
> Takte
> entspricht....
>
>
> gibt es auch halbe takte???

Na eben nicht.

Autor: neuer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
....Funktioniert die _delay_us Funktion prinzipiell überhaupt mit
Nachkommastellen, oder werden die sowieso weggeschnitten?....


funktioniert mit nachkommastellen.

es gibt aber minimal immer ein schleifendurchlauf. nop's werden nicht 
ergänzt, die hier evtl gebraucht werden , wenn  ein schleifendurchlauf 
zuviel ist und man dann einen weniger reinsetzt und dann evtl mit 3xnop 
ergänzt . darum die ungenauigkeit.

Autor: neuer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
fazit : solange du mit delay arbeitest und den code nicht als asm mit 
nop schreibst, kommst du mit der genauigkeit nicht hin.

Autor: neuer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
....Das sind die Toleranzen des RC-Oszillators. Nimm einen Quarz....


nein!!!!!!!!!

Autor: neuer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
...._delay_us(4.26);.....

das wird nicht genau umgesetzt...wegen mindestdurchlauf einer schleife 
ohne nop... die es in der delay nicht gibt.

Autor: Norbert S. (norton)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke nochmals für die vielen Antworten und Ratschläge.
Ich werde meine Impulse also mit den "delay" Funktionen realisieren. Die 
Genauigkeit des internen Oszillators sollte für meine Anwendung reichen.

Danke Norton

Autor: UBoot-Stocki (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

kann er nicht an Stelle des delays ein fach "inline" ein paar asm( nop 
); schreiben ??? (Habe die richtige Syntax im Moment nicht zur Hand)

Gruß


Andreas

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  UBoot-Stocki (Gast)

>kann er nicht an Stelle des delays ein fach "inline" ein paar asm( nop
>); schreiben ??? (Habe die richtige Syntax im Moment nicht zur Hand)

Ja.

asm volatile("nop")

MFG
Falk

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>kann er nicht an Stelle des delays ein fach "inline" ein paar asm( nop
>); schreiben ??? (Habe die richtige Syntax im Moment nicht zur Hand)

Ich würde sogar sagen, dass dies die einzige gute Lösung ist.

Bei gewünschten 1 µs Impulslänge und 8 MHz Taktfrequenz müssen zwischen 
dem H-Setzen des Pins und dem L-Setzen 1 µs später genau >>> 8 <<< 
Taktzyklen vergehen.  Das Aufrufen einer Delay-Funktion beinhaltet 
mindestens ein "rcall" sowie ein "ret".  Das benötigt aber schon 7 Takte 
(rcall 3, ret 4)!  Was soll die Delay-Funktion im Innern in dem einen 
verbleibenden Takt machen?

190 kHz Frequenz sind 5.263 µs, abzüglich der 1 µs für die Impulse 
ergeben sich 4.263 µs Wartezeit für den "L"-Zustand.  Das ist genau 
nicht hizukriegen, weil 4.263 µs kein ganzzahliges Vielfaches von 1/8 
MHz = 0.125 µs sind.  Der am nächsten liegende realisierbare Wert ist 
4.25 µs. Das entspricht 4.25/0.125 = 34 Taktzyklen.  Da könnte man an 
den Aufruf einer Delay-Funktion in Erwägung ziehen, aber man könnte auch 
einfach 33 "nop"s hintereinanderschreiben.  Letztere Variante hat den 
Vorteil, dass man sich keinen einzigen Gedanken daran verschwenden muss, 
wie genau die verwendete Delay-Funktion arbeitet (compilerspezifische, 
vielleicht noch versionsabhängige Optimierungen etc.).  Damit die 
Impulse garantiert korrekt generiert werden, muss man lediglich die 
"nop"s richtig abzählen.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ AVRFan (Gast)

>Ich würde sogar sagen, dass dies die einzige gute Lösung ist.

Nicht ganz.

>Bei gewünschten 1 µs Impulslänge und 8 MHz Taktfrequenz müssen zwischen
>dem H-Setzen des Pins und dem L-Setzen 1 µs später genau >>> 8 <<<
>Taktzyklen vergehen.

Ja.

>  Das Aufrufen einer Delay-Funktion beinhaltet
>mindestens ein "rcall" sowie ein "ret".  Das benötigt aber schon 7 Takte
>(rcall 3, ret 4)!

Nein. Die _delay_us() ist ein Inline ASM Makro.

>Vorteil, dass man sich keinen einzigen Gedanken daran verschwenden muss,
>wie genau die verwendete Delay-Funktion arbeitet (compilerspezifische,

_delay_us() hat eine Granularität von 3 Takten, _delay_ms() von vier.

>vielleicht noch versionsabhängige Optimierungen etc.).  Damit die
>Impulse garantiert korrekt generiert werden, muss man lediglich die
>"nop"s richtig abzählen.

Ja. Damit kann man dann auf einen Takt genau arbeiten.

MFg
Falk

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>  Das Aufrufen einer Delay-Funktion beinhaltet
>>mindestens ein "rcall" sowie ein "ret".  Das benötigt aber schon 7 Takte
>>(rcall 3, ret 4)!

>Nein. Die _delay_us() ist ein Inline ASM Makro.

Was heißt da 'nein'?  Hab nix falsches erzählt.  Dass _delay_us() gar 
keine Funktion, sondern ein Inlinemakro ist, kann ja kein Mensch 
ahnen... lach.

>_delay_us() hat eine Granularität von 3 Takten.

Dann gurkt es intern wahrscheinlich gemäß

  ldi  temp, [n]
Loop:
  dec  temp
  brne Loop

Das benötigt zum Durchlaufen nämlich genau 3 n Takte.

Achja, danke für den Hinweis mit dem Inlinemakro... ;-)

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist kein Inline/makro/, sondern eine Inline/funktion/.

Wie die zu Grunde liegenden Schleifen aufgebaut sind, das brauchst
du nicht mutmaßen, das kannst du einfach in den beiden Headerdateien
nachlesen. ;-)

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Es ist kein Inline/makro/, sondern eine Inline/funktion/.

Wird ja immer doller...

>kannst du einfach in den beiden Headerdateien nachlesen. ;-)

Headerdateien? Nie gehört... gg

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.