Forum: Compiler & IDEs MicroPython: uasyncio


von Christoph M. (mchris)


Lesenswert?

Im Moment beschäftige ich mich gerade mit Micropython.

Ich habe folgende Problemstellung:
1. Es soll jede Sekunde ein Zählerwert ausgegeben werden
2. Gleichzeitig soll es möglich sein, mittels eine User Input (REPL) den 
Zähler auf 0 zu setzen.

Ich habe es mal mit "uasyncio" probiert und zwei Tasks erzeugt.
https://github.com/peterhinch/micropython-async/blob/master/v3/docs/TUTORIAL.md
Im einen wird der Wert kontinuierlich ausgeben und der andere versucht, 
den User-Input zu lesen. Leider scheint aber das lesen wollen eines 
User-Inputs
1
        x=input()
2
        print(x)

das gesamte System zu blockieren und es geht erst weiter, wenn man eine 
Taste drückt.
Hat jemand eine Lösung für so ein Problem?

von Katon (Gast)


Lesenswert?

Welcher Controller? Welche Eingabeschnittstelle?

Eingabe via UARTx:
1
...
2
3
z = UARTx.any()                # Anzahl der Zeichen im Eingabepuffer
4
5
if z > 0:
6
    c = UARTx.read(1)          # Zeichen abholen
7
    ...                        # Zeichen verarbeiten   
8
9
...

von Christoph M. (mchris)


Lesenswert?

Ich verwende einen ESP32.
Die Idee mit der UART wäre gut, aber die Kommunikation geht über REPL 
und REPL blockiert UART0 (welche die richtig Schnittstelle wäre).

von Alex Z. (alexander_z49)


Lesenswert?

Ich habe auf mehreren ESP32 µPython mit uasyncio laufen für 
Benutzereingaben über TCP und gleichzeitigem ansteueren von sk9822 LEDs. 
Würde helfen, wenn du uns deinen Code mal zeigst.

Welche Verbindung nutzt du um die REPL aufzurufen? Ich nehme an, der 
ESP32 ist über USB als virtueller Com-Port am PC erreichbar und du nutzt 
ein Terminal-Programm?

Alex

von Christoph M. (mchris)


Lesenswert?

>Ich habe auf mehreren ESP32 µPython mit uasyncio laufen für
>Benutzereingaben über TCP und gleichzeitigem ansteueren von sk9822 LEDs.

Klingt gut. Hier ist der Code:
1
import uasyncio
2
3
async def count():
4
    counter=0
5
    while True:
6
        print(counter)
7
        counter=counter+1
8
        await uasyncio.sleep_ms(1000)
9
10
async def userInput():
11
    while True:
12
        print("wait for input")
13
        x=input()
14
        print(x)
15
        await uasyncio.sleep_ms(100)
16
        
17
async def main():
18
    uasyncio.create_task(count())
19
    uasyncio.create_task(userInput())
20
    await uasyncio.sleep_ms(10_000)
21
22
uasyncio.run(main())

Obwohl der Counter jede Sekunde ausgegeben werden sollte, passiert das 
nur, wenn man den "userInput" drückt.
Vielleicht liegt es ja an der Ausgabe und eine LED würde trotzdem 
blinken.

von Katon (Gast)


Lesenswert?

Du kannst es mit einer nichtblockierenden Abfrage von 'stdin' lösen.
1
import sys, select
2
3
spoll = select.poll()
4
spoll.register(sys.stdin, select.POLLIN)
5
6
...
7
8
if spoll.poll(0):           # Zeichen im Eingangspuffer von stdin?
9
    c = sys.stdin.read(1)   # Zeichen abholen
10
    print(c)                # Zeichen verarbeiten/ausgeben
11
12
...

von Christoph M. (mchris)


Lesenswert?

>Du kannst es mit einer nichtblockierenden Abfrage von 'stdin' lösen.

Danke, das scheint sehr gut zu funktionieren. Ich habe es mal in die 
Routine mit dem Zähler verpackt:
1
import sys, select
2
import utime as time
3
4
spoll = select.poll()
5
6
spoll.register(sys.stdin, select.POLLIN)
7
8
counter=0
9
10
while True:
11
    if spoll.poll(0):           # Zeichen im Eingangspuffer von stdin?
12
        c = sys.stdin.read(1)   # Zeichen abholen
13
        print("input: "+c)      # Zeichen verarbeiten/ausgeben
14
    time.sleep(0.1)
15
    print(counter)
16
    counter=counter+1

Wenn man es in der "Thonny" Umgebung debugged, muss man erst mal "Enter" 
drücken. Danach werden immer erst alle Zeichen im Tastaturbuffer 
gesammel und bei Enter erst übertragen. Das scheint aber eine 
Eigenschaft von "Thonny" zu sein.

Wenn man es mit minicom benutzt
1
minicom -D /dev/ttyUSB0

funktioniert es perfekt.

von Christoph M. (mchris)


Lesenswert?

Die verwendete Funktion
1
time.sleep(0.1)
bremst das Polling auf 100ms pro Zeichen.
Es wäre besser, das Polling "full speed" während der Wartezeit zu 
machen.
Kennt jemand eine gute Methode dazu?

Es gibt hier

https://docs.micropython.org/en/latest/library/time.html

die Methode time_ticks_diff. Aber ich habe die Befürchtung, dass es 
einen Zeitbasis Überlauf geben könnte und dann das System hängt:
1
# Wait for GPIO pin to be asserted, but at most 500us
2
start = time.ticks_us()
3
while pin.value() == 0:
4
    if time.ticks_diff(time.ticks_us(), start) > 500:
5
        raise TimeoutError

von Kaj (Gast)


Lesenswert?

Christoph M. schrieb:
> Es wäre besser, das Polling "full speed" während der Wartezeit zu
> machen.
> Kennt jemand eine gute Methode dazu?
Einfach das sleep weglassen?

von Christoph M. (mchris)


Lesenswert?

>Einfach das sleep weglassen?

Ja, dann wäre es "full speed". Es soll aber auch der Counter alle 100ms 
erhöht und ausgegeben werden.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.