Funktion beenden

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ja genau, das mache ich auch in separaten Funktionen.
Das Problem ist wie komme ich mit 'pruefe_ir_eingabe()' an den Informationen ran welche Taste gedrückt wurde?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das glaube ich nicht, dass du das in separaten Funktionen machst. Bitte zeige deinen Code.

Ein Weg ist eine collections.dequeue, die du im callback mit eingehenden Werten fuellst. ABER ACHTUNG: die Werte rauslesen darfst du nur mit einem kurzzeitig disableten IRQ, siehe https://docs.micropython.org/en/latest/ ... -functions
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Benutzeravatar
Kebap
User
Beiträge: 686
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

egon11 hat geschrieben: Mittwoch 15. März 2023, 16:42 Irgenwie ist das mit der Callback-Funktion alles triggi. Wenn ich darin eine While-True Schleife ausführen lasse um auf bestimmte Dinge zu reagieren dann läuft sie nicht weiter...
Du denkst, du brauchst eine While-True Schleife, um bestimmte Ziele zu erreichen, und scheiterst dann daran.
Vielleicht sagst du einfach mal, was deine eigentlichen Ziele sind, denn vielleicht gibt es andere Wege dorthin.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

@ __deets__ Das mit dem collections.dequeue liest sich ja gut. Allerdings kann ich pyb nicht auf dem Pico installieren. Ich finde auch den source Code nicht.


@Kebap Ich möchte verschiedene Funktionen erstellen die ein WS2812b zum leuchten bringt. Das heißt einmal "statische Lichter", (einmal in den gewünschten Farben an und dann bleibt es so). Das habe ich ja hinbekommen.

Jetzt geht es mir aber um das fortlaufende, heißt z.b. endlos blinken. Beim Endlosblinken braucht man ja - soweit ich weiß - eine unendliche Schleife. Und die soll aber, wenn man etwas anderes drückt, diese abrechen und etwas anderes starten.

So ähnliches habe ich schon mal mit dem Arduino und deren C Programmiert. Da ging es mit loop().
Ich dachte so ähnliches kann man auch in Python machen.
Daher das ich mich besser in Python auskenne als in C dachte ich mir, ich mache das in Python.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Man braucht beim endlos-blinken keine endlose Schleife. Man kann das durchaus so machen, wie Kebab und ich das dargestellt haben: eine Hauptschleife, und die prueft den gerade aktiven Mode, und ruft eine Unterfunktion auf. Und die Unterfunktion zB prueft, wieviel Zeit vergangen ist, und schaltet entsprechend die Animation einen Schritt weiter. OHNE WHILE SCHLEIFE. Das geht schon alles. asyncio waere eleganter, eben weil es den "natuerlichen" Programmfluss moeglich macht. Aber geht ja nunmal nicht.

Und bei dem Arduino muss das so aehnlich ausgesehen haben, denn dessen loop kann auch keine Endlos-Schleife enthalten (oder implizit aufrufen), sonst kommen veraenderte Werte genauso wenig an.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

OK klinkt logisch, nur wie bekomme ich den aktiven Mode wenn ich das pyb Modul nicht bekomme?
Und mit damit die Unterfunktion einen schritt weiter schaltet, kann ich in der Hauptschleife (while True?) die Zeit geprüft werden ob ich die unterfunktion nochmal starte mit anderen Werten. So etwas?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich habe keine Ahnung von welchem pyb-Modul du redest.

Und warum willst du die Zeit in der Hautptschleife pruefen? Ich habe doch geschrieben, dass die Unterfunktion das tut. Was angeblich "logisch" ist.

Den Pico kannst du auch mit dem Arduino-Framework benutzen. Wenn du das damit schon hinbekommen hast, wuerde ich das benutzen, weil du offensichtlich doch nicht so wirklich besser in Python auskennst.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ah, jetzt erst gesehen, ich hatte das pyb-Modul selbst verlinkt. Mein Fehler, ich dachte das waere ein allgemeines Modul, fuer alle ports. Das rp2-Modul hat das leider nicht.

Hier https://docs.micropython.org/en/v1.15/r ... rules.html gibt es allgemeine Hinweise, unter anderem auch wieder schedule. Das kann also benutzt werden, um das einsortieren in eine dequeue zu machen, ohne dass es zum Konflikt mit der Hautpschleife kommt.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1012
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Eine Vorgehensweise, die auch im Micropython-Forum angepriesen worden ist, ist die Nutzung von uasyncio.

Blinkende LED ist gar kein Problem. Das Problem wird sein, dass du wahrscheinlich noch nie etwas mit asyncio / uasyncio gemacht hast. Das ist nicht trivial.
ISR-Callbacks können z.B. eine Funktion aufrufen, die einen Task abbricht `task.cancel()`.

Um das vernünftig zu gestalten, wirst du auch mit Klassen arbeiten müssen.

Blinken geht auch mit Timer.

Code: Alles auswählen

from uasyncio import ThreadSafeFlag
from machine import Timer
from time import sleep

def blinker(pin, delay_ms, flag):
    # die toggle funktion wird durch
    # den Timer aufgerufen
    def toggle(timer):
        # der Timer wird der zu aufrufenden Funktion
        # übergeben. Man kann ihn mit timer.init(...) neustarten
        print("Toggle")
        
        # Ohne LED getestet
        # deswegen auskommentiert
        
        # Pin 0 -> 1 oder 1 -> 0
        # pin(not pin())
        
        if flag.state:
            # Wenn flag.state gesetzt ist, Funktion verlassen
            # und den Timer nicht erneut starten
            return
        timer.init(mode=Timer.ONE_SHOT, period=delay_ms, callback=toggle)
        
    Timer(0,mode=Timer.ONE_SHOT, period=delay_ms, callback=toggle)


flag = ThreadSafeFlag()
# hier noch einen Pin zuweisen.
# pin=None hatte ich zum Testen genutzt, da ich keine LED angeschlossen habe
blinker(pin=None, delay_ms=1_000, flag=flag)
sleep(5)
flag.set()
print("Blinken beendet")
Hier noch eine vereinfachte Variante:

Code: Alles auswählen

from machine import Timer
from time import sleep


def blinker(pin, delay_ms):
    def toggle(timer):
        print("Toggle")
        # pin(not pin())
        
    return Timer(0, mode=Timer.PERIODIC, period=delay_ms, callback=toggle)


# hier noch einen Pin zuweisen.
# pin=None hatte ich zum Testen genutzt, da ich keine LED angeschlossen habe
timer = blinker(pin=None, delay_ms=1_000)
sleep(10)
timer.deinit() # <- beendet den Timer
Den Timer habe ich mit der ID 0 initialisiert. Das ist dann ein HardwareTimer.
Wenn man die ID -1 nutzt, wird ein SoftwareTimer verwendet, von denen auch mehr zur Verfügung stehen, aber vom jeweiligen Mikrocontroller unterstützt werden müssen.
Der ESP32 kann das auf jeden Fall. Beim Testen ist mir dann noch aufgefallen, dass auch bei id -1 ein und derselbe Timer zurückgeliefert wird.
Entsprechend habe ich dann 2 SoftwareTimer mit ID -1 und -2 gestestet, woraus unterschiedliche Objekte resultieren.
Möglicherweise ist das aber noch ein Bug. Ich hätte erwartet, dass Timer(-1) immer einen neuen Timer zurückliefert und nicht den existierenden SoftwareTimer mit der ID -1.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

OK. Aber 2 Fehler bekomme ich wenn ich dies ausführe.
1. Fehler ist bei flag.state:

Code: Alles auswählen

AttributeError: 'ThreadSafeFlag' object has no attribute 'stat'
und es funktioniert nur der Software Timer (-1)
Wenn ich Timer(0, ...) eingebe, dann kommt der Fehler

Code: Alles auswählen

[ValueError: Timer doesn't exist/code]
Benutzeravatar
Dennis89
User
Beiträge: 1123
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

naja ich kann auch kein 'stat' im Code finden.

Das mit dem Timer steht auch in der Doku: (Es geht ja um einen Pico?)
https://docs.micropython.org/en/latest/ ... tml#timers

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Dennis89 hat geschrieben: Donnerstag 16. März 2023, 22:47 Es geht ja um einen Pico?
Ja genau
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Das mit dem Timer() und ThreadSafeFlag() ist genau was ich suche.
Nur das halt der Abruf von ThreadSafeFlag().state nicht funktioniert.
Aber so etwas wäre für meine Zwecke genial.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ich habe nochmal folgenden Code erweitert:

Code: Alles auswählen



def callback(data, addr, ctrl):
    global x
    if data > 0:  # NEC protocol sends repeat codes.
        print('Data {:02x} Addr {:04x}'.format(data, addr))
        blinker(pin=None, delay_ms=1_000, x=data)
       

def blinker(pin, delay_ms,x):
    def toggle(timer):
        print(x)
        
        if x != 70:
            print("return")
            return
        timer.init(mode=Timer.ONE_SHOT, period=delay_ms, callback=toggle)
    
    Timer(-1,mode=Timer.ONE_SHOT, period=delay_ms, callback=toggle)
    

ir = NEC_16(Pin(16, Pin.IN), callback)

Wenn ich die 1 auf der FB drücke ist data 69, die 2 ist 70 u.s.w.

Ich dachte mir wenn ich das Argument 'data' mit angebe und in der toggle-Funktion prüfe ob die gerade gedrückte Taste ungleich 70 (Taste 2) ist, dann sollte sie per return abbrechen.

Das tut sie nur, solange ich nicht die Taste 2 drücke, wenn ich als erstes paar mal die Taste 1 (69) drücke, dann bricht sie wie gewollt ab, aber sobald ich die 2 drücke dann wieder die 1 wird die Toggle Funktion nicht mehr abgebrochen bzw kehrt nicht zurück und die print-Ausgabe ist immer noch 70.
Hängt das mit der Callback-Methode zusammen?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Es wurde wirklich schon oft hier gesagt: im callback darfst du nur signalisieren, oder mit schedule längeren/komplexen Code laufen lassen. Der Blinker Code ist so auch Quatsch, weil du andauernd neue Objekte erzeugst, statt eines immer wider zu verwenden. Das ist auch schlecht entworfen in der Beziehung, weil du es nicht von außen manipulieren kannst. Da muss ein ordentliches Objekt her, mit on/off oder toggle Methoden.
Antworten