PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : 100us an/aus signal?



BloodyNap
20.02.2005, 19:35
wie kann ich mit einem timer an einem ausgang nen signal mit 100us an und 100us aus herstellen?

hab das so gemacht ( sind aber keine 100us irgendwie ;) ):
Ddrb.2 = 1
Portb.2 = 0

Xport Alias Portb.2

Dim Tcounter As Byte
Tcounter = 0

On Timer0 Ontimer0
Config Timer0 = Timer , Prescale = 8

...

Ontimer0:
Tcounter = Tcounter + 1
If Tcounter = 46 Then
If Xport = 0 Then
Xport = 1
Else
Xport = 0
end if
end if
return

mein gedankengang war dabei:
ich habe einen quarz mit 3686400hz
takt = 3686400/8 = 460800

alle 2.17us löst der Ontimer0 aus
da ich aber nur eine genauigkeit von 100us brauche das ganze * 46


gedanken fehler? rechenfehler? oder geht das so nicht ?

mfg

RCO
20.02.2005, 20:03
alle 2.17us löst der Ontimer0 aus
da ich aber nur eine genauigkeit von 100us brauche das ganze * 46

Müsste Funktionieren, ABER:

Du musst Tcounter wieder auf 0 setzen, wenn er bei 46 war!
Hast du das Signal mal gemessen, ich würde vermuten, dass es bei ca 557 uS liegt. Vielleicht ist ja die Zeit 2,71 uS an, der Rest aus zu kurz? Was willst du für einen Duty cycle. Warum nicht 50:50?

If Tcounter >= 23 then
xport = 1
else
xport = 0
end if

if Tcouner = 46 then
Tcounter = 0
end if

MFG Moritz

BloodyNap
20.02.2005, 20:20
jojo das mit dem auf 0 setzten habe ich ... (nur vergessen zu posten)

zum cycle:
emm ich möchte das das deingen 100us AN macht und dann nach 100us AUS...

aber wieso sollte das signal bei 557us liegen, wenn ich das so mache?

will damit nen fahrtenregler ansprechen...

ich poste einfach mal das komplette dingen...


$regfile = "2313def.dat"
$crystal = 3686400
$baud = 9600

Ddrb.2 = 1 'X
Ddrb.3 = 1 'Y
Ddrb.4 = 1 'Z

Portb.2 = 0
Portb.3 = 0
Portb.4 = 0

Xport Alias Portb.2
Yport Alias Portb.3
Zport Alias Portb.4


Dim Tcounter As Byte

Dim Xcounter As Byte
Dim Ycounter As Byte
Dim Zcounter As Byte

Dim Ximpulse As Byte
Dim Yimpulse As Byte
Dim Zimpulse As Byte
Dim Intervallength As Byte

Tcounter = 0

Xcounter = 0
Ycounter = 0
Zcounter = 0

Ximpulse = 10 '=>1000usek
Yimpulse = 10 '=>1000usek
Zimpulse = 10 '=>1000usek
Intervallength = 20 '=>2000usek

On Timer0 Ontimer0
Config Timer0 = Timer , Prescale = 8 'Takt: Quarz/8 => 460800 => Tick alle 2.17usek

Enable Timer0
Enable Interrupts 'Interrupts global



'Hauptprogramm
Do
Loop

End

'Ontimer0
Ontimer0:
Tcounter = Tcounter + 1
If Tcounter = 46 Then ' Tick alle 100usek
Xcounter = Xcounter + 1
Ycounter = Ycounter + 1
Zcounter = Zcounter + 1

If Xcounter <= Ximpulse Then
Xport = 1
End If
If Xcounter > Ximpulse Then
Xport = 0
End If
If Xcounter = Intervallength Then
Xcounter = 0
End If

If Ycounter <= Yimpulse Then
Yport = 1
End If
If Ycounter > Yimpulse Then
Yport = 0
End If
If Ycounter = Intervallength Then
Ycounter = 0
End If

If Zcounter <= Zimpulse Then
Zport = 1
End If
If Zcounter > Zimpulse Then
Zport = 0
End If
If Zcounter = Intervallength Then
Zcounter = 0
End If

Tcounter = 0
End If
Return


nach dem dingen sollte das signal 1000usek AN/1000usek AUS sein oder?
an meinem led sieht das aber eher nach 1sek AN/1sek AUS aus... (hab kein oziloskop womit ich das testen könnte...)

RCO
20.02.2005, 20:40
zum cycle:
emm ich möchte das das deingen 100us AN macht und dann nach 100us AUS...

Dein Interrupt erzeugt alle 2.17 uS einen Interrupt.
Dann wird Tcounter 1 hochgezählt. Bis jetzt ist xport nur im Falle tcounter = 46 an. Wenn es kleiner oder größer ist aus. Du erzeugst aleo keinen Wechsel damit! Du hast einen Cycle (wenn wir mal davon ausgehen, dass es nut von 0 bis 46 geht) von 47 zu 1!

Und 2. dein Script erzeugt (wemm es mur von 0 bis 46 geht) alle 100 us 2 Wechsel und nciht nur einen. Bei dir wäre 01 100us lang. Gewünscht ist aber 01 = 200us (etwas blöd ausgedrückt).

Verstanden?!

Mach es so:
Tcounter = Tcounter + 1
If Tcounter = 46 then
toggle xport
Tcounter = 0
End if

MFG Moritz

BloodyNap
20.02.2005, 20:52
öm
und was ist wenn ich nu eine längeres AN als Aus haben möchte?

RCO
20.02.2005, 23:37
Ähm, mir fällt gerade was auf, du hast die Frequenz nicht zufällig mal gemessen? Du hast bei deinem Code was ganz wesentliches übersehen!


Takt: Quarz/8 => 460800 => Tick alle 2.17usek

Das stimmt leider überhaupt nicht. Alle 2.17 uS wird der Timer0 um ein erhöht. Er läuft aber erst bei 256 über und löst erst dann einen Interrupt aus! Ich hab mich leider vorher immer auf die Angabe 2,17 uS verlassen.
OnTimer wird also nur alle 556 uS ausgelöst!
Du musst vermutlich nen kleineres Prescaler nehmen (1).
Und den Timer vorladen.
Leider ist es sehr schwer da, der Timer nach 3,6864 Takten überlaufen müsste, damit er jede uS überläuft.
Wenn wir uns die Zahl mal anschauen, fällt uns was aus! Das ist im Grunde die Quarzfrequenz/1 Mio
Könntst du also ein anderen Quarz nehmen?
4 Mhz oder 8 wären gut. Da das Timing sehr viele Resourcen frisst, wäre ein 16 Mhz Qurz natürlich am besten.


Fragen?!

MFG Moritz

Werner_Just
21.02.2005, 08:28
Hallo,

warum das ganze im Hauptprogramm laufen lassen?

Falls der verwendete AVR eine Time-Compare-Unit besitzt (z.B. in Timer2)...
46 ins Timer-Compare Register laden.

Config Timer2 = Timer, Prescale = 8, Compare = Toggle(*), Clear Timer = 1
OCR2 = 46
(*) toggelt OC2-Pin, andere Pins im OC-Int toggeln.


Falls nicht, Timer mit 256-46 voreinstellen und den Portpin in der Overflow-Interruptroutine toggeln.

On Timer0 OVF_Int
Config Timer0 = Timer, Prescale = 8
Timer0 = 210
...

OVF_Int:
Timer0 = 210
Toggle PortX.Y
Return


Ist nur eine Überlegung, getestet hab ich das nicht.

Ciao,
Werner

RCO
21.02.2005, 09:22
Beim ersten Beispiel blick ich nciht ganz durch, aber as 2. ist klar.
Es sind aber halt schon Fehler im Ansatz. Du hast es jetzt richtig gemacht aber wir wollen ja noch versuchen den cycle einzustellen. Dafür wäre vermutlich ein kleinere Prescaler und ein anderes Quarz sinnvoll. Natürlich nur, wenn das ganze so fein eingestellt werden soll.

MFG Moritz

Werner_Just
21.02.2005, 10:20
Beim ersten Beispiel bin ich mir auch nicht sicher. Speziell ob Clear Timer = 1 wirklich den Timer beim Aufruf des Compare Interupt löscht.

Ansonsten nutzt das 2.Beispiel einfach die Möglichkeit der Timer 1 & 2 bei einem beliebigen Zählerstand einen Interupt auszulösen. Timer 0 besitzt diese Funktion leider nicht.

Ciao,
Werner

P.S. Der in BASCON integrierte Simulator scheint bei den neuen AVRs nicht ganz fehlerfrei zu sein. Wenn interne Register der Timer nicht oder nicht wie erwartet gesetzt werden, lohnt es sich das Programm noch mal im AVR Studio zu testen. Z.B. die CAPTURE Funktion von Timer 1 funktionierte bei mir im BASCON Simulator nicht. Simulier ich den erzeugten Code im Studio klappt es, und was wichtiger ist auch auf dem Zielsystem funktioniert es.

BloodyNap
21.02.2005, 14:28
ich kann maximal nen 10mhz quarz nehmen weil der at90s2313 nur max 10mhz kann... aber ich glaube das wäre schon eine verbesserung oder?

RCO
21.02.2005, 15:11
Es geht vor Allem darum eine relativ gerade Zahl zu habe.
Wenn du halt eine Einheit auf 1 uS genau bestimmen willst, dann muss der Timer nach 256-Quarzfrequen/1Mio überlaufen. Bei einer Quarzfrequenz x,xxx ist das schwer, weil es natürlich keine 0,xxx langen Takte gibt.
Je nachdem wie genau die Skalierung des cycles sein soll, also 1 uS oder 2 oder 5 bleibt halt mehr oder weniger Zeit für andere und diese Funktion, deshalb ist im Grunde zu einer hohen Qurarfrequenz zu raten. Wenn du Beispielsweise eine Skallierung von 5 nimmst, hast du bei 10 Mhz 50 Takte bis zum nächsten Interrupt, dass ist nicht gerade viel!

Wie genau darf/muss es sein, reichen auch 10 uS?

MFG Moritz

Werner_Just
21.02.2005, 16:53
Hallo Moritz,

> hast du bei 10 Mhz 50 Takte bis zum nächsten Interrupt
der Quarz und der Vorteiler bestimmen die Zeitbasis und damit die Genauigkeit. Warum sollte man dann wieder eine 2. Zeitbasis erzeugen? Das treibt nur unnötig die Genauigkeit in den Keller.

10 MHz Takt, Prescale = 1 -> Zeitbasis der Timers = 0.1µs
8MHz, Prescale=8 -> 1µs, usw.

Ein 8bit Zähler läuft alle 256 Takte über (8Bit Zähler) und jede zu erzeugende Zeit lässt sich als x-mal 256 Takte + y Takte darstellen. Man Zählt einfach die Anzahl der Timerüberläufe und hängt die restlichen Takte dran.

Egal welche Zeit erzeugt werden soll, die Genauigkeit ist immer gleich.

Alternativ nimmt man den 16bit Timer. Dann hat man zwischen zwei Überläufen 2^16 Takte Zeit und kann auch das "Anhängen" der restlichen Takte elegant die AVR-Hardware machen lassen.

Ciao,
Werner

BloodyNap
21.02.2005, 17:13
jop reicht vollkommen...
glaub nicht das der fahrtenregler da so sensibel ist

RCO
21.02.2005, 19:36
der Quarz und der Vorteiler bestimmen die Zeitbasis und damit die Genauigkeit. Warum sollte man dann wieder eine 2. Zeitbasis erzeugen? Das treibt nur unnötig die Genauigkeit in den Keller.


Ich glaube, da hast du mich falsch verstanden.
Ob der Timer jetzt nach einem Count überläuft oder nach 8 oder 10 oder 50 ist doch egal.



10 MHz Takt, Prescale = 1 -> Zeitbasis der Timers = 0.1µs
8MHz, Prescale=8 -> 1µs, usw.

Ja, nur wenn ich das richtig sehe, hat der Prescaler genau 8 Takte Zeit um etwas auszuführen, das ist wenig. Obwohl, vielleicht reicht es.

Ich würde dass dann schon so machen, dass ich den Timer mit dem entsprechenden Wert vorlade, so dass ich zusammen die 200us voll habe.
Und nicht wie BloodyNap das gemacht hat erst in der Interruptroutine addieren und auswerten. Gut wäre dann zu wissen, wie lang genau die Berechnung für den nächsten Interrupt dauert.


Alternativ nimmt man den 16bit Timer. Dann hat man zwischen zwei Überläufen 2^16 Takte Zeit und kann auch das "Anhängen" der restlichen Takte elegant die AVR-Hardware machen lassen.

Das hab ich nicht verstanden, man hat doch nciht mehr Zeit nur weil man einen 16 Bit Timer nimmt!?

MFG Moritz

BloodyNap
22.02.2005, 19:04
so hab nu nen 10Mhz quarz eingebaut...

hab mein prescale auf 1 gemacht und stelle den timer so vor das er alle 25uS aus gelöst wird...

überprüft mal bitte ob der gedankengang richtig ist:
10.000.000 / 1(prescale) / 255(timerüberlauf) = 0.000.025.5 => 25,5uS
ist ne ungrade zahl deswegen stellt ich den timer auf 5 vor:
10.000.000 / 1(prescale) / 250(timerüberlauf) = 0.000.025.0 => 25uS
da ich keine höhere genauigkeit brauche müsste das doch klappen oder?

RCO
23.02.2005, 09:33
Sieht gut aus, ich galube allerdings, dass der Timer erst bei 256 überläuft, bei 255 ist er ja "nur voll".

MFG Moritz

Werner_Just
23.02.2005, 20:33
Hallo,

warum den Timer nach jedem Overflow neu stellen? Lasst den Timer laufen einfach laufen!

Anstatt 4x (256 - 6) zu zählen, lass den Zähler (1x 232) + (3x 256) zählen.

Stellt den Timer einmal vor und zählt in der OVF_Int Routine nur die Anzahl der Interrupts, ohne der Timer neu zu starten. Den Timer neu stellen muß man nur wenn die gewünschte Zeit erreicht wurde.


BSP:
100µs, cnt = 1000, HEX = 3E8
FF - E8 = Voreinstellwert, nach 232 Takten erfolgt er erste Oberflow. Danach erfolgen die Overflows alle 256 Takte.
3 = Anzahl 256er Overflows

Der 4. Overflow entsteht nach genau 1000 Takten = 100µs.

314 µs, HEX = C44
FF - 44 = BB = Voreinstellwert
C = Anzahl 256er Overflows

Der 13. Overflow entsteht nach genau 3140 Takten = 314 µs

Keine Umrechnungen, keine Ungenauigkeiten da der Timer weiterläuft, jede beliebige Zeit einstellbar.

Naja, das mit den Ungenauigkeiten stimmt nicht ganz. Beim Zählerstart muß (sollte) man die Zeit mit einrechnen, die man zum Voreinstellen und Zähler starten braucht. Aber das muß nur einmal sein und nicht bei jeden Overflow.

> Das hab ich nicht verstanden, man hat doch nciht mehr Zeit nur weil man einen 16 Bit Timer nimmt!?
Doch, zumindest bei langen Zeiten. Der Timer erfordert nicht alle 256 Takte die Aufmerksamkeit des Programms, sondern nur alle 65356 Takte.

Ciao,
Werner

RCO
24.02.2005, 09:45
314 µs, HEX = C44
FF - 44 = BB = Voreinstellwert
C = Anzahl 256er Overflows

Der 13. Overflow entsteht nach genau 3140 Takten = 314 µs

Worauf willst du hinaus? Was meinst du damit?

Es geht ja darum, dass man den Cycle noch einstellen können soll.
Eine Stufe alle 25 uS:
0 an 200 aus
25 an 175 aus
50 an...

Dazu braucht man dann schon alle 25 uS einen Interrupt, wo dann auch ein 16-bitter nix bringt.
Was meisnt du, wieviele Takte braucht man unter Bascom um die Routine aufzurufen und nen neuen Timerwert zu setzen? Ich hab mal gehört, das Bascom für eine Anweisung unter ASM, also einen Takt, 3 Takte braucht.
Stimmt das, kann man das überhaupt so sagen?

MFG moritz

BloodyNap
24.02.2005, 13:10
kann ich mir nicht vorstellen...
wenn dann ist das ein durschnittswert, weil für z.B. varX = 5 braucht ASM auch nur einen befehl... es wird auch sicherlicht andere anweisungen wie Schleifen geben, die wesentlich mehr als 3 takte unter ASM brauchen...

RCO
24.02.2005, 13:33
wenn dann ist das ein durschnittswert, weil für z.B. varX = 5 braucht ASM auch nur einen befehl

Befehl? Du meinst vermutlich Takt.
Du hast mich missverstande, ich muss aber zugeben, dass der Satz auch echt besch... war. Also ASM braucht für die meisten Anweisungen einen Takt, für manche mehr. Bascom braucht meines Wissens nach länger. Ich glaube mal gehört zu haben ca. 3 mal länger. Es wäre natürlich interessant, wie lang es exakt ist, und wie läange der Aufruf der Interruptroutine (warum heißt die IRQ?) braucht.

MFG moritz

Werner_Just
24.02.2005, 14:51
Ich verstehe es einfach nicht...


Es geht ja darum, dass man den Cycle noch einstellen können soll.
Eine Stufe alle 25 uS:
0 an 200 aus
25 an 175 aus
50 an...
Warum braucht man um den Cycle einstellen zu können eine Stufe?
Wo ist der Vorteil einer solchen Einteilung in Stufen?


Dazu braucht man dann schon alle 25 uS einen Interrupt...
Warum braucht man dafür alle 25 µs einen Interrupt. Damit man eine Stufe von 25 µs hat, OK!
Aber warum im Schritten von 0/200;25/175;....;175/25;200/0 arbeiten, wenn man ohne größeren Aufwand auch in Stufen von 1µs oder 0.1µs arbeiten kann.



Was meisnt du, wieviele Takte braucht man unter Bascom um die Routine aufzurufen und nen neuen Timerwert zu setzen? Ich hab mal gehört, das Bascom für eine Anweisung unter ASM, also einen Takt, 3 Takte braucht.

Keine Ahnung. Viele werden es nicht sein.
LDI Rx, Konst braucht einen Takt, da wird BASCOM nicht wesentlich mehr brauchen.


Stimmt das, kann man das überhaupt so sagen?

Das kommt vermutlich ganz auf den Befehl an und in welchem Kontext er verwendet wird. Wenns stimmt, das BASCOM Code im Durchschnitt 3mal langsamer ist als reiner Assembler Code, dann ist das imo ein guter Wert.

Ciao,
Werner