Forum: Compiler & IDEs Impulse erzeugen


von Norbert S. (norton)


Angehängte Dateien:

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"
1
  PORTB |= (1 << PORTB1);
2
  _delay_us(1);
3
4
  PORTB &= ~(1 << PORTB1);
5
  _delay_us(4.26);
6
7
  PORTB |= (1 << PORTB1);
8
  _delay_us(1);
9
10
  PORTB &= ~(1 << PORTB1);
11
  _delay_us(4.26);
12
13
  PORTB |= (1 << PORTB1);
14
  _delay_us(1);
15
16
  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.

von Johannes M. (johnny-m)


Lesenswert?

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

von Norbert S. (norton)


Angehängte Dateien:

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?

von Falk B. (falk)


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-Tutorial#Warteschleifen_.28delay.h.29

>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

von Norbert S. (norton)


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?

von Falk B. (falk)


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

von Michael Wilhelm (Gast)


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

von Jan M. (mueschel)


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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Jan M. (mueschel)


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.

von Falk B. (falk)


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

von neuer (Gast)


Lesenswert?

....- der uC nur Pulse erzeugen kann, die einer ganzzahligen Anzahl 
Takte
entspricht....


gibt es auch halbe takte???

von Simon K. (simon) Benutzerseite


Lesenswert?

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

Na eben nicht.

von neuer (Gast)


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.

von neuer (Gast)


Lesenswert?

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

von neuer (Gast)


Lesenswert?

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


nein!!!!!!!!!

von neuer (Gast)


Lesenswert?

...._delay_us(4.26);.....

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

von Norbert S. (norton)


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

von UBoot-Stocki (Gast)


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

von Falk B. (falk)


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.

1
asm volatile("nop")

MFG
Falk

von AVRFan (Gast)


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.

von Falk B. (falk)


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

von AVRFan (Gast)


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... ;-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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. ;-)

von AVRFan (Gast)


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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.