PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Frequenzgenerator Entwickeln ? !



nase
18.12.2010, 15:32
Hallo, suche jemand der einem Anfänger in einfachen Schritte bei der Entwicklung eines Frequenzgenerators hilft, habe schon einige Versuchem mit Timer unternommen, allerdings komme ich nicht über Frequenz von ca 4 Khz hinaus. Habe zwar schon einige fertige Programm gefunden , allerdings habe ich die nicht durchschauen können.
Mir geht es aber in der Hauptsache um das Verständnis.
Das war mein letzter Test:



$regfile "m32def.dat"
$crystal = 1000000
$hwstack = 32
$swstack = 10
Config Lcd = 16 * 2
Config Lcdpin = Pin , Db4 = Portc.2 , Db5 = Portc.3 , Db6 = Portc.6 , Db7 = Portc.7 , Rs = Portc.5 , E = Portc.4
D e f i n i t i o n d e r V a r i a b l e n
Dim Taktwert As Byte
D e f i n i t i o n d e r P in 's
Portb = &B00011110
Ddra = &B11111111
T i m e r 0
Config Timer0 = Timer , Prescale = 1
Enable Timer0
On Timer0 Timer_null
Enable Interrupts
H a u p t p r o g r a m m
Do
If Pinb.1 = 0 Then Taktwert = Taktwert + 1
If Pinb.2 = 0 Then Taktwert = Taktwert -1
Gosub Anzeige
Waitms 50
Loop
U n t e r r o u t í n e A n z e i g e
Anzeige:
Cls
Locate 1 , 1
Lcd "Taktwert=" ; Taktwert
Locate 2 , 9
Lcd "V.FG6A"
Waitms 100
Return
U n t e r r o u t i n e T i m e r 0
Timer_null:
Timer0 = Taktwert
Toggle Porta.0
Return

stefan_Z
18.12.2010, 17:38
Die LCD-Ausgabe brauch sehr viel Zeit, das sollte die 4kHz erklären. Die LCDs vertragen nicht so schnelle Datenschübe, daher wird in der Routine quasi mit WAITUS / WAITMS gearbeitet.
Den Aufruf würde ich einfach mit in die IFs packen, so dass die Anzeige nur dann aktualisiert wird, wenn du klickst. Allerdings bräuchtest du auch ne Art Entprellung, damit du nicht pro Klick 20 Schritte hochgehst.

PICture
18.12.2010, 18:57
Hallo!


Hallo, suche jemand der einem Anfänger in einfachen Schritte bei der Entwicklung eines Frequenzgenerators hilft ....Mir geht es aber in der Hauptsache um das Verständnis.

Ich könnte dir als PIC ASMan ausschliesslich bei Hardware (Elektronik) helfen, antworte jedoch nur auf konkrete Fragen. ;)

MfG

nase
18.12.2010, 19:08
Hallo!


Hallo, suche jemand der einem Anfänger in einfachen Schritte bei der Entwicklung eines Frequenzgenerators hilft ....Mir geht es aber in der Hauptsache um das Verständnis.

Ich könnte dir als PIC ASMan ausschliesslich bei Hardware (Elektronik) helfen, antworte jedoch nur auf konkrete Fragen. ;)

MfG

Danke , aber mir geht's nur um die Software

gruß Nase

nase
18.12.2010, 19:33
Die LCD-Ausgabe brauch sehr viel Zeit, das sollte die 4kHz erklären. Die LCDs vertragen nicht so schnelle Datenschübe, daher wird in der Routine quasi mit WAITUS / WAITMS gearbeitet.
Den Aufruf würde ich einfach mit in die IFs packen, so dass die Anzeige nur dann aktualisiert wird, wenn du klickst. Allerdings bräuchtest du auch ne Art Entprellung, damit du nicht pro Klick 20 Schritte hochgehst.

Hab die LCD Anzeige komplett rausgenommen, an der Frequenz hat sich nichts geändert, immer noch maxomal 4 Khz

Sauerbruch
18.12.2010, 20:48
Ich hab´ Deinen Code mal im Simulator laufen lassen. Es zeigt sich, dass die komplette Timer0-ISR 126 Taktzyklen verbraucht. Es müssen ja auch eine ganze Menge Register "gerettet" und nach Ende der ISR wieder zurückgegeben werden. Das sind also etwa 125µs Zeitverlust pro Flanke, also etwa 250µs pro kompletten Impuls - was sich ziemlich genau mit den von Dir gemessenen maximalen 4 KHz deckt.

Das ist ein sehr lehrreiches Beispiel dafür, dass auch die kürzeste ISR dem Controller ganz schön viel Arbeit bereitet :-) Aber Du wolltest ja wissen, wie Du mehr rausholen könntest. Und da sehe ich zwei Möglichkeiten:

Entweder Du erhöhst die Taktfrequenz des Controllers. Der Mega32 kann mit dem internen Oszillator bis zu 8MHz - dann kämst Du schon mal bis etwa 32 kHz.

Oder Du arbeitest mit der Hardware-PWM - und um genau zu sein, im "CTC"-Modus. Das ist ein sehr feines Feature, was die Erzeugung von absolut frequenzgenauen Rechtecksignalen erlaubt, ohne dass der Controller auch nur das kleinste bisschen dafür rechnen oder arbeiten muss. Das läuft nebenbei im Hintergrund ab, während der Controller sich um andere Dinge kümmern kann.

Im Datenblatt des Mega32 gibt´s auf Seite 74 ein Bild dazu, das mehr sagt als 1000 Worte. Der Wermutstropfen ist allerdings der, dass Bascom (soviel ich weiß) den CTC-Modus nicht direkt unterstützt - man muss die beiden relevanten Register halt "von Hand" setzen. Aber das tut nicht weh - und wenn man verstanden hat was man dabei tut, macht´s sogar Spaß :-)

