Forum: Mikrocontroller und Digitale Elektronik Lese PWM Signal mit Micropython


von Felix (Gast)


Lesenswert?

Hallo,

momentan versuche ich, ein externes PWM Signal eines SMT172 
Temperatursensor an einem ESP32 Pin zu lesen. Ich würde das gerne mit 
Micropython hinbekommen, es klappt aber leider nicht. Hat jemand 
Erfahrung, wie man ein PWM Signal in Micropython ausliest?

Ein Teilproblem, welches ich nicht verstehe, ist folgendes: Wenn ich ein 
Callback für eine ansteigende Flanke des externen Pins setze und dann im 
Callback nur den Wert des Pins ausgebe, dann ist er mal 0 und mal 1. 
Sollte bei einer ansteigenden Flanke nicht immer der Pinwert im 
Interruptcode 1 sein?

Viele Grüße
Felix

von Theor (Gast)


Lesenswert?

Hm.

Mal drei andere Fragen:

1. Wenn die Callback-Funktion für einen steigende Flanke ausgelöst wird, 
welchen anderen Wert als '1' kann der Pin, während einer gewissen Zeit 
nach der Flanke haben?

2. Wie auch immer, Du Frage 1. beantwortest: Welchen Zweck hat es, den 
Wert nach dem Interrupt der steigenden Flanke, den Portpin zu lesen, 
wenn per Definition einer steigenden Flanke der Wert '1' sein muss ?

Jedenfalls, wenn Du unbedingt darauf bestehst, den Zusammenhang zwischen 
dem Wechsel von '0' und '1' und einer steigenden Flanke programmatisch 
zu überprüfen:
3. Für wie lange Zeit ist nach einer steigenden Flanke der Wert '1' und 
wie lange braucht im Vergleich der Code um den Portpin auszulesen?

von Felix (Gast)


Lesenswert?

Hallo Theor,

den Wert direkt danach auszulesen ist erstmal ein kleiner Sanity-Check 
gedacht. Ein Problem was bei Micropython nach meinem Verständnis besteht 
ist, dass du nur eine Interruptfunktion pro Pin haben kannst. D. h. mit 
dem Wert muss gechecked werden, ob es gerade durch eine steigende Flanke 
oder fallende Flanke getriggert wurde. Die einzulesende PWM-Frequenz ist 
maximal 7kHz, d. h. das auslesen des Pins sollte nach meinem Verständnis 
nicht zu lange dauern.

Gruß Felix

von Theor (Gast)


Lesenswert?

> den Wert direkt danach auszulesen ist erstmal ein kleiner Sanity-Check
gedacht.

Beantworte bitte Frage 1 und 2 von oben. Was soll der Sanity-Check, wenn 
die Definition gesund ist? Oder siehst Du in der Definition einen 
Fehler? Oder hast Du konkreten Anlass zu vermuten, dass der ESP diese 
Definition nicht korrekt realisiert?

> Ein Problem was bei Micropython nach *meinem Verständnis*
> [Hervorhebung durch mich] besteht ist, dass du nur eine
> Interruptfunktion pro Pin haben kannst.
> D. h. mit dem Wert muss gechecked werden, ob es gerade durch
> eine steigende Flanke oder fallende Flanke getriggert wurde.

Das ist eine problematische Aussage, denn der erste Satz hat keinen 
inneren Zusammenhang mit dem zweiten.

Was den ersten Satz betrifft:

Falls ich nur genau einen Interrupt pro Pin haben kann, dann weist 
das auftreten des Interrupts auch darauf hin, das genau dieser Pin den 
Interrupt ausgelöst hat.

Das Gegenteil wäre der Fall, wenn ein Interrupt durch mehrere Quellen 
ausgelöst werden kann und der Interrupt-Mechanismus keine eigenen Mittel 
bereitstellt, die Quelle zu unterscheiden.

Der Doku von micropython entnehem ich nicht, dass der Interrupt 
unspezifisch bzgl. der Pins ist. 
http://docs.micropython.org/en/v1.9.3/esp8266/esp8266/tutorial/pins.html

Das ist (zugegeben) manchmal ein Versäumnis des Autors. Deswegen 
könntest Du im Datenblatt des Controller nachprüfen, ob das beim ESP... 
so ist oder nicht. (Ich kenne den leider nicht). Aber hast Du eigentlich 
einen Anlass anzunehmen, dass die Doku von micropython in der Hinsicht 
zu lakonisch ist?

Beim AVR, z.B. dem ATMega48, 88, 168 gibt es so einen Fall durchaus. Der 
Pin Change Interrupt ist in Grenzen (und abhängig von der Konfiguration) 
unspezifisch. Man kann z.B. nicht ohne weiteres sagen ob und welcher Pin 
zwischen 23 und 16 den Interrupt ausgelöst hat. Meinst Du das ist beim 
ESP auch so und warum konkret meinst Du das?

Was den zweiten Satz betrifft:
Was lässt Dich davon ausgehen, dass der ESP nicht ausschliesslich bei 
einer steigenden Flanke den Interrupt auslöst?

Was den Zusammenhang betrifft:
Angenommen, der ESP hätte wie Du sagst nur einen Intterupt, der bei 
einer beliebigen Flanke auslöst. Das heisst noch nicht, dass er das 
nicht spezifisch für einen Pin tut. Umgekehrt geht die Schlussfolgerung 
auch nicht.


> Die einzulesende PWM-Frequenz ist maximal 7kHz, d. h. das auslesen
> des Pins sollte nach meinem Verständnis nicht zu lange dauern.
Das sollte auch 1mHz und bei 1GHz nicht zu lange dauern. Wichtig ist 
doch die Relation zwischen CPU-Frequenz und PWM-Frequenz, wenn Du das 
abfragst.
Also Frage 3. Und die wird ja nur relevant, falls Du Frage 1 und 2 so 
beantwortest, dass die Definition nicht realisiert wird, oder das der 
ESP den Interrupt unspezifisch bzgl. der Ursache auslöst, oder das der 
ESP den Interrupt unspezifisch oder für mehrere Pins gleichermaßen 
auslöst.

Denk darüber mal in Ruhe nach. Das ist alles recht einfach.

Wenn ich Dir raten darf, wonach Du nicht gefragt hast: Hüte Dich vor 
unbegründeten Annahmen und analysiere Deine Fragen, wenn die Antwort 
Dich nicht befriedigt. Häufig stellt man nur die falschen Fragen oder 
man stellt sie zu ungenau.

von Felix (Gast)


Lesenswert?

Um die Diskussion wieder etwas stärker auf die Frage zu fokussieren: Ich 
habe folgenden Code auf einem ESP32 Dev Board mit an Pin4 
angeschlossenen SMT172 Temperatursensor ausgeführt:
1
>>> import machine
2
>>> p4 = machine.Pin(4, machine.Pin.IN)
3
>>> def callback(p):
4
...     print("{} {}".format(p, p.value()))
5
... 
6
>>> p4.irq(trigger=machine.Pin.IRQ_RISING, handler=callback)
7
<IRQ>
8
>>> Pin(4) 0
9
Pin(4) 0
10
Pin(4) 0
11
Pin(4) 0
12
Pin(4) 0
13
Pin(4) 1
14
Pin(4) 1
15
Pin(4) 1
16
Pin(4) 1
17
Pin(4) 0
18
Pin(4) 0
19
Pin(4) 0
20
Pin(4) 0
21
Pin(4) 1
22
Pin(4) 1
23
Pin(4) 1
24
Pin(4) 1
25
Pin(4) 0
26
Pin(4) 0
27
Pin(4) 0
28
Pin(4) 0

Nach meinem Verständnis müsste IRQ_RISING dafür sorgen, dass der 
Callback nur bei einer steigenden Flanke ausgeführt wird und damit die 
Ausgabe nur 1 anzeigt. Die Frequenz von 7kHz des SMT172 ist deutlich 
niedriger als die 240Mhz Frequenz des ESP32. Leider weiß ich nicht, 
wielange das Interpretieren des Python Codes genau braucht, hat da 
jemand einen Hinweis bzw wo bei mir der Denkfehler ist?

von Theor (Gast)


Lesenswert?

Die Hinweise sind Dir gegeben worden.

Und Tschüss.

von Sascha W. (sascha-w)


Lesenswert?

Felix schrieb:
> Um die Diskussion wieder etwas stärker auf die Frage zu fokussieren: Ich
> habe folgenden Code auf einem ESP32 Dev Board mit an Pin4
> angeschlossenen SMT172 Temperatursensor ausgeführt:
>
>
1
>>>> import machine
2
> ...
3
>
>
> Nach meinem Verständnis müsste IRQ_RISING dafür sorgen, dass der
> Callback nur bei einer steigenden Flanke ausgeführt wird und damit die
> Ausgabe nur 1 anzeigt.
richtig

> Die Frequenz von 7kHz des SMT172 ist deutlich
> niedriger als die 240Mhz Frequenz des ESP32.
Wie lang soll denn die H-Time des Sensors sein - von den 143μs 
Periodendauer?

> Leider weiß ich nicht,
> wielange das Interpretieren des Python Codes genau braucht, hat da
> jemand einen Hinweis bzw wo bei mir der Denkfehler ist?
Auf jeden Fall solltest du dich bei so zeitkritischen Funktionen davon 
verabschieden so aufwendige Sachen wie Print im Interrupt zu machen. 
Lies den Zustand des Pins in eine Variable und setze ein Flag. In der 
loop kannst du des Zustand ausgeben.
Was die Verarbeitungsgeschwindigkeit angeht - toggle mal einen Pin in 
der loop und schau dann welche Frequenz dann am Pin rauskommt.
Im übrigen willst du ja die Zeit deines PWM-Signals messen, wenn du 100 
Stufen auflösen willst darf die Verarbeitung auch nur weniger als 1/100 
der zu messenden Zeitspanne betragen.

Ich hab zwar noch nicht mit μPython gearbeitet, aber ich denken das wird 
nichts.

Sascha

von Felix (Gast)


Lesenswert?

Hallo Sascha,

vielen Dank für den Input. Ich habe das Print Statement herausgenommen 
und tatsächlich, jetzt passt das Verhalten zur Theorie:
1
from machine import Pin
2
3
elements = 100
4
buf = bytearray(elements)
5
counter = 0
6
7
def callback(p):
8
  global buf, counter, elements
9
10
  if counter >= elements:
11
    return
12
  
13
  buf[counter] = p.value()
14
  counter += 1
15
16
pwmPin = Pin(4, Pin.IN)
17
pwmPin.irq(trigger=Pin.IRQ_RISING, handler=callback)
18
19
while counter < elements:
20
  pass
21
22
pwmPin.irq(None)
23
24
print(buf)
Output:
1
bytearray(b'\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01')

Als kleines Fragezeichen bleibt noch, warum die ersten zwei Werte nicht 
1 sind. Ich habe gecheckt, dass es nicht an der Initialisierung liegt, 
die ersten zwei Aufrufe schreiben wirklich ne 0 rein.

Die maximale Frequenz rauszufinden wäre spannend. Leider kann ich 
momentan das Timing des Outputs nicht messen.

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.