HIER gerade nicht, aber generell sollte man sich sowas gar nicht erst angewöhnen......ist mir wohl soweit bekannt das man das nicht umbedingt so macht, da aber sowieso nur mit einem Reset wieder rausgesprungen wird ist das wie Du schon Sagst kein alzugrosses Problem!
Sauberer wäre entweder, den Ende-Code mit in die Timerüberlauf-Subroutine zu nehmen (effizienter aber logischerweise unübersichtlicher), oder den Ende-Code auch als Subroutine gestalten, und den dann aus der Timer-ISR heraus anzuspringen (Gosub). Dann ist das sauber geschachtelt, in Ende könnte man später auch noch ein aufwecken des Controllers einbauen, von wo dann sauber in die Timer-ISR, und von dort in die Main-Loop "return"t werden kann.
Also sauber geschachtelte Subroutinen.
Eine weitere saubere Alternative wäre, in der Timer-ISR stattdessen in Timeoutflag zu setzen, und dieses in der Hauptprogrammschleife abzufragen.Die ISR wird dann vorher sauber verlassen (alle Stacks ordentlich aufgeräumt), im Hauptprogramm kannst Du dann nach "Ende" hopsen.
(Entweder endgültig mit GOTO, oder wenn eine Rückkehr möglich sein soll mit GOSUB (wobei Ende dann logischerweise eine Subroutine sein muß).)
Natürlich kann man von diesen ganzen Konzepten abweichen, der AVR macht jeden Mist mit, den Du ihm sagst. Aber dann mußt Du eben auch wirklich wissen, was Du ihn tun läßt.
Goto springt einfach zur neuen Flash-Adresse.
Gosub auch, legt aber zusätzlich die Rücksprungadresse auf den (HW-)Stack
Call ist Gosub ähnlich, packt aber zusätzlich(!) entsprechend der in declare Subroutine deklarierten Variablen irgendwelchen Kram in den Frame und/oder SW-Stack
Entsprechend müssen beim beenden einer deklarierten Call-Sub die verwendeten Stacks sauber abgeräumt werden -> End Sub bzw Exit Sub
Entsprechend muß beim beenden einer Gosub-Sub der HW-Stack sauber abgeräumt werden -> Return nimmt die oberste Adresse (war ja, wenn man nichts durcheinander gebracht hat die Rücksprungadresse), und hopst dahin.
(Handelt es sich bei einer Gosub-Sub um eine ISR (also mit On Interruptquelle "deklariert"), reaktiviert das erste Return (ausserhalb irgendwelcher IF-Conditions) ausserdem global die Interrupts (RETI statt RET)
Springt man zB aus einer ISR (Interrupt also deaktiviert) mit Gosub in eine andere ISR hinein, werden bei der Rückkehr von dieser in die Erste bereits die IRQs global freigegeben. Stacktechnisch paßt das aber...)
Nein... oder besser gesagt nicht wegen debounce, sondern weil die Sprungziele (Press, Press2, Press3) eben als Subroutinen mit je einem Return enden, welches erstens die obersten beiden Bytes vom Stack nimmt (da fehlt also jetzt was, außerdem könnte der Stackpointer ins Nirvana laufen (laut Datenblatt hat der volle 16bit (also bis Adresse 0xFFFF), SRAM gibts aber nur bis Adresse 0x045F),...Bei deinen debounce musst du mit subs arbeiten. Das Programm läuft nach dem decr bis zu return und holt sich eine Adresse aus dem stack...
und zweitens diese beiden Bytes als Adresse für den Rücksprung nutzt.
Es wurde ja nicht konkret geschrieben, was geht, und was nicht. Meinem derzeitigen Verständnis nach sillte nur die Voreinstellung korrekt arbeiten (debounce..Press2...).
Wird eine der anderen Tasten gedrückt, geht die Anzeige auf "00", soweit korrekt?
Immer "00"?
Zahl wird ja eigentlich nicht initialisiert, ist also nach dem Programmstart 0.
Der Grund ist in Bascom ziemlich fies versteckt:
Eigentlich hat der SRAM nach einem Powerup eher zufällige Werte, auch nach einem Reset kann da alles mögliche stehen. Daß das immer 'ne 0 sein soll, hatte mich ziemlich verwirrt.
Der Grund ist, das Bascom beim Start des Programmes einfach den gesamten SRAM löscht (=0 setzt), es sei denn, man iunterdrückt das mit der $NORAMCLEAR-Direktive.
Damit wäre das verhalten (meiner Meinung nach(!!))nachvollziehbar.
In der Hauptprogrammschleife ist der HW-Stack leer, der Stackpointer zeigt auf 0x045F (RAMEND). Ein Gosub würde(!) dorthin die Rücksprungadresse PUSHen und danach (Post Decrement) den Stackpointer dekrementieren (jaja, zwei Bytes, zwei PUSHs, die Adresse steht also in 0x045E:0x045F, der SP zeigt auf 0x045D).
Am Ende der SUB wird die Adresse vom Stack gePOPt, wobei eben erst (Pre Increment) der SP Incrementiert wird (auch wieder zwei Bytes, die Inhalte von 0x045E:0x045F sind die Rücksprungadresse, der SP ist wieder 0x045F.
Jetzt wird aber nicht mit Gosub gesprungen, sondern mit Goto. Der Stack bleibt also leer, der SP auf 0x045F.
Am Ende der SUB schlägt dann das Return zu:
es wird zweimal vom Stack gePOPt, also erst der SP PreIncrementiert, und dann von da (0x0460) geladen. Diese Zelle existiert schlichtweg nicht, Zelle 0x0461 beim zweiten POP ebenso.
Meiner Meinung nach liefern beide POPs also jeweils 'ne 0, und genau dahin wird gesprungen:
Flashadresse 0x0000
Das entspricht dem Reseteinsprungpunkt (auch wenn es kein Reset ist, insbesondere also die I/O-Register, der SRAM usw bestehen bleiben).
Aber dort beginnt der Programmcode inklusive den Initialisierungen, die BASCOM so implementiert. Auch inklusive des SRAM-Clears.
Zahl wird also auch 0 gesetzt, die Timer etc... reinitialisiert. Die Vorauswahl mit Debounce..Press2 und die Anzeige geht erstmal wieder (bis zum nächsten Drücken einer der anderen beiden Tasten...
P.S.: mMn sollte der Code übrigens trotzdem so laufen, wenn mit der $NORAMCLEAR-Direktive ein löschen der Variablen (insbesondere Zahl) beim ... äh ... Warmstart unterdrückt wird.
Das wäre dann quasi das Bild mit dem "Analysten" aus dem, von @TommyB hier ...