for_ro
18.12.2010, 20:48
Hallo nase,
ich halte es für leicht nachvollziehbar, dass du nicht über 4KHz hinauskommst.
Der Aufruf der Timer ISR, die Befehle in der ISR und der Rücksprung ins Programm benötigen 125 Takte. Da du togglest, also 250 Takte für eine volle Periode. Macht bei 1MHz/250 = 4KHz.
Taktwert > 195 führt übrigens dazu, dass die Frequenz wieder kleiner wird.
Ich sehe zwei Möglichkeiten, die Frequenz zu erhöhen:
1. Du rufst die Timer ISR mit der Nosave Option auf. Dann musst du wissen, welche Rehister für deinen Code gebraucht werden. Diese musst du dann von Hand pushen und poppen.
2. Du erzeugst die Ausgabe mittels eines Timers im CTC Mode. Dann kannst du bis auf halbe Taktfrequenz kommen. Dabei sind allerdings nur bestimmte Frequenzen möglich (1/2, 1/4, 1/6, ...). Und du musst den zugehörigen Pin frei haben.
Dafür geht das Ganze rein in Hardware, also ohne den µC zu belasten. Will heißen, dein Programm hat noch 100% der Rechenzeit zur Verfügung.

@Sauerbruch: warst du ein paar Sekunden schneller. Geht übrigens in Bascom so:
Config Timer0 = Timer , Clear Timer = 1 , Compare = Toggle , Prescale = 1
in OCR0 setzt du dann den Wert, bei dem getoggelt werden soll.

nase
19.12.2010, 07:18
Also das mit der höheren Taktfrequenz ist mir bewusst , und auch schon eingeplant. Aber wie gesagt, es geht mir nicht um die Frequenzausgabe sondern um die Machbarkeit, zB. aus 1 Mhz so viel wie möglich rauszuholen.
Und um das wie . Ihr habt mir jetzt schöne Ansetze geliefert , die ich jetzt erst mal verdauen und testen muß.Melde mich dann wieder.
gruß Nase

s.o.
19.12.2010, 08:38
Ist mir jetzt zu aufwändig, den ganzen Treat exakt zu lesen. Ich überfliege nur mal deinen Quellcode. Ergebnis: Ich bin irgendwie zu dumm dafür...

Rechteck. richtig? Was spricht denn dagegen die ganze Timing von der Hardware machen zu lassen. Schau dir mal den CTC (Clear Timer on Compare Match) Mode an. Da kannste alle Alle Frequenzen bis CPUFrequenz/2 erzeugen... Also Theoretisch dürfste bis 10 Mhz Tack kommen...

Außerdem würde ich sehr driftig von Bascom oder wie sich diese Sprache schimpft abraten... Die Sprache ist Langsam und absolut nicht portierbar...

wkrug
19.12.2010, 10:05
Ein Kollege und ich sind auch gerade dabei einen Frequenzgenerator zu entwickeln.

Wir sind dabei auf den DDS Chip AD9833 von Analog Devices gestossen.
Der gibt Sinus, Dreieck und Rechteck Signale raus.

Als Verstärker haben wir mal einen AD8000 geplant, da der 9833 nur 0,6Vpp Ausgangssignal macht.

Als Maximalfreuenz haben wir so um die 1MHz angepeilt.
Der AD9833 könnte zwar theoretisch Signale bis 12MHz generieren, der Sinus hat aber dann nur noch 2 Stützstellen und schaut somit "grausig" aus.

Wenn man nur Sinus braucht wär eventuell ein annderer DDS Chip besser geignet. Ich hab auch schon mal mit einem AD9951 rumgebastelt.
Das ist aber dann schon so ziemlich das Ende, was man händisch noch einlöten kann.

hardware.bas
19.12.2010, 12:05
s.o. schrieb: " Außerdem würde ich sehr driftig von Bascom oder wie sich
diese Sprache schimpft abraten... Die Sprache ist Langsam und absolut
nicht portierbar..." Eigenartige Meinung! Ist doch DIE Sprache des
Praktikers, ohne C(hinesisch) lernen zu müssen, aber egal. Geschmacks-
sache. Zum Thema: Für die Erzeugung eines sauberen Sinus wäre auch
die Anwendung des PLL-Verfahrens in Verbindung mit einem
durchstimmbaren Oszillator denkbar. VG Micha

nase
19.12.2010, 15:35
Ich hab´ Deinen Code mal im Simulator laufen lassen. Es zeigt sich, dass die komplette Timer0-ISR 126 Taktzyklen verbraucht. Es müssen ja auch eine ganze Menge Register "gerettet" und nach Ende der ISR wieder zurückgegeben werden. Das sind also etwa 125µs Zeitverlust pro Flanke, also etwa 250µs pro kompletten Impuls - was sich ziemlich genau mit den von Dir gemessenen maximalen 4 KHz deckt.

Das ist ein sehr lehrreiches Beispiel dafür, dass auch die kürzeste ISR dem Controller ganz schön viel Arbeit bereitet :-) Aber Du wolltest ja wissen, wie Du mehr rausholen könntest. Und da sehe ich zwei Möglichkeiten:

Entweder Du erhöhst die Taktfrequenz des Controllers. Der Mega32 kann mit dem internen Oszillator bis zu 8MHz - dann kämst Du schon mal bis etwa 32 kHz.

Oder Du arbeitest mit der Hardware-PWM - und um genau zu sein, im "CTC"-Modus. Das ist ein sehr feines Feature, was die Erzeugung von absolut frequenzgenauen Rechtecksignalen erlaubt, ohne dass der Controller auch nur das kleinste bisschen dafür rechnen oder arbeiten muss. Das läuft nebenbei im Hintergrund ab, während der Controller sich um andere Dinge kümmern kann.

Im Datenblatt des Mega32 gibt´s auf Seite 74 ein Bild dazu, das mehr sagt als 1000 Worte. Der Wermutstropfen ist allerdings der, dass Bascom (soviel ich weiß) den CTC-Modus nicht direkt unterstützt - man muss die beiden relevanten Register halt "von Hand" setzen. Aber das tut nicht weh - und wenn man verstanden hat was man dabei tut, macht´s sogar Spaß :-)
Was ich noch nicht verstanden habe ist folgendes:
Wenn ich eine Taktfrequenz von 1 Mhz habe, und mittels Timer 0 bei jedem Überlauf einen Interrupt Auslöse und in der Interrupt Routine eine Led toggel komm ich rechnerich auf eine Frequenz von 1960 Hz. Was auch so messbar ist.
Wenn ich aber jetzt dem Timer 0 einen Vorgabewert von 100 gebe muß ich doch in meiner Ausgangsfrequenz höher werden, das funktioniert auch errechnet mit 3225 Hz, was auch messbar ist. Wenn ich aber einen Vorgabewert von 254 gebe , errechne ich 500 khz mess aber nur ca 4 Khz.

Sauerbruch
19.12.2010, 16:34
Wenn ich aber einen Vorgabewert von 254 gebe , errechne ich 500 khz mess aber nur ca 4 Khz.

Der Knackpunkt ist der, dass mit dem Überlaufen des Timers die ISR bei weitem nicht sofort erreicht wird. Der Controller muss eine Menge an internen Registern "retten", bevor er sein Hauptprogramm verlässt und in die ISR geht. Wie for_ro und ich bereits gestern geschrieben haben, dauert es alleine schon 62 (!!) Taktzyklen, bis die ISR ausgeführt wird. Und weil diese Register nach dem Abarbeiten der ISR ale wieder zurückgeholt werden müssen, vergehen weitere 62 Taktzyklen, bevor über eine neue ISR überhaupt nur nachgedacht werden kann. Selbst wenn in der ISR (wie bei Deinem Code) fast nichts drinsteht, dauert das reine "Vorbereiten, Abarbeiten und Nacharbeiten" der ISR schon etwa 125 Taktzyklen! Die ISR kann deshalb also maximal 8000 mal pro Sekunde ausgeführt werden, was einer maximalen Frequenz von 4kHz entspricht.

Wenn Du den Timer auf 254 vorlädst, wird zwar tatsächlich 2 Takte später der Interrupt ausgelöst. Das heißt aber nicht, dass bereits 2 Taktzyklen später der nächste Interrupt erfolgen kann - weil´s eben mindestens mal 125 Zyklen dauert, bis die ISR einschließlich aller "Hausaufgaben" erledigt ist. Und vorher kann´s keine neue ISR geben...

Ist das ganze jetzt etwas klarer?

for_ro
19.12.2010, 18:24
Außerdem ist der Overflow Interrupt während der Abarbeitung der ISR abgeschaltet und wird auch beim Verlassen nicht nachgeholt. Zumindest ist so das Verhalten im Simulator, in Hardware könnte es anders aussehen.
Daher habe ich geschrieben, dass Taktwert > 195 keine Erhöhung der Frequenz mehr bringt. Dabei wird der Überlauf in der ISR oder während des Return (Rückspeichern der Register) auftreten und daher ignoriert werden. Dann muss der Timer erst wieder komplett hochzählen um dann erneut überzulaufen.

wkrug
20.12.2010, 08:16
Außerdem ist der Overflow Interrupt während der Abarbeitung der ISR abgeschaltet und wird auch beim Verlassen nicht nachgeholt. Zumindest ist so das Verhalten im Simulator, in Hardware könnte es anders aussehen.
Nicht ganz.
Es wird das Overflow Interrupt Flag gesetzt und nach der Abarbeitung sofort wieder die Interrupt Routine ausgeführt.

Ist das Flag bereits gesetzt und es tritt ein weiterer Overflow Interrupt auf wird dieser nicht registriert. Der eine bestehende aber trotzdem ausgeführt.

Ein Ausweg aus deiner Misere wäre die Interrupt Routine mit inline Assembler auszustatten und die Bascom Registerrettung für diese Interruptroutine abzuschalten.
Die benötigten Register, sowie das Status Register SREG musst Du dann aber per Hand auf den Stack schieben und hinterher wieder herunterholen.
Das sollte in 16Taktzyklen erledigt sein.

Beispiel:
PUSH r16
IN r16,SREG
PUSH r16

sbis PORTD,0 ;Ist der Port ein ?
RJMP SET ;Der Port war 0 es wird nach SET gesprungen
cbi PORTD,0 ;Der Port wird abgeschaltet
RJMP END ; Zum Ende der Routine springen

SET:
sbi PORTD.0 ;Der Port wird eingeschaltet

END:
POP r16
OUT SREG,r16
POP r16

; ENDE

Damit wird das Regiser R16 und das SREG gesichert und wären für Deinen Interruptroutine nutzbar.
Probier den Code mal aus, er toggelt den PortD.0 wenn ich da keinen Denkfehler reingebastel habe.
Die Registersicherung von BASCOM solltest Du aber für dieses kleine Programm abschalten. Die Routine sollte dann ca. 10x so schnell laufen wie dein BASCOM Pedant.
Wenn bei der Routine das SREG nicht geändert wird - Guck mal in die Code Tabelle - könnte man sich die r16 und SREG Sicherung auch noch sparen, dann gehts noch schneller.

Besserwessi
20.12.2010, 08:32
Der gezeigte ASM Code verändert das SREG nicht. Das Retten des SREG kann hier also ausnahmsweise entfallen.

Auch wenn man das SREG in R16 rettet braucht man R16 dann nicht noch einmal auf den Stack zu schieben, auch R16 wird nicht weiter genutzt.

for_ro
20.12.2010, 09:12
Außerdem ist der Overflow Interrupt während der Abarbeitung der ISR abgeschaltet und wird auch beim Verlassen nicht nachgeholt. Zumindest ist so das Verhalten im Simulator, in Hardware könnte es anders aussehen.
Nicht ganz.
Es wird das Overflow Interrupt Flag gesetzt und nach der Abarbeitung sofort wieder die Interrupt Routine ausgeführt.

Wie schon gesagt ist das nicht das Verhalten im Simulator. Du kannst deutlich sehen, dass der Timer mit einem Wert kleiner der Vorgabe die ISR verlässt.
In Hardware habe ich es mangels freiem µC noch nicht ausprobiert. Da nase aber schreibt, dass er das gleiche Verhalten beobachtet, denke ich, dass dies auch dort so ist.
Probier es mal aus.

Besserwessi
20.12.2010, 10:05
Welcher Simulator ?

Die beiden Simulatoren im AVR Studio löschen das Interruptflag bei Eintritt in die ISR, so wie die Hardware.
Wenn der Timer schon in der ISR überläuft, ist das Interrutflag schon gesetzt, und die CPU springt nur ganz kurz, für einen ASM befehl, zurück ins Hauptpropgramm. Der nächste Überlauf kommt zwar erst später, aber das gestezte Flag reicht um den Interrupt auszulösen. Irgendwann geht dann ggf. auch mal ein Interrupt verloren, weil ein Überlauf bei schon gesetztem Falg auftritt.

for_ro
20.12.2010, 10:22
Welcher Simulator ?
Bascom Programm und Bascom Simulator.


Die beiden Simulatoren im AVR Studio löschen das Interruptflag bei Eintritt in die ISR, so wie die Hardware.
Wenn der Timer schon in der ISR überläuft, ist das Interrutflag schon gesetzt, und die CPU springt nur ganz kurz, für einen ASM befehl, zurück ins Hauptpropgramm. Der nächste Überlauf kommt zwar erst später, aber das gestezte Flag reicht um den Interrupt auszulösen. Irgendwann geht dann ggf. auch mal ein Interrupt verloren, weil ein Überlauf bei schon gesetztem Falg auftritt.
Wenn dies der vom Bascom Compiler generierte Ablauf wäre, dann würden Timer Reload Werte von > 200 nicht zu niedrigeren Frequenzen führen, weil dann in jedem Fall mit dem nächsten Befehl die ISR angesprungen würde.
Ich habe mir den ASM Code jetzt nicht angesehen aber entscheidend ist ja, wann das TIFR.TOV0 Flag zurückgesetzt wird. Im Bascom Simulator wird das Flag jedenfalls erst im Return gelöscht.

mrmajo
20.12.2010, 13:52
Hallo,

wenn ich mich selbst um die Registerrettung kümmern möchte, wie finde ich herraus welche Register ich retten muss?

Klar, es kommt drauf an, was mein Program in der Interruptroutine macht...

Nur wie finde ich herraus, was Bascom mit welchen Registern macht, wenn ich z.B. eine Berechnung mache, oder Werte aus dem $Data Bereich einlese?

Wäre für Tipps dankbar.

Gruß,
Marco

for_ro
20.12.2010, 14:19
wenn ich mich selbst um die Registerrettung kümmern möchte, wie finde ich herraus welche Register ich retten muss?

Stoppe den Bascom Simulator am ISR Label.
Öffne die Register Ansicht (grüne R ganz oben)
Steppe durch die Befehle bis zum Return
Alle veränderte Register werden Rot dargestellt.
Hinzu kommt noch SREG.
In diesem Fall sähe es mit NOSAVE dann so aus:

Timer_null:
!PUSH R16
!In R16, SREG
!PUSH R16
!PUSH R24
!PUSH R25
!PUSH R26
!PUSH R27

Timer0 = Taktwert
Toggle Porta.0

!POP R27
!POP R26
!POP R25
!POP R24
!POP R16
!Out Sreg, R16
!POP R16
Return

Ergebnis: 42 Takte, also etwa 12KHz.

mrmajo
20.12.2010, 14:30
Hallo,

vielen Dank!
Das werde ich mir die Tage mal anschauen.

Gruß,
Marco

nase
22.12.2010, 19:53
Wenn ich aber einen Vorgabewert von 254 gebe , errechne ich 500 khz mess aber nur ca 4 Khz.

Der Knackpunkt ist der, dass mit dem Überlaufen des Timers die ISR bei weitem nicht sofort erreicht wird. Der Controller muss eine Menge an internen Registern "retten", bevor er sein Hauptprogramm verlässt und in die ISR geht. Wie for_ro und ich bereits gestern geschrieben haben, dauert es alleine schon 62 (!!) Taktzyklen, bis die ISR ausgeführt wird. Und weil diese Register nach dem Abarbeiten der ISR ale wieder zurückgeholt werden müssen, vergehen weitere 62 Taktzyklen, bevor über eine neue ISR überhaupt nur nachgedacht werden kann. Selbst wenn in der ISR (wie bei Deinem Code) fast nichts drinsteht, dauert das reine "Vorbereiten, Abarbeiten und Nacharbeiten" der ISR schon etwa 125 Taktzyklen! Die ISR kann deshalb also maximal 8000 mal pro Sekunde ausgeführt werden, was einer maximalen Frequenz von 4kHz entspricht.

Wenn Du den Timer auf 254 vorlädst, wird zwar tatsächlich 2 Takte später der Interrupt ausgelöst. Das heißt aber nicht, dass bereits 2 Taktzyklen später der nächste Interrupt erfolgen kann - weil´s eben mindestens mal 125 Zyklen dauert, bis die ISR einschließlich aller "Hausaufgaben" erledigt ist. Und vorher kann´s keine neue ISR geben...

Ist das ganze jetzt etwas klarer?


Ok . jetzt hab ich's verstanden. Danke für die sehr aufschlussreiche Erklärung.

Gruß Nase

nase
23.12.2010, 15:26
Wenn ich aber einen Vorgabewert von 254 gebe , errechne ich 500 khz mess aber nur ca 4 Khz.

Der Knackpunkt ist der, dass mit dem Überlaufen des Timers die ISR bei weitem nicht sofort erreicht wird. Der Controller muss eine Menge an internen Registern "retten", bevor er sein Hauptprogramm verlässt und in die ISR geht. Wie for_ro und ich bereits gestern geschrieben haben, dauert es alleine schon 62 (!!) Taktzyklen, bis die ISR ausgeführt wird. Und weil diese Register nach dem Abarbeiten der ISR ale wieder zurückgeholt werden müssen, vergehen weitere 62 Taktzyklen, bevor über eine neue ISR überhaupt nur nachgedacht werden kann. Selbst wenn in der ISR (wie bei Deinem Code) fast nichts drinsteht, dauert das reine "Vorbereiten, Abarbeiten und Nacharbeiten" der ISR schon etwa 125 Taktzyklen! Die ISR kann deshalb also maximal 8000 mal pro Sekunde ausgeführt werden, was einer maximalen Frequenz von 4kHz entspricht.

Wenn Du den Timer auf 254 vorlädst, wird zwar tatsächlich 2 Takte später der Interrupt ausgelöst. Das heißt aber nicht, dass bereits 2 Taktzyklen später der nächste Interrupt erfolgen kann - weil´s eben mindestens mal 125 Zyklen dauert, bis die ISR einschließlich aller "Hausaufgaben" erledigt ist. Und vorher kann´s keine neue ISR geben...

Ist das ganze jetzt etwas klarer?

Danke , damit hast du mir sehr geholfen, hab das Problem zwar noch nicht behoben, weiß aber jetzt , warum ich eines hatte.

Sauerbruch
24.12.2010, 08:07
Danke , damit hast du mir sehr geholfen, hab das Problem zwar noch nicht behoben, weiß aber jetzt , warum ich eines hatte.


Na - dann sollte dieser zweite Schritt doch auch möglich sein, oder :-)

Du solltest einfach mal den "CTC"-Modus ausprobieren. CTC heißt "Clear Timer on Compare" - und das bringt die Sache auf den Punkt:

Die zentrale Rolle spielt hier das "Output Compare"-Register, in das Du einen Wert zwischen 0 und 255 schreibst. Der Timer zählt nun so lange hoch, bis er den Wert dieses Registers erreicht hat. Ist "Gleichstand" erreicht, wird der Timer auf 0 gesetzt, ein Ausgang getoggelt (!) und das Spiel beginnt von vorne.

Heißt also im Klartext: Je kleiner der Wert im Output-Compare-Register, umso höher die Ausgangsfrequenz.

Beim Mega32 ist der zugehörige Ausgang B.3, und das Register heißt "OCR0" (weil´s ja für den Timer0 gilt).

Im Gegensatz zu den Interrupt-basierten Methoden passieren hier die wesentlichen Dinge (Rücksetzen des Timers und Toggeln des Ausganges) auf Hardware-Basis, und das hat zwei große Vorteile:

Erstens hält das ganze den Controller nicht von anderen Dingen ab. Er kann sich um ganz andere Sachen kümmern (z.B. Potis abfragen, LCD-Anzeigen bedienen etc., etc) - das Rechteck-Signal am OC-Ausgang wird sozusagen "von selbst" generiert.

Zweitens geschehen das Rücksetzen des Timers und das Toggeln des Ausganges tatsächlich in einem einzigen Taktzyklus - d.h. das Spiel fängt sofort wieder von vorne an. Wenn Du z.B. in das Output-Compare-Register den Wert 5 schreibst (ganz direkt, also mit der Zeile OCR0 = 5), wird der Ausgang alle 5 Takte getoggelt - uns schon bist Du bei 100 KHz! Das, was Dich bei der Interrupt-Variante ausgebremst hat, nämlich die langwierige Register-Schieberei über mehr als 120 Zyklen, entfällt im CTC-Modus.

Und mit Bascom kann man den CTC-Modus auch direkt wählen (wie ich auch erst durch diesen Thread gelernt habe)... for_ro hatte ein paar Beitrge vorher gepostet, wie man das macht.

Viel Spaß beim Ausprobieren, und halt´ uns auf dem Laufenden!

Daniel

wkrug
24.12.2010, 08:54
Wie hoch soll denn die Frequenz denn nun gehen.

Schreib bitte nicht so hoch wie möglich.
Mit einem passenden DDS Chip sind heutzutage 1GHz Sinus drin.

Bei Frequenzen höher 2kHz Sinus wär ein DDS Chip meine erste Wahl.
Ich hab mir den ATMEGA 16 DDS Generator nachgebaut und bin ziemlich enttäuscht. Das Teil soll angeblich bis 64kHz Sinus gehen, ab 2kHz schaut der Sinus aber grausam aus.
Guck mal: http://www.scienceprog.com/avr-dds-signal-generator-v20/
Der Rechteck wird dort auch mit einem PWM Mode erzeugt, dabei sind aber die Sprünge, gerade bei den hohen Frequenzen brutal ( 8MHz, 4MHz, 1MHz ).
Das geht sicher nocht etwas feiner, aber viel nicht!

Guck mal bei ELV nach dem DDS 20.
http://www.elv-downloads.de/service/manuals/DDS20/53665_DDS_20_Board_V6_2_KM.pdf
Da ist eine komplette Dokumentation inklusive Schaltplan drin.
Die Generatorschaltung schaut mir einigermassen brauchbar und durchgerechnet aus.

Den Controller und das Display könntest Du dabei gegen einen deiner Wahl austauschen.

Der verwendete DDS Chip hat eine SPI Schnittstelle, die Du ja in Hardware bei einem ATMEGA Controller dabei hast.
Zudem wären bei diesen Chips diverse Modulationsverfahren, wie FSK und PSK, relativ einfach zu implementieren.
Bei Analog Devices gibts dafür sogar einen Calculator, der einem die benötigten Daten ausrechnet.

Wobbeln wäre durch fortlaufende Änderung der Werte für die Frequenz hier auch nicht wirklich ein Problem.

Die Endstufe mit dem AD811 würde ich durch einen AD8000 ersetzen, weil günstiger und höhere Bandbreite.

Ein Highlight wär dann noch eine serielle Schnittstelle via FT232.
Über die könnte man die Einstellwerte zusätzlich noch veränderbar machen - Sprich Betrieb vom PC aus.
Oder das Teil als FSK Modulator nutzen um damit unidirektional Daten vom PC zu einem geeigneten Empfänger zu übertragen.


Ich denk mal, so kommst Du zu einem Frequenzgenerator, der seinen Namen auch verdient.

nase
24.12.2010, 15:56
Danke , damit hast du mir sehr geholfen, hab das Problem zwar noch nicht behoben, weiß aber jetzt , warum ich eines hatte.


Na - dann sollte dieser zweite Schritt doch auch möglich sein, oder :-)

Du solltest einfach mal den "CTC"-Modus ausprobieren. CTC heißt "Clear Timer on Compare" - und das bringt die Sache auf den Punkt:

Die zentrale Rolle spielt hier das "Output Compare"-Register, in das Du einen Wert zwischen 0 und 255 schreibst. Der Timer zählt nun so lange hoch, bis er den Wert dieses Registers erreicht hat. Ist "Gleichstand" erreicht, wird der Timer auf 0 gesetzt, ein Ausgang getoggelt (!) und das Spiel beginnt von vorne.

Heißt also im Klartext: Je kleiner der Wert im Output-Compare-Register, umso höher die Ausgangsfrequenz.

Beim Mega32 ist der zugehörige Ausgang B.3, und das Register heißt "OCR0" (weil´s ja für den Timer0 gilt).

Im Gegensatz zu den Interrupt-basierten Methoden passieren hier die wesentlichen Dinge (Rücksetzen des Timers und Toggeln des Ausganges) auf Hardware-Basis, und das hat zwei große Vorteile:

Erstens hält das ganze den Controller nicht von anderen Dingen ab. Er kann sich um ganz andere Sachen kümmern (z.B. Potis abfragen, LCD-Anzeigen bedienen etc., etc) - das Rechteck-Signal am OC-Ausgang wird sozusagen "von selbst" generiert.

Zweitens geschehen das Rücksetzen des Timers und das Toggeln des Ausganges tatsächlich in einem einzigen Taktzyklus - d.h. das Spiel fängt sofort wieder von vorne an. Wenn Du z.B. in das Output-Compare-Register den Wert 5 schreibst (ganz direkt, also mit der Zeile OCR0 = 5), wird der Ausgang alle 5 Takte getoggelt - uns schon bist Du bei 100 KHz! Das, was Dich bei der Interrupt-Variante ausgebremst hat, nämlich die langwierige Register-Schieberei über mehr als 120 Zyklen, entfällt im CTC-Modus.

Und mit Bascom kann man den CTC-Modus auch direkt wählen (wie ich auch erst durch diesen Thread gelernt habe)... for_ro hatte ein paar Beitrge vorher gepostet, wie man das macht.

Viel Spaß beim Ausprobieren, und halt´ uns auf dem Laufenden!

Daniel
Danke,das ist eine wunderbare Erklärung.Hab jetzt im CTC-Modus ausprobiert,und es klappt wunderbar,komme jetzt bei 1Mhz Takt auf 500Khz Ausgangsfrequenz,um jetzt einen möglichst großen Frequnzbereich abzudecken,muss ich den Vorteiler Software mäßig ändern ,dafür hatte ich jetzt aber noch nicht die Zeit.(Geschenke auspacken usw).
Dann versuche ich noch die Frequenz zu messen um sie dann auf dem Display darzustellen.

Wünsche erst einmal Schöne Weihnacht.

Sauerbruch
25.12.2010, 09:11
Hallo Nase,

schön, dass es auf Anhieb mit dem CTC-Modus geklappt hat!

An dieser Stelle sollte aber nochmal der kleine "Haken" des Verfahrens erwähnt werden, den wkrug in seinem Posting auch schon angesprochen hat:

Am oberen Ende des Frequenzbereiches (also wenn OCR0 kleine Werte hat, z.B. 0, 1 oder 2) sind die Abstände zwischen den erzeugten Frequenzen ganz schön groß. Man kann das auch ohne Frequenzzähler durchspielen, denn die Toggle-Frequenz lässt sich aus der Taktfrequenz, dem Prescaler und dem Wert im OCR-Register errechnen:

f = Taktfrequenz / (2 * Prescaler * (1 + OCR))

Für Taktfrequenz = 1 MHz, Prescaler = 1 und OCR = 0 ergibt sich eine Ausgangsfrequenz von 1 MHz / (2 * 1) = 500 KHz. Das hattest Du ja auch schon festgestellt.

Wenn Du OCR jetzt jeweils um 1 erhöhst, kommst Du auf Werte von Taktfrequenz / 4, Taktfrequenz / 6, Taktfrequenz / 8 usw.

Das heißt, Deine Frequenzen am oberen Rand des Spektrums wären 500 kHz, 250 kHz, 166 kHz, 125 kHz - und das sind ja schon ziemliche Sprünge.

Die niedrigste Frequenz wäre dann übrigens 1 MHz / (2 * (255 + 1)) = 1 MHz / 512, also knapp 2 KHz. Wenn Du niedrigere Frequenzen generieren möchtest, musst Du einen geeigneten Prescaler wählen.

nase
27.12.2010, 19:56
Hab es jetzt so hingebogen , das ich die OCR0 Werte nur im oberen Bereich nutze und dann den Prescaler softwaremäßig umstelle, so komme ich auf ein Frequenzbereich von 15 Hz bis 500 Khz. wobei die Frequenzsprünge im unteren Bereich sehr klein sind bis auf den höhreren Bereich , da bleiben sie immer noch in den von dir genannten Sprünge.

for_ro
27.12.2010, 20:18
... sind bis auf den höhreren Bereich , da bleiben sie immer noch in den von dir genannten Sprünge.
Das kannst du noch verbessern, indem du eine höhere Taktfrequenz benutzt.
Bei 16MHz hast du z.B. die Stufen 500KHz, 471KHz, 444KHz, 421KHz usw.
Bei 20MHz hast du z.B. die Stufen 500KHz, 476KHz, 455KHz, 435KHz usw.

nase
28.12.2010, 13:33
OK werd ich probieren !

wkrug
28.12.2010, 14:21
Um bei den Frequenzen weiter nach unten zu kommen, kannst Du auch den Timer 1 in diesem Modus betreiben.
Der hat dann 16Bit breite, also 65536 verschiedene Werte.

Wenn Du diesen Timer für nicht schon was anderes nutzt...

nase
30.12.2010, 16:54
Ja daran hab ich auch gedacht, aber ich möchte die erzeugte Frequenz mit dem Timer 1 als Torzeit ( 1Sekunde) messen und auf dem Display darstellen. Da tut sich allerdings schon das nächste Problem auf. Mein Takt wird am OC2 ( Portd.7)ausgegeben, den möchte ich jetzt abfragen, aber wie????

Eine Abfrage auf Pind.7 oder Portd.7 funktioniert nicht ??

Besserwessi
30.12.2010, 17:53
Wenn man die Frequenz per CTC Modus erzeugt, und keinen groben Fehler drin hat, dann stimmt das Verhältnis zur Taktfrequenz des µC. Ein nachmessen mit dem selben µC macht damit überhaupt keinen Sinn - da kommt immer der Sollwert bei raus.

wkrug
31.12.2010, 08:35
Wenn man die Frequenz per CTC Modus erzeugt, und keinen groben Fehler drin hat, dann stimmt das Verhältnis zur Taktfrequenz des µC. Ein nachmessen mit dem selben µC macht damit überhaupt keinen Sinn - da kommt immer der Sollwert bei raus.
Da hat Besserwessi natürlich recht.
Grundsätzlich gibt es bei einem AVR Controller mehrere Möglichkeiten Frequenzen zu messen.
Die den Controller am wenigsten belastende ist, die Messfrequenz auf einen Timer Clock In zu legen und damit diesen Timer + Überlaufvariable hochzuzählen.
Dann brauchst Du nur nach einen Torzeit den aktuellen Timerwert und die Hochzählvariable miteinander zu verrechnen und kommst auf Deine Frequenz.

Bei sehr niedrigen Frequenzen wird es genauer, wenn man die zu messende Frequenz auf den ICP Pin legt und einen Timer mit der ( heruntergeteilten ? ) Taktfrequenz des Controllers laufen lässt.
Die Frequenz wird dann anhand des Unterschiedes zwischen 2 ICP Interrupts ( = 1 Periode ) errechnet.
Dieses Verfahren bringt dann schnelle und genaue Ergebnisse auch noch bei Frequenzen um 1Hz.

Das Optimum dürfte eine Messroutine sein, die beide Verfahren benutzt, die ICP Interrupts aber nur bei niedrigen Frequenzen zulässt.
Wenn die Frequenzschritte, bedingt durch die Taktfrequenz dieses Timers, bei der ICP Methode über 1Hz groß werden ( bei 1sek Torzeit ) ist es günstiger die Zählmethode zu verwenden.

Die ICP Methode belastet bei höheren Frequenzen den Controller stark, da ja bei jedem 0 nach 1 Übergang ein Interrupt ausgelöst wird!

Besserwessi
31.12.2010, 09:21
@wkrug:
Die Messung der Frequenz über die ICP Funktion geht auch noch bei relativ hohen Frequenzen (bis über 100 kHz) mit mehr Auflösung als durch Zählen, wenn man sich nicht auf die Zeit zu einer Periode beschränkt, sonder ggf. mehr Perioden misst. Nur bei höheren Frequenzen ist der µC nicht schnell genug und man braucht einen Vorteiler - mit einer Stufe von 1:256 oder 512 kommt man dann auch schon bis rund 50 MHz.


Auch per Software DDS kann man einen Sauberen Sinus über 2 kHz hinkriegen, man sollte dazu aber schon einen Rekonstruktionsfilter passend zur Abtastrate haben.

nase
31.12.2010, 09:53
Hab um bei meiner Frequenzeinstellung in einen möglichst großen Bereich zu variieren per Software den Prescaler geändert.
Weil ich es aber nicht hinbekommen habe bei folgender Anweisung :
Config Timer2 = Timer , Clear Timer = 1 , Compare = Toggle , Prescale = 256
hab ich es mit der direkten Registereingabe versucht, und es hat auch geklappt.
Tccr2 = &B00011100

Allerdings hab ich unterschiede in der Ausgabefrequenz bei der Bascom Anweisung 30 bis 7810 Hz, und bei der Registereingabe 7 bis 1980 Hz.
Wo liegt der Unterschied zwischen der Bascom Anweisung und der Registereingabe ?

Sauerbruch
31.12.2010, 11:03
Eigentlich sollte es keinen Unterschied geben... was die Register anbetrifft, kocht Bascom auch nur mit Wasser :-)

Wenn ich mir allerdings das Datenblatt des ATMega32 so anschaue, resultiert aus TCCR2 = &B00011100 ein Prescaler von 64. Das würde erklären, weshalb sich die Frequenzspektren genau um den Faktor 4 unterscheiden.

Genau genommen müssten die Frequenzen unter der Bascom-Konfiguration dann zwar niedriger sein als bei direkter Registereingabe - also genau andersrum wie Du es beschrieben hast. Aber vielleicht hast Du das ja nur verwechselt...?

Wenn Du ein LCD am Start hast, kannst Du Dir übrigens genau anschauen, was Bascom mit den einzelnen Registern so alles anstellt, indem Du sie Dir direkt anzeigen lässt (z.B. LCD TCCR2). Du musst den dezimal angezeigten Inhalt nur noch nach binär umwandeln - aber das macht der Windows-Taschenrechner ganz bequem!

wkrug
31.12.2010, 11:43
Die Messung der Frequenz über die ICP Funktion geht auch noch bei relativ hohen Frequenzen (bis über 100 kHz) mit mehr Auflösung als durch Zählen
Was zu beweisen wäre.
bei 100kHz hast Du genau 160 Takte, bevor der nächste ICP Interrupt auftritt.
Allein die Registersicherung verschluckt davon schon mal ca. 70 Takte, wenn man sie nicht abschaltet.
Dazwischen ist aus den ermittelten Werten die Frequenz zu berechnen.
Ich habs schon mit einem ATMEGA 32 Controller probiert.
Ab ca. 13kHz geht es los, das das Display rumzickt, weil das Display Timing nicht mehr stimmt. Ab 2 kHz ist die Zählerei genauer als die ICP Methode.
Gut, man könnte den ICP Interrupt sperren, bis alle dazugehörigen Aufgaben erledigt sind und erst dann wieder eine neue Messung starten, aber richtig toll find ich das nicht.
Das ICP Verfahren ist ab dem Zeitpunkt nicht mehr genauer, als die Zählmethode, wenn ein Wert höher oder niedriger des Counters mehr als einen Wert in der Torzeit überschreitet.
Wenn man mehrere Perioden zur Messung heranzieht wird das zwar etwas besser, aber irgendwann ist da auch Schluß.
Wo dieser Punkt liegt ist abhängig von der Torzeit der Messung und dem Prescaler des "ICP Timers".

Aber gut, hier gehts um einen Frequenzgenerator und nicht um einen Frequenzzähler.
Ich würde aber trotzdem eine Lösung mit einem speziellen DDS Chip vorziehen.
Guck mal bei ELV unter der Baubeschreibung für den DDS 130 Funktionsgenerator.
Das Teil könnte größtenteils übernommen werden. Lediglich den Controllerteil würd ich austauschen und der Filter ist lt. Simulation auch etwas wellig.

Ein Kollege und Ich basteln zur Zeit an einem Funktionsgenerator mit AD9834 ( DDS Chip ) , AD5620 ( D/A Wandler = Amplitudenmodulation ), AD8000 ( Ausgangsverstärker ) und nem ATMEGA 644 Controller rum.

Es ist dran gedacht Dreieck, Sinus und Rechtecksignale ( TTL Pegel ) zu erzeugen inklusive Wobbeln.
Das Teil soll AM, FM, und PPM Modulation beherrschen.
Ausserdem wird eine USB Schnittstelle reinkommen, mit der man die Parameter einstellen und die Modulatoren bedienen kann.

Die maximale Trägerfrequenz wird so zwischen 20 und 30MHz betragen.
Nach unten möchten wir bis 1Hz kommen.

Zur Zeit existieren nur mal die ersten Schaltpläne, mal gucken, was daraus wird.

nase
01.01.2011, 09:33
Eigentlich sollte es keinen Unterschied geben... was die Register anbetrifft, kocht Bascom auch nur mit Wasser :-)

Wenn ich mir allerdings das Datenblatt des ATMega32 so anschaue, resultiert aus TCCR2 = &B00011100 ein Prescaler von 64. Das würde erklären, weshalb sich die Frequenzspektren genau um den Faktor 4 unterscheiden.

Genau genommen müssten die Frequenzen unter der Bascom-Konfiguration dann zwar niedriger sein als bei direkter Registereingabe - also genau andersrum wie Du es beschrieben hast. Aber vielleicht hast Du das ja nur verwechselt...?

Wenn Du ein LCD am Start hast, kannst Du Dir übrigens genau anschauen, was Bascom mit den einzelnen Registern so alles anstellt, indem Du sie Dir direkt anzeigen lässt (z.B. LCD TCCR2). Du musst den dezimal angezeigten Inhalt nur noch nach binär umwandeln - aber das macht der Windows-Taschenrechner ganz bequem!

Alles klar, hab ich wohl einen groben Fehler gemacht, falsch abgelesen !
Danke

Das mit der Displayanzeige probier ich mal aus.