Hallo zusammen,
dies dürfte mal wieder eine banale Sache sein, da das www hierzu wenig
hergibt. Als ich endlich dachte gefunden zu haben was ich suche, wurde
ich doch wieder enttäuscht.
Beitrag "hysterese assembler"
Wenn hier z.B. der Wert zwischen 60 und 61 springt, wird auch immer
zwischen Aktion 1 und Aktion 2 gesprungen. Ich hätte jedoch gern, das
bei
>= 60 Aktion 1 ausgeführt wird. Bei erreichen von>=100 Aktion 2 und, wenn der Wert <60 wird soll erst Aktion 1 wieder erfolgen.
Analog hierzu soll bei
>=140 Aktion 3 erfolgen und wenn der Wert <100 wird soll erst Aktion 2 wieder
stattfinden.
Hoffe Ihr versteht mich. Ich schaffe es leider irgendwie nicht, dieses
Problem in Assembler zu lösen. Einen Programmauszug habe ich mal
angehängt.
Bernd_Stein
Der springende Punkt in einer Hysterese besteht darin, dass es einen
Bereich gibt, in dem du einfach nichts tust.
if( Wert > 100 )
Aktion 2, zb. Heizung/Strom abschalten, LED einschalten
if( Wert < 60 )
Aktion 1 zb. Heizung/Strom einschalten, LED abschalten
Bewegt sich der Wert im Bereich 60 bis 100, veränderst du den Zustand
ganz einfach nicht. Ob dann eingeschaltet ist oder nicht hängt davon ab,
auf welchem Weg dieser Zwischenbereich betreten wurde. Kommst du von
unten (also aus dem Bereich kleiner 60), bleibt auch weiterhin die
Heizung eingeschaltet. Kommst du von oben (also aus dem Bereich größer
100), bleibt sie auch weiterhin ausgeschaltet. Erst wenn der Wert dann
wieder unter 60 fällt, wird die Heizung wieder eingeschaltet.
Bei LED oder generell Portpins, die sich selbst ihren Zustand merken,
bedeutet das ganz einfach: nichts tun - nichts verändern. Wenn es darum
geht, eine Funktion entsprechend aufzurufen muss man noch eine
Zustandsvariable mit hinzunehmen, die sich das merkt.
LDS Reg_A, Wert ; Variable, in der ein Wert von 0-255 stehen kann
3
CPI Reg_A, 61 ; Bereich 0 - 60
4
BRLO Set_Aktion_1
5
CPI Reg_A, 151 ; Bereich 61 - 150
6
BRLO Set_Aktion_2
7
;---------- ab hier Bereich von 151 bis 255 ----------
8
LDS Reg_A, Aktion_Flag
9
ORI Reg_A, 0b00000100 ; Bit für Aktion 3
10
RJMP End_Bereichswahl
11
Set_Aktion_1:
12
LDS Reg_A, Aktion_Flag
13
ORI Reg_A, 0b00000001 ; Bit für Aktion 1
14
RJMP End_Bereichswahl
15
Set_Aktion_2:
16
LDS Reg_A, Aktion_Flag
17
ORI Reg_A, 0b00000010 ; Bit für Aktion 2
18
19
End_Bereichswahl:
20
STS Aktion_Flag, Reg_A
21
RET
Diese Aktionsflags behandelst du in aufgerufenben Unterprogrammen. Diese
sind in deiner Programmschleife untergebracht.
1
Loop_Main:
2
....
3
....
4
RCALL Aktion_1
5
RCALL Aktion_2
6
RCALL Aktion_3
7
...
8
....
9
RJMP Loop_Main
Und in den Unterprogrammen erledigst du den Job:
1
Aktion_1:
2
LDS Reg_A, Aktion_Flag
3
ANDI Reg_A, 0b00000001 ; Bit für Aktion 1 gesetzt ?
4
BREQ End_Aktion_1 ; Bit ist nicht gesetzt, Ergebnis ist 0
5
LDS Reg_A, Aktion_Flag
6
ANDI Reg_A, 0b11111110 ; Bit für Aktion 1 Quittieren
7
STS Aktion_Flag, Reg_A
8
.... ; Aktion 1 durchführen
9
....
10
End_Aktion_1:
11
RET
Ich hab das hier mal mit Flags dargestellt, natürlich geht's auch ohne.
Allerdings hab ich die Erfahrung gemacht, das gerade bei umfangreichen
Assemblerprogrammen der Aufbau über eine Struktur und die Abarbeitung in
abhängigkeit von Flags vieles einfacher macht und der Übersichtlichkeit
dient. Solche Flags lassen sich auch z.B. in der Timer-ISR erzeugen. Die
Bearbeitung im HAuptprogramm läuft dann analog ab.
Gruß oldmax
Hi
Sorry, hab vergessen, des Unterprogramm Bereichswahl muß natürlich vor
den Aktionsaufrufen in der Loop_Main stehen. Im Übrigen hab ich grad mal
dein TXT-Progrramm überflogen.... na ja, soviel zur
Übersichtlichkeit.....
Gruß oldmax
Oldmax schrieb:> ...> Im Übrigen hab ich grad mal> dein TXT-Progrramm überflogen.... na ja, soviel zur> Übersichtlichkeit.....> Gruß oldmax>
Vielen Dank.
Dein Programm sieht sehr gut durchdacht bzw. strukturiert aus.
Werde mir jetzt mal die Mühe machen es im Detail zu verstehen und den
Stil in meinen Programmen zu übernehmen.
Hast Du das Programmieren richtig gelernt oder Dir selber beigebracht ?
Bernd_Stein
Stephan schrieb:> Der kann Größer, Gleich und Kleiner in einem Befehl hi hi
Kann doch der AVR mit CP auch. Musst halt sinnvoll auswerten.
Karl Heinz Buchegger schrieb:> Kommst du von> unten (also aus dem Bereich kleiner 60), bleibt auch weiterhin die> Heizung eingeschaltet. Kommst du von oben... usw
Aber darauf achten, am Anfang einen sinnvollen Zustand zu setzen, falls
der Wert von Anfang an im Bereich "tue nichts" liegt.
[avrasm]
Bereichswahl:
LDS Reg_A, Wert ; Variable, in der ein Wert von 0-255 stehen
kann
CPI Reg_A, 61 ; Bereich 0 - 60
BRLO Set_Aktion_1
CPI Reg_A, 151 ; Bereich 61 - 99 nix tun
BRLO Set_Aktion_0
CPI Reg_A, 151 ; Bereich 100 - 150 Aktion 2
BRLO Set_Aktion_2
[\avrasm]
...
Set_Aktion_0:
nop
ret
> LDS Reg_A, Wert ; Variable, in der ein Wert von 0-255 stehen
3
> kann
4
> CPI Reg_A, 61 ; Bereich 0 - 60
5
> BRLO Set_Aktion_1
6
> CPI Reg_A, 141 ; Bereich 61 - 140
7
> BRLO Set_Aktion_2
8
>
>> Bei einem Wertependler zwischen 60 und 61 findet da doch IMHO wieder ein> ständiger Wechsel zwischen Aktion_1 und Aktion_2 statt. Oder irre ich?>
Nachdem ich das Programm studiert habe, sehe ich auch einen ständigen
Wechsel zwischen Aktion_1 und Aktion_2 bei einem Wertependler zwischen
60 und 61. Dies wollte ich ja unbedingt vermeiden.
Bernd_Stein
Nun sollte jedoch bei >=100 die Aktion_2 zum tragen kommen. Das sehe ich
aber nicht und wenn ich mir das denken soll kommt nur Mist dabei raus,
weil ja die nächste Stufe >=140 die Aktion_3 einschalten soll und diese
so lange aktiv sein soll bis der Wert 100 unterschritten wird.
Hier soll dann wieder Aktion_2 zum Einsatz kommen bzw. Aktion_1 falls
der Wert 60 unterschreiten sollte.
Bernd Stein schrieb:> Ihr macht es einem wirklich nicht leicht.
Warum?
Ich hab dir doch schon geschrieben, wie man eine Hysterese macht.
Umsetzen und erweitern auf deine 3 Schaltbereiche musst du es selber.
Und nein, IMHO kannst du die Hysteresebereiche nicht direkt aneinander
angrenzen lassen. Du brauchst einen Bereich (auch wenn er nur sehr klein
ist) (*), in dem ganz sicher Aktion 2 die richtige Wahl ist und der bei
Veränderung des Messwertes ganz sicher auch mal vom Messwert angenommen
wird, damit es nicht zum Durchschalten von einem Hysteresebereich in den
anderen kommen kann.
Du hast 5 Bereiche
Bei Messwerten im **** Bereich, gilt die jeweils darunter angegebene
Operation. Ist der Messwert im ..... Bereich, machst du einfach gar
nichts.
Die entsprechenden Bedingungen darfst du jetzt selber in Assembler
ausformulieren.
Als C-Spezi hätt ich einfach geschrieben
1
if(ADC_Value<60)
2
Aktion_1();
3
elseif(ADC_Value>100&&ADC_Value<110)
4
Aktion_2();
5
elseif(ADC_Value>140)
6
Aktion_3();
(*) oder alternativ ein paar Flags, die eine Aussage darüber erlauben,
wie der jeweilige Hysteresebereich betreten wurde und im Prinzip eine
kleine Statemaschine dazu.
Eine weitere Möglichkeit besteht darin, einfach nach jeder Prüfung den
Umschaltpunkt entsprechend zu setzen:
1
ifInputpegel<Threshold
2
{
3
Output=L;
4
Threshold=THRESHOLD_H
5
}
6
else
7
{
8
Output=H;
9
Threshold=THRESHOLD_L
10
}
Vor der ersten Verwendung dieser Funktion muss man der
Umschaltpunkt-Variablen "Threshold" einen Wert zuweisen. Es bietet sich
an, dafür den arithmetischen Mittelwert von THRESHOLD_H und THRESHOLD_L
zu nehmen:
Karl Heinz Buchegger schrieb:> (*) oder alternativ ein paar Flags, die eine Aussage darüber erlauben,> wie der jeweilige Hysteresebereich betreten wurde und im Prinzip eine> kleine Statemaschine dazu.
Hmmm.
Du hast einen Wert (zb in einem Register) der dir sagt, welche Aktion
gerade auszuführen ist. Nennen wir ihn DO_ACTION.
eine 1 sagt dir: Aktion 1 ist auszuführen
eine 2 sagt dir: Aktion 2 ist auszuführen
eine 3 sagt dir: Aktion 3 ist auszuführen
(Die genauen Zahlen spielen keine Rolle, weil man sie sowieso hinter
Konstanten Bezeichnungen versteckt)
Pseudocode:
Karl Heinz Buchegger schrieb:> Bernd Stein schrieb:>> Ihr macht es einem wirklich nicht leicht.>> Warum?>> ...>
Auch darum, weil die Frage lautete :
Wie programmiert man eine Hysterese in Assembler ?
Und nun erhalte ich immer mehr so etwas :
>> Als C-Spezi hätt ich einfach geschrieben>
1
>if(ADC_Value<60)
2
>Aktion_1();
3
>elseif(ADC_Value>100&&ADC_Value<110)
4
>Aktion_2();
5
>elseif(ADC_Value>140)
6
>Aktion_3();
7
>
>
Nun die Sache scheint doch nicht so banal in Assembler zu sein.
Aber eine Hysterese in Assembler zu programmieren ist doch mit
sicherheit Standard. Man muß doch nicht immer das Rad neu erfinden.
Und Ihr wollt das ich das tue, deshalb macht Ihr es mir nicht leicht.
Bernd_Stein
Bernd Stein schrieb:> Wie programmiert man eine Hysterese in Assembler ?>> Und nun erhalte ich immer mehr so etwas :>>>> Als C-Spezi hätt ich einfach geschrieben>>
1
>>if(ADC_Value<60)
2
>>Aktion_1();
3
>>elseif(ADC_Value>100&&ADC_Value<110)
4
>>Aktion_2();
5
>>elseif(ADC_Value>140)
6
>>Aktion_3();
7
>>
>>> Nun die Sache scheint doch nicht so banal in Assembler zu sein.> Aber eine Hysterese in Assembler zu programmieren ist doch mit> sicherheit Standard.
Du wirst das ja doch wohl lesen können? oder nicht?
Oder soll ich schreiben
[pseudocode]
wenn der Messwert kleiner 60 ist
dann führe Aktion 1 aus
andernfalls wenn der Messwert größer 100 UND kleiner 110 ist
dann führe Aktion 2 aus
andernfalls wenn der Messwert größer 140 ist
dann führe Aktion 3 aus
[/pseudocode]
Auch wenn man kein C kann, sollte das eigentlich leicht lesbar sein.
Also nicht einfach gleich bei jeder Programmiersprache, die nicht mit
der von dir benutzten identisch ist, sofort abschalten, sondern das
Progammstück studieren. Kein Mensch verlangt von dir in C zu schreiben.
Aber lesen wirst du das ja wohl können. Da kommt nix von dem ganzen
C-spezifischen Kram vor, der ein Lesen für den Unkundigen erschwert.
> Man muß doch nicht immer das Rad neu erfinden.> Und Ihr wollt das ich das tue, deshalb macht Ihr es mir nicht leicht.
Nein.
Wir wollen nicht das du das Rad erfindest. Aber DU sollst den
Assemblercode selber schreiben. Wir liefern dir nur die Idee, den
Algorithmus. Sorry, aber das gehört auch zur Softwareentwicklung, dass
man eine Idee in seine Lieblingsprogrammiersprache umsetzen kann.
Dieses Forum versteht sich in erster Linie als Helfer zur Selbsthilfe.
Dazu gehört auch, dass der Fragesteller nach Möglichkeit selbst
programmiert, und ihm möglichst wenig auf dem Silbertablett serviert
wird. Nur so lernst du.
Karl Heinz Buchegger schrieb:> ...> Du wirst das ja doch wohl lesen können? oder nicht?>> Oder soll ich schreiben>> [pseudocode]>> wenn der Messwert kleiner 60 ist> dann führe Aktion 1 aus>> andernfalls wenn der Messwert größer 100 UND kleiner 110 ist> dann führe Aktion 2 aus>> andernfalls wenn der Messwert größer 140 ist> dann führe Aktion 3 aus> [/pseudocode]>
Ok, muß halt selber überlegen wie ich es z.B mache, wenn der Wert mal
bei 150 war und dann auf 70 absinkt das dann Aktion_2 aktiv wird.
>> Dieses Forum versteht sich in erster Linie als Helfer zur Selbsthilfe.> Dazu gehört auch, dass der Fragesteller nach Möglichkeit selbst> programmiert, und ihm möglichst wenig auf dem Silbertablett serviert> wird. Nur so lernst du.>
Ich lerne am besten, wenn ein ich einen fehlerfreien Code nachvollziehen
kann. Das z.B. war dafür schon ganz gut :
Beitrag "Re: Wie programmiert man eine Hysterese in Assembler ?"
Nun das es einen Bereich geben muß in dem nichts passiert ist ja der
Knackpunkt den Herr Schmidt ( Schmidt-Trigger ) ja schon erkannt hat.
Wenn hier jemand einen Schmidt-Trigger Baustein für TTL-Pegel sucht,
verweist Ihr ihn dann auch auf Transitoren, Widerstände und Formeln
oder schreibt vielleicht auch jemand : " Nimm den 7414 " ?
Bernd_Stein
Bernd Stein schrieb:>> [pseudocode]>>>> wenn der Messwert kleiner 60 ist>> dann führe Aktion 1 aus>>>> andernfalls wenn der Messwert größer 100 UND kleiner 110 ist>> dann führe Aktion 2 aus>>>> andernfalls wenn der Messwert größer 140 ist>> dann führe Aktion 3 aus>> [/pseudocode]>>> Ok, muß halt selber überlegen wie ich es z.B mache, wenn der Wert mal> bei 150 war und dann auf 70 absinkt das dann Aktion_2 aktiv wird.
<Kopfklatsch>
Das ist doch da alles schon berücksichtigt.
Du musst dir nur überlegen, wie in Assembler die Phrase
wenn A kleiner B
umgesetzt wird.
Wenn du A in einem Register hast und wenn B eine konstante Zahl ist,
dann ist diese Phrase ein
CPI A, Zahl
BR...
welchen Branch musst du daher benutzen, wenn du die Logik
wenn A kleiner als eine Zahl
mach was
entsprechend umsetzen sollst?
CPI A, Zahl
BR... VergleichTrifftNichtZu
mach was
VergleichTrifftNichtZu:
weiter gehts
oder aber auch, wenn zb die abhängige Aktion etwas größer und komplexer
ist
CPI A, Zahl
BR... VergleichTrifftZu
weiter gehts
VergleichTrifftZu:
mach was
...
Da gibt es verschiedene Möglichkeiten, je nachdem. Aber allen ist
gemeinsam, das bestimmte Anweisungen nur dann ausgeführt werden, wenn
die Bedingung A kleiner B erfüllt ist (oder größer, oder kleiner gleich
oder was auch immer)
Das eine ist der logische, anwendungsabhängig Teil zu denken. Das andere
ist dessen Umsetzung in eine bestimmte Programmiersprache. Und wenn das
eben Assembler ist, dann muss man eben die Assemblerversion eines
derartigen Vergleichs benutzen. Und die besteht nun mal (oft) aus einem
Compare mit einem nachfolgenden Branch.
Ach Bernd, Du stehst Dir wieder mal selbst im Wege, willst ganz einfache
Dinge hochwissenschaftlich lösen...
Pseudocode:
wenn Temperatur oberen Schwellwert überschreitet, dann schalte Heizung
aus
wenn Temperatur unteren Schwellwert unterschreitet, dann schalte Heizung
ein
wenn Temperatur zwischen unterem und oberem Schwellwert ist, dann lasse
alles so, wie es ist...
Den ASM-Code dazu findest Du in meiner uralten Antwort, die Du im ersten
Beitrag dieses Threads verlinkt hast.
Natürlich brauchst Du ein Flipflop, was sich den aktuellen Zustand
merkt. Dies kann bei einfachen Dingen der Portpin sein, mit sbi
schaltest Du ihn ein, mit cbi wieder aus. Manchmal (z.B. bei einem
Blinker) geht es aber nicht mit dem Portpin, da muss man eben einen
Merker benutzen. Dies ist eine Bitvariable, die man setzen oder löschen
kann (sbr, cbr) und deren Status man abfragen kann (sbrc, sbrs). Merker
werden gelegentlich auch als Bitvariablen, Booleans, Flags oder
Semaphores (kein Anspruch auf Vollständigkeit) bezeichnet und
signalisieren einen Zustand.
...
Hi
Bernd, es ist wirklich nicht immer leicht, einem Spezi zu folgen, aber
ein wenig nachdenken, kombinieren und abwandeln solltest du schon
können. Sonst erwartest du, das du hier fertige Software serviert
bekommst. An die Kollegen, die hier mit C oder anderen Sprachen helfen
wollten: "es ist nicht immer einfach, von einer Hochsprache auf
Assembler herunterzubrechen, wenn man A: noch nicht sattelfest ist und
B: von der Hochsprache keine Ahnung hat. Das hat mit Lesen nix zu tun.
Zurück zu meiner Antwot:
Na klar, das Konstrukt war keine Hysterese, aber eine Vorlage. In den
Aktionen, solltest du deine Grenzen verarbeiten. Zur Not mit weiteren
Bits, die dir Sagen, der Wert kommt von oben oder von unten. ( Bit
gesetzt, dann fallender Wert, Bit 0, dann steigender )
OT
Ich werde hier doch nicht maßgeschneiderte Software präsentieren und,
sorry dafür, ein Programmierer erfindet natürlich ständig ein neues
Rad.... sonst gäb es nicht soviel Software und Softwareupdates...
Außerdem, es macht ihn stolz, eine "eigene" Version von einem Rad
entwickelt zu haben, was Anfangs durchaus noch eiern darf. Irgendwann
einmal entdeckt er die Veröffentlichung eines "Experten" und stellt
fest, das seine Version aber mit 2 Bytes weniger auskommt.
OT-end
Du hast gefragt, ob ich mir das Programmieren selbst beigebracht hab :
ja. Es war ein weiter Weg vom Sinclair Z80 bis zum Delphi-
Datenbankprogramm. Und dann natürlich noch die Hardware, erst diskret,
dann vor 4 Jahren ungefähr den µC entdeckt..
Gruß oldmax
...
Danke an alle die hier mitgewirkt haben.
Dies war wirklich mal ein Thread, der ohne sinnlose Kommentare
ausgekommen ist. Anhand der Hilfestellung hier habe ich mal ein Programm
geschrieben, das ich in der Codesammlung hinterlegt habe.
Beitrag "ATtiny26 Balkenanzeige ( Hysterese ) mit acht Schaltschwellen (ASM)"
Bernd_Stein