Impulse erzeugen

OP #766806
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.
Angehängte Dateien:
#766870
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
OP #766913
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?
#766924
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
Gast #766927
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
#766979
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.
Moderator Persönliche Seite #767002
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.
#767020
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.
#767107
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
Gast #767126
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.
Gast #768650
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.
#768734
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
Gast #768755
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... ;-)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren