PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Alternative zu "Wait"-Befehl



Torsten_G
19.06.2005, 16:08
Hallo Leute,

ich bin auf der Suche nach einer Alternativ-Programmierung zum "Wait"-Befehl. Irgendwie stehe ich da vorm Scheunentor.

Die Suchfunktion hat mir da auch nichts Hilfreiches verraten können - ehrlich gesagt, weiß ich auch gar nicht, wonach genau ich da suchen sollte...

Ein kleines Beispiel, um die Problematik zu verdeutlichen.
Mit folgendem Programmcode bekommt man ganz leicht eine Blinkfunktion an Portd.6 und Portd.7 in Abhängigkeit von Pinc.0 bzw. Pinc.1 realisiert:



Do

If Pinc.0 = 0 then

Portd.6 = 0 'LED an

Wait 5

Portd.6 = 1 'LED aus

Wait 5

end if

If Pinc.1 = 0 then

Portd.7 = 0 'LED an

Waitms 500

Portd.7 = 1 'LED aus

Waitms 500

end if

loop

end



Das blinkt zwar nett und munter vor sich hin, aber der Nachteil ist natürlich, das während der Wartezeit (Wait 5) das weitere Programm nicht durchlaufen wird. Eine Blinksequenz kann erst starten bzw. stoppen, wenn die andere Sequenz abgeschlossen ist.

Logische Folge: Die Blinker arbeiten unregelmäßig.

Die Interrupts wollte ich gerne für andere Zwecke nutzen, und außerdem muß es ja auch nicht immer ein Pin-Status als Startbedingung für die Blinker sein.

Ich würde mich freuen, wenn ihr mir ein paar Ideen liefern könntet, wie die beiden Blinker unabhängig voneinander abgearbeitet werden können.

Sorry für die Banal-Frage, aber ich bin noch ziemlicher Anfänger mit Bascom.

Ach so: Als Chip verwende ich den Mega 8

Besten Dank und viele Grüße

Torsten

linux_80
19.06.2005, 16:29
Hallo,

was ich von SPS Programmen her weiss, macht man sich einen Blinker-Merker der alleine vor sich hin irgendein Bit toggelt,
wenn man jetzt irgendwo was blinkendes braucht, einfach diesen Blinker-Merker in der Schleife mit verknüpfen.
Da der Mega8 mit mind. 8MHz läuft, sollte die Schleife oft genug durchlaufen werden um das Blinken als solches erkennen zu können.

Muster: :-)
http://users.erols.com/techserv/green-blinker.gif

PicNick
19.06.2005, 16:42
Abgesehen von Timer-Routinen, die asynchron ablaufen, kannst du noch folgendes tun
In der Main schleife eine einzigen Wait in des kleinsten sinnvollen Einheit,
bei dir, sagen wir, 100ms
Dann hast du zwei Zähler, einer zählt bis 5, blinkt, und fängt wieder bei 1 an, der andere bis 50 .


dim count1 as byte
dim count2 as byte
do
incr count1
if count1 = 5 then
count1 = 0
if Pinc.0 = 0 then
toggle Portd.6
end if
end if
incr count2
if count2 = 50 then
count2 = 0
if Pinc.1 = 0 then
toggle Portd.7
end if
end if
waitms 100
loop

rapo
19.06.2005, 17:44
Hi,
warum im "Hauptprogramm" die LED blinken lassen...?
Es geht auch mit dem 16bit timer2. Der ist so zu konfigurieren, dass alle naja, wie man es will 1,2,5.. sec. ein Interrupt ausgelöst wird. In dieser Routine wird dann der LED Port geschaltet, oder weiterer Zähler laufen lassen um Imp.-Dauer/Imp.Pause zu beeinflussen...
Bei "robotikhardware.de" gibts da eine software zum Download glaub ich rnAVr.... Die erzeugt den richtigen Programmcode, der dann sogar 1:1 übernommen werden kann...

Grüße Ralf

PicNick
19.06.2005, 17:56
@rapo: Solange du für das, was du timen willst, genug Timer bei der Hand hast, würde ich dir folgen. Aber wenn dein Board einiges zu tun hat überlegst du dir, ob du in eine blinkende Led einen Timer reinbutterst.

Torsten_G
19.06.2005, 18:22
Hallo miteinander,

vielen Dank für Eure Ideen. So banal, wie ich dachte, scheint die Problematik gar nicht zu sein...

@PicNick:
Genau, darum gings mir. Ich möchte nicht wegen so einem dummen Rumgeblinke gleich Timer, Counter und Interrupts verbraten, die brauche ich noch für andere Zwecke. Stichwort: PWM...

Die Idee mit dem Zählen gefällt mir, allerdings kommt Dein Beispiel noch nicht ohne den Wait-Befehl aus und der µC liegt satte 100ms auf der faulen Haut. Das reduziert zwar das Problem, löst es aber nicht.
Und rumgelungert wird bei mir schon gleich gar nich - in den 100ms gibt es immer noch genug zu tun für den Krabbelkäfer.

Aber das Prinzip an sich scheint mir erfolgversprechend.
Würde es funktionieren, eine Variable bei jedem Programmdurchlauf um Eins hochzuzählen und den Blinktakt mit einem Vergleich auf die Variable aufzubauen?

Das hätte zwar den Nachteil, das der Blinktakt von Przessor-Takt und Durchlaufzeit des Programms abhängt, aber damit könnte man ja möglicherweise leben?

Danke und Grüße

Torsten

linux_80
19.06.2005, 19:20
Würde es funktionieren, eine Variable bei jedem Programmdurchlauf um Eins hochzuzählen und den Blinktakt mit einem Vergleich auf die Variable aufzubauen?

Das hätte zwar den Nachteil, das der Blinktakt von Przessor-Takt und Durchlaufzeit des Programms abhängt, aber damit könnte man ja möglicherweise leben?

sag ich doch: Blinker-merker
irgendwo im Programm zählst Du jeden scheifendurchlauf, da man meistens vorher auch weiss mit wieviel Mhz der Käfer läuft, kann man auch die anzahl der schleifendurchläufe bestimmen bis der zähler überläuft, danach eine Variable die als Blinker-merker funktioniert toggeln,
wenn Du nun einen Blinker brauchst diese Variable verwenden um das Lamperl ein oder auszuschalten jenachdem ob der Blinker-merker grad an oder aus ist
:-)

PicNick
19.06.2005, 19:32
Ich mach das so, daß ich den Timer0 für eine Zeit einstelle, die für alle zeitabhängigen funktionen zweckmäßich ist. Dort findet auch diese Zählerei statt. da komm ich meistens mit 1 - 10 mS aus.
(ganz genau genommen ist da eine TImer-queue, in die irgendwelche Funktionen zur runtime dann Entries machen, mit anzahl ticks, wann ein Callback erfolgen soll. Fast wie im Windows)
Die eigentliche Hauptschleife strudelt ohne wait ihre übrigen states ab und tut halt, was sie tun soll.)
Das "Wait" in der vorgeschlagenen Form ist nur, weil ja im Beispiel sonst nix zu tun ist.

rapo
19.06.2005, 20:35
Hallo,
das mit dem Blinken und Timer "verbraten" war mir schon klar, war ja auch nur ein Gedanke...

Torsten_G
19.06.2005, 23:47
Hallo Leute,

euch allen vielen Dank, ich hab´s jetzt mal - versuchsweise - mit Zählvariablen gemacht, das wird prima reichen, um eine Status-LED flashen zu lassen.

Letztendlich ist es wohl eine Frage der Genauigkeit - wenn der Programmdurchlauf mehr Zykluszeit braucht, wird ein "Zähl-Blinker" natürlich entsprechend langsamer.

Für genaue Zeitimpulse unabhängig von der Zykluszeit geht dann wohl kein Weg an den eingebauten Timern vorbei.

Viele Grüße

Torsten

harryup
26.06.2005, 10:47
hi,
wenn in einem prog eine oder mehrere funktionen nach zeit x ausgeführt werden müssen, ist es schon sinnvoll, einen timer dafür zu verbrutzeln. der kann ja das gesamte zeitmanagement eines progs. steuern.
z.b.
timer-int alle 1/10 sec.
im int eine var um 1 hochzählen lassen.
bei var=30 (beispiel) led an
bei var=60 led wieder aus
' restliche zeitkritischen sachen oder nach umgebungsbedingungen
bei var=x und bedingung=y flag für anderes ereignis setzen
nach 'längstem ereignis' variable wieder nullen

so wird zwar ein tiomer verbraten, aber kein wait verwendet.
den int kann man schon kurz halten, der verbrät nur sehr wenig zeit.
grüssens, harry

Marco78
26.06.2005, 11:03
Sehe ich das richtig, das WAIT X einfach nur viele NOP in den AVR schreibt?
Es gibt ja Programme, in denen man nur eine gewisse Anzahl von verschiedenen Wartezeiten hat. z.B. WAITMS 150/500/1000, diese aber oft einsetzt. 150 nach Tastenabfragen, 500 und 1000 für LEDs.

Wenn meine erste Vermutung richtig ist, würde der flash ja irgendwann fast nur noch mit NOPs beschrieben sein. Wie wäre es denn, wenn man einfach wie hier jetzt drei SUBs erstellt und an den jeweiligen Stellen dort hinspringt? Sprungbefehle verbrauchen ja nicht so viele Programmzeilen wie sinnlose NOPs.
Wenn es absolut Zeitkritsche Anwendungen sind, muss man halt zuvor noch die Zeiten für die Sprünge abziehen, aber ansonsten würden ein paar µs ja nicht viel ausmachen.

PS: Mark von MCS empfiehlt an Stelle von WAIT 1 WAITMS 1000 zu verwenden, weil das weniger Programmspeicher belegt.

mohi
31.03.2012, 13:34
Hallo,

dieser Thread ist zwar schon etwas älter, aber wer weiß vielleicht antwortet ja doch jemand auf meine Frage ohne einen neuen Thread aufmachen zu müssen...

Also ich habe eigentlich ein ziemlich ähnliches Problem.
Ich hab eine Uhr gebastelt, mit einem ATmega 16 und ner LCD (1602a), ein Wecker ist auch dabei und da sind wir auch schon beim Problem:

Ich möchte die Alarmdauer festlegen, sagen wir mal erst mal auf 5 Minuten, also 300 Sekunden.

Wenn bei meiner Uhr der Alarm (Wecker) ausgelöst wird, dann wird ein Pin frei geschalten...
Ich hab erstmal ganz einfach folgenden Code genommen:

If Alarm_stat = 1 Then
Portc.1 = 1
wait 300
Portc.1 = 0
End if

Tja, wenn ich das in mein Code einbaue, dann pausiert der ATmega 300 Sekunden lang.
In dieser Zeit bleibt meine Uhr stehen, nach 300 Sekunden geht die Uhr ganz normal weiter...

Wie könnte Portc.1 für eine gewisse Zeit auf 1 setzen, ohne diesen Befehl in die Do/Loop zu schreiben?

Oder wie würdet ihr die Alarmdauer festlegen?

Viele Dank schonmal!

peterfido
31.03.2012, 14:00
Du hast doch eine Uhr drin. Demnach auch irgendwo eine Sub, welche jede Sekunde aufgerufen wird. Ich mache es immer so:

PseudoCode:


do
...
...
...
loop
end

sectic:
if alarmzeit=zeit then alarmdauer=300
if alarmdauer>=1 then
decr alarmdauer
set ausgang
else
reset ausgang
endif
return

mohi
31.03.2012, 14:23
Ja habe ich, nämich bei Config Dcf77 am Ende dieser Zeile steht bei mir Gosub = Sectic

Ist dann Alarmdauer eine neue Variable?
Anscheined schon, werds gleich mal ausprobieren...

mohi
31.03.2012, 16:28
Stimmt der folgende Code-Teil in deinen Augen?



Dim Alarmdauer As Word
Alarmdauer = 0

Config Portb.1 = Output ' Wecker
Portb.1 = 1 ' Wecker
Wecker Alias Portb.1

Do
Loop
End
Sectic:
If _hour = Alstd And _min = Almin Then Alarmdauer = 3
If Alarmdauer >= 1 Then
Decr Alarmdauer
Set Wecker
Else
Reset Wecker
End If
Return

Es funktioniert zwar, aber die Wecker-LED geht nach einer Sekunde wieder aus statt nach 3 Sekunden...

Ist es ok, when ich _hour = Alstd And _min = Almin schreibe?
Ich frag deswegen, weil in deinem Code _hour und _min in eine Variable stecken...

Aber wenigstens ist der Hinweiß, dass das ganze auch in Sectic zu realisieren ist, ziemlich cool! Vielen Dank...

peterfido
31.03.2012, 19:31
Womöglich wird die Sectic öfter in der Sekunde aufgerufen. Da in meinem Beispiel (wie auch von dir übernommen) die Alarmdauer auf 3 und dann gleich wieder auf eins weniger gesetzt werden, bleiben netto nur 2 Sekunden übrig. Du kannst es auch in der Hauptschleife erledigen, indem Du z.B. die Sekunde zwischenspeicherst und dann vergleichst. Ist diese anders, dann ist eine Sekunde vergangen. Möglichkeiten gibt es halt viele.

mohi
31.03.2012, 20:02
Möglichkeiten gibts es bestimmt viele, nur sind leider meine Möglichkeiten begrenzt, da ich Bascom-Neuling bin...

Dein Codebeispiel hat mir deshalb auch so gut gefallen, weil ich es verstanden habe :-)

Hab eben die Alarmdauer auf 10 erhöht, leider bleibt die Alarm-LED trotzdem nur eine Sekunde an.
In dem Sectic-Bereich, also zwsichen Sectic und Return, ist nur eine Flagsetzung...

Lösche ich folgenden Code, bleibt die Alarm_LED nonstop an...


If _hour = Alstd And _min = Almin Then Alarmdauer = 10
If Alarmdauer >= 1 Then
Decr Alarmdauer
Set Wecker
Else
Reset Wecker
End If

mohi
31.03.2012, 20:28
Sag mal, wie meinst du das mit Sekunde zwischenspeichern?
Wie funktioniert die Alarmdauer-Regelung in der HAuptschleife?

peterfido
31.03.2012, 21:40
Scheint, als ob irgendwas anderes passt nicht. Für eine bessere Aussage bräuchte ich mehr Code. Da du nur die Stunde und Minute vergleichst, müsste die ganze Minute über jede Sekunde Alarmdauer auf 3 gesetzt werden.

Die Sekunde zwischenspeichern geht ganz einfach:



dim sekalt as byte
...
...
do
if sekalt<>_sec then
sekalt=_sec
gosub sekuendlich
end if

loop
end

sekuendlich:
'hier der Code rein, welcher nach jeder neuen Sekunde ausgeführt werden soll. z.B.
gosub Uhranzeigen
gosub Alarme
gosub Menuetimer
gosub beleuchtungstimer
...
...
...
return

mohi
31.03.2012, 22:21
Ja ich glaube dass das daran liegt, das in der Hauptschleife bereits der Wecker-Port (also die Weck-LED) genutzt wird...

Ich schick dir gleich mal ne PN.

mohi
01.04.2012, 12:27
Ist nicht mehr nötig. Ich habs hinbekommen und zwar hab ich in der Sectic folgendes geschrieben:


Dim Alarm_dauer As Word
Alarm_dauer = 0

Do
.
.
.
Loop
End

Sectic:
If PortB.1 = 1 Then Alarm_dauer = Alarm_dauer + 1
If Alarm_dauer = 5 Then ' Alarm dauert 5 Sekunden
Reset PortB.1
End If
Return

Vielen Dank für deinen Tip und schönen Sonntag dir...