Dunkle Seite MH-Z19

Was nochmal? Wie viel kannst du?

Ja, heute sprechen wir noch einmal über unseren beliebten Kohlendioxidsensor Winsen MH-Z19. Nein, es wird keine Wiederholungen geben *.



Fast *

Wie Sie auf den Seiten dieser Ressource sehen regelmäßig erscheinen Horror Artikel über die Gefahren einer hohen Konzentration von CO2 in den Raum. Und obwohl Behauptungen, dass Konzentrationen über 1000 ppm die Hölle und den Tod mit sich bringen, leicht übertrieben sind ( Wikipedia sagt, dass zumindest einige Effekte mit 1% beginnen, das sind 10.000 ppm, während der Sensor den gesamten Bereich von 5000 ppm hat) - CO2 kann dienen als Indikator für das Vorhandensein anderer schlechter Dinge aufgrund unzureichender Belüftung. Deshalb habe ich mich auch für die faszinierende Welt der CO2-Metrie entschieden und den genannten Sensor in die Hand genommen.

Als erstes habe ich es natürlich mit Arduino verbunden. Ich habe (mit den notwendigen Änderungen) den Code aus dem Artikel kopiert , die geschätzten Zahlen erschienen auf dem Bildschirm.

Aber während ich es kopierte, kroch ein Wurm des Zweifels in meine Seele - warum gab dieser Sensor neun Bytes aus und nur zwei Bytes erklären CO2 von ihnen? Vielleicht will er mir noch etwas sagen?

Eine Suche im Internet führte mich zu einer so interessanten Seite . Der Autor experimentiert mit dem MH-Z19 und zeigt seine Reaktion auf undokumentierte (und dokumentierte) Befehle. Er hat noch nicht alle Teams ausprobiert, daher kann unser Teil noch herumtollen. Das werden wir tun.

Zunächst beschäftigen wir uns mit dem „klassischen“ Team 0x86 (oder einfach 134), mit dem wir die CO2-Konzentration erhalten. Revspace-Berichte:

A response to command 0x86 typically looks like this:
0xFF CM HH LL TT SS Uh Ul CS
where
CM is the command repeated back
HH/LL is the CO2 ppm value, high/low part
TT is the temperature in degrees Celcius, plus 40. For example, when temperature is 25 deg C, then TT = 0x41
SS is some kind of status byte, this byte always has only one bit set!
Uh/Ul is some unknown value, perhaps related to pressure? After booting the sensor, it starts out at 15000 exactly, then typically settles to about 10500.
Cs is the checksum

Das heißt, die Antwort des Sensors auf diesen Befehl enthält auch die Temperatur T (um 40 Grad verschoben) und zwei unbekannte Zielwerte - ein Byte S und zwei Byte U. S nimmt Werte von zwei Grad an, und U fällt beim Starten des Sensors von 15.000 auf etwas mehr als 10 ab 000.

Wie kann man verstehen, was die Zahlen S und U bedeuten? Natürlich müssen Sie eine Grafik zeichnen! Zeichnen Sie in jeder unverständlichen Situation ein Diagramm.

Langweilige technische Details
, . Serial.println(). USB-UART, . ( ) :

rlwrap cat | cu -l /dev/ttyACM0 > sensor_$(date '+%Y%m%d_%H%M%S').log


, , cat /dev/ttyACM0 > .., - , . (rlwrap cat | cu -l /dev/ttyACM0) , ( ). , , , .

:

tail -f sensor_.log

:

...
1188 62 64 42 38 10790 
1188 62 64 42 38 10790 
1190 62 64 42 38 10790 
1191 62 64 42 38 10790 
1192 62 64 42 38 10790 
1193 62 64 42 38 10790 
1195 62 64 42 38 10790 
...

— CO2, T, S, U (U — , ).

. ipython --pylab.

y = map(lambda a: map(int, a.split()), open("sensor1.log", "r").readlines()) #     ,     ,   
yt = transpose(y)
x = arange(len(yt[0])) / 720. #    ,       
figure()
plot(x, yt[0]) # CO2
figure(); plot(x, yt[1], "g"); # T
figure(); plot(x, yt[2], "r"); # S
figure(); plot(x, yt[-1], "m"); # U


Also der CO2-Graph:

Im Prinzip scheint es die Wahrheit zu sein. Traurig nur periodische Ausbrüche. Es scheint, dass dies daran liegt, dass der Sensor einfach auf dem Tisch liegt und mit der geringsten Brise seine Messwerte verloren gehen.

Temperatur:

Der Moment, in dem ich das Fenster geöffnet habe, ist deutlich sichtbar. Schwenkt um 1 - 2 Grad, was für eine undokumentierte Gelegenheit nicht schlecht ist. Wenn Sie sich jedoch an das NDIR- Prinzip erinnern-Sensor, Sie können verstehen, dass Sie vom eingebauten Thermometer keine hohe Genauigkeit erwarten sollten. Diese Instrumente messen die Absorption von Licht im fernen Infrarotbereich, und Ilyichs gute alte Glühbirne wird verwendet, um dieses Licht zu erzeugen, und Sie können sogar durch die Fenster sehen, wie es alle fünf Sekunden aufleuchtet (ein solcher Moment wird vom KDPV erfasst). Und diese Glühbirne verbraucht viel Energie und erwärmt dadurch den gesamten Sensor. Wie stark er sich erwärmt, hängt von der momentanen Konjunktur der Luftströme ab.

Wir nähern uns den interessantesten. Wert S:

Sagt nichts? Mir auch. Mit Trauer zeichnen wir CO2 und S in derselben Grafik und erhöhen leicht:

Ja! Jetzt ist alles klar! Wenn alles in Ordnung ist, ist S 64, und wenn der CO2-Sensor zu würfeln beginnt, fällt er auf 4. Mit S können Sie also herausfinden, wie gut sich der Sensor anfühlt und wie genau seine Messwerte sind.

Es bleibt, wie die Fallschirmjäger sagen, der Extremwert U:

Leider macht der Fokus mit der Überlagerung hier wenig. Es ist nur sichtbar, dass es, wie versprochen, am Anfang 15.000 entspricht und dann auf etwas mehr als 10.000 abfällt (aber es kann nach langer Zeit ein wenig fallen). Und einmal am Tag wiederholt sich der Zyklus.

Aber als ich die Sensorleistung nicht an 5, sondern an 3,3 Volt Arduino anschloss, änderte sich die Situation:

3,3 Volt am Arduino werden vom LP2985-Chip entnommen, der ein linearer Stabilisator mit 160 Milliampere ist. Und die Glühbirne frisst nach den Artikeln im Internet ungefähr so ​​viel. Beim Betrachten des Sensors fällt auf, dass die Glühbirne mit diesem Netzteil länger aufleuchtet als bei fünf Volt. Und der Wert von U ist eineinhalb Mal höher.

Die folgende Hypothese stellt sich heraus: Der Sensor ermittelt automatisch, wie lange es dauert, bis die Glühbirne angezündet ist, um genügend Infrarotstrahlung zu erhalten. Wenn nicht genügend Strom vorhanden ist, brennt er die Glühbirne länger. Und der Wert von U spiegelt nur die Brenndauer der Glühbirne wider (oder einen anderen verwandten Wert, zum Beispiel den Energieverbrauch).

Um diese Annahme zu testen, versorgen wir den Sensor mit einer Lithium-Ionen-Batterie, die offensichtlich einen viel größeren Strom erzeugen kann:

In der Tat fällt U manchmal unter 10.000! Dies ist jedoch offensichtlich kein absoluter Beweis, und nach 24 Stunden wird fast das Gegenteil. Die Hypothese bleibt also nur eine Hypothese, aber ich habe mir nichts Besseres ausgedacht.

UPD: Lieber unsvp noch gelöst , das Rätsel des Wertes von U. Ich gebe ihm das Wort:

Der Wert von U ist offensichtlich der Mindestwert der gemessenen Absorption von IR-CO2 pro Tag in einigen internen Maßeinheiten.

Nichts hinzuzufügen, außer vielleicht den Zeitplan:

Warum habe ich nicht selbst daran gedacht? Alles ist einfach. Ich habe ein Diagramm mit vier Werten gleichzeitig gezeichnet und mich darauf festgelegt. Es war jedoch notwendig, zwei Größen zu zeichnen (wie im obigen Bild), dann würde fremder Müll angesichts der Größe S die Wahrnehmung nicht beeinträchtigen. Wiederhole meine Fehler nicht.

Vielleicht füge ich Folgendes hinzu: Sehen Sie nach 48 Stunden einen Schritt größer als 1000 ppm? Dieser Sensor wird so automatisch kalibriert. In diesem Fall fiel der Wert von U im Vergleich zu dem vor der Kalibrierung. Es ist offensichtlich, dass die tatsächliche CO2-Konzentration in diesem Zeitraum nur zugenommen hat. Die Schlussfolgerung daraus ist sehr einfach: Der U-Wert ist kein sehr „roher“ Absorptionswert, sondern wird bereits für die aktuelle Kalibrierung angepasst berechnet, was anscheinend einen gewissen Unterschied in den Mindestwerten im aktuellen und vorherigen Kalibrierungszyklus darstellt.

Im Allgemeinen ist meiner Meinung nach die automatische Kalibrierung (zumindest in der Form, in der sie im MH-Z19 implementiert ist) böse. Revspace gibt an, dass es mit dem Befehl 0x79: ABC-Logik ein / aus deaktiviert werden kann.

/ UPD

Nun, mit einem Team erledigt. Es ist Zeit, weiter zu gehen, und dann nähert sich der Artikel dem Ende und weitere 255 Teams wurden nicht getestet!

Im Revspace-Artikel endet die Liste der getesteten Befehle wie folgt :

Befehl 0x89-0x8F
Es wird keine Antwort zurückgegeben, jedoch scheint der Befehl 0x8d den Sensor zurückzusetzen.

Befehl 0x99 (Bereich)
...

Außerdem werden nicht alle Teams mit niedrigeren Zahlen verifiziert. Somit bleibt etwas mehr als die Hälfte der Gesamtzahl unbekannter Teams übrig.

Ohne weiteres habe ich beschlossen, Befehle zufällig zu geben (genauer gesagt pseudozufällig). Und hier ist was ich habe:

...
Command: 255 1 47 0 0 0 0 0 208  Response: 0 0 0 0 0 0 0 0 0  CRC: 00 CO2/t/s/u: 0 0 0 0
Command: 255 1 17 0 0 0 0 0 238  Response: 0 0 0 0 0 0 0 0 0  CRC: 00 CO2/t/s/u: 0 0 0 0
Command: 255 1 45 0 0 0 0 0 210  Response: 0 0 0 0 0 0 0 0 0  CRC: 00 CO2/t/s/u: 0 0 0 0
Command: 255 1 5 0 0 0 0 0 250  Response: 0 0 0 0 0 0 0 0 0  CRC: 00 CO2/t/s/u: 0 0 0 0
Command: 255 1 88 0 0 0 0 0 167  Response: 0 0 0 0 0 0 0 0 0  CRC: 00 CO2/t/s/u: 0 0 0 0
Command: 255 1 245 0 0 0 0 0 10  Response: 0 0 0 0 0 0 0 0 0  CRC: 00 CO2/t/s/u: 0 0 0 0
Command: 255 1 107 0 0 0 0 0 148  Response: 0 0 0 0 0 0 0 0 0  CRC: 00 CO2/t/s/u: 0 0 0 0
Command: 255 1 214 0 0 0 0 0 41  Response: 0 0 0 0 0 0 0 0 0  CRC: 00 CO2/t/s/u: 0 0 0 0
Command: 255 1 136 0 0 0 0 0 119  Response: 0 0 0 0 0 0 0 0 0  CRC: 00 CO2/t/s/u: 0 0 0 0
Command: 255 1 7 0 0 0 0 0 248  Response: 0 0 0 0 0 0 0 0 0  CRC: 00 CO2/t/s/u: 0 0 0 0
Command: 255 1 153 0 0 0 0 0 102  Response: 255 153 1 0 0 0 0 0 102  CRC: 102102 CO2/t/s/u: 256 0 0 0
Command: 255 1 146 0 0 0 0 0 109  Response: 0 0 0 0 0 0 0 0 0  CRC: 00 CO2/t/s/u: 0 0 0 0
Command: 255 1 72 0 0 0 0 0 183  Response: 96 249 2 211 215 212 17 215 204  CRC: 159204 CO2/t/s/u: 723 215 212 4567
Command: 255 1 51 0 0 0 0 0 204  Response: 93 151 80 143 212 255 255 255 217  CRC: 185217 CO2/t/s/u: 20623 212 255 -1
Command: 255 1 98 0 0 0 0 0 157  Response: 16 136 252 75 66 50 48 48 13  CRC: 9313 CO2/t/s/u: -949 66 50 12336
Command: 255 1 65 0 0 0 0 0 190  Response: 10 0 0 0 0 0 0 0 0  CRC: 0 0 CO2/t/s/u: 0 0 0 0
Command: 255 1 243 0 0 0 0 0 12  Response: 0 0 0 0 0 0 0 0 0  CRC: 0 0 CO2/t/s/u: 0 0 0 0
Command: 255 1 13 0 0 0 0 0 242  Response: 0 0 0 0 0 0 0 0 0  CRC: 0 0 CO2/t/s/u: 0 0 0 0
Command: 255 1 35 0 0 0 0 0 220  Response: 0 0 0 0 0 0 0 0 0  CRC: 0 0 CO2/t/s/u: 0 0 0 0
Command: 255 1 229 0 0 0 0 0 26  Response: 0 0 0 0 0 0 0 0 0  CRC: 0 0 CO2/t/s/u: 0 0 0 0
Command: 255 1 95 0 0 0 0 0 160  Response: 0 0 0 0 0 0 0 0 0  CRC: 0 0 CO2/t/s/u: 0 0 0 0
Command: 255 1 48 0 0 0 0 0 207  Response: 0 0 0 0 0 0 0 0 0  CRC: 0 0 CO2/t/s/u: 0 0 0 0
Command: 255 1 209 0 0 0 0 0 46  Response: 0 0 0 0 0 0 0 0 0  CRC: 0 0 CO2/t/s/u: 0 0 0 0
Command: 255 1 200 0 0 0 0 0 55  Response: 0 0 0 0 0 0 0 0 0  CRC: 0 0 CO2/t/s/u: 0 0 0 0
...

Hier wurde der Befehl an den Sensor gesendet (die Befehlsnummer selbst ist die dritte Nummer von Anfang an). Die Antwort ist die Antwort des Sensors. Sie können den Rest nicht betrachten (CRC ist die berechnete / tatsächliche Prüfsumme, CO2 / t / s / u ist das Aufschlüsselungsergebnis Sensorantwort auf vier Zahlen, als würde sie auf einen "Standard" -Befehl reagieren).

Wie Sie sehen können, nicht viel. Darüber hinaus weigerte sich der Sensor irgendwann völlig, etwas anderes als Nullen auszugeben. Das Letzte, was ich vom Sensor bekam, war:

Command: 255 1 134 0 0 0 0 0 121  Response: 0 0 0 0 0 0 0 0 0  CRC: 0 0 CO2/t/s/u: 0 0 0 0
Command: 255 1 130 0 0 0 0 0 125  Response: 242 98 200 201 207 216 178 130 33  CRC: 50 33 CO2/t/s/u: -14135 207 216 -19838
Command: 255 1 134 0 0 0 0 0 121  Response: 204 91 151 80 143 212 255 255 236  CRC: 93 236 CO2/t/s/u: -26800 143 212 -1
Command: 255 1 200 0 0 0 0 0 55  Response: 181 156 252 77 79 68 66 85 83  CRC: 241 83 CO2/t/s/u: -947 79 68 16981
Command: 255 1 134 0 0 0 0 0 121  Response: 13 10 0 0 0 0 0 0 0  CRC: 246 0 CO2/t/s/u: 0 0 0 0
Command: 255 1 216 0 0 0 0 0 39  Response: 0 0 0 0 0 0 0 0 0  CRC: 0 0 CO2/t/s/u: 0 0 0 0

Und dann Nullen. Ich habe versucht, Befehle nacheinander einzugeben, beginnend mit 0x8e - wieder Nullen. Ich habe versucht, den "Standard" -Befehl 0x86 - Nullen zu geben. Habe ich den Sensor abgeschaltet? In Wahrheit sind alle Voraussetzungen dafür gegeben - ich gebe kleine undokumentierte Befehle ein, also verbinde ich auch die Sensorschnittstelle direkt mit dem Fünf-Volt-Arduin, obwohl das Datenblatt ausdrücklich angibt, dass es für 3,3 Volt ausgelegt ist.

Zuerst habe ich das gute alte Rezept eines jeden Enikeyshchik ausprobiert - schalte es aus und wieder ein. Das heißt, er nahm es heraus und steckte es an den Sensor plus Strom, während alles andere funktionierte. Der Sensor produzierte ungefähr das gleiche wie in der letzten zitierten Passage (jedoch mit leicht unterschiedlichen Zahlen). Ja, das bedeutet, dass der Sensor nicht vollständig abgestorben ist und bei jedem Start etwas sagt, vermuteten die Shtirlits.

Dann gab ich meinem Gehirn etwas mehr und vermutete noch vor einer Wahrheit - diese Nullen, die wir oben gesehen haben, sind überhaupt nicht die Antwort des Sensors. Tatsächlich ist der Sensor stumm und mein Programm zeichnet, was die Arduin-Funktion des Empfangens von n Bytes ausgegeben hat (um Nullen zu sagen). Und wenn jedes Mal vor dem Empfang sichergestellt wird, dass etwas zu nehmen ist, stellt sich heraus, dass es nichts zu akzeptieren gibt. Außer in Fällen, in denen der Sensor gerade neu gestartet wurde.

Es stellt sich heraus, dass der Sensor keine Befehle mehr akzeptiert. Anscheinend waren 5 Volt an der seriellen Schnittstelle nicht umsonst. Ja, der Artikel hat irgendwie nicht gefragt. Vielen Dank für Ihre Aufmerksamkeit. Wir sind uns nicht einig, es gibt nichts zu sehen.

Ah warte ...

Sehen Sie diese Zahlen am Ende?

13 10

Ähnelt nichts?

Dies ist natürlich ein guter alter Zeilenvorschub ! Mit anderen Worten, 0x0D 0x0A - dies ist die Methode zum Übersetzen einer Zeichenfolge, beispielsweise unter Windows (und unter Unix ist dies einfacher - 0x0A, da einige Dateien beim Öffnen in einem Windows-Notizbuch Zeilenumbrüche verlieren).

Vielleicht möchte der Sensor uns etwas in menschlicher Sprache sagen? Wenn diese Sprache jedoch Chinesisch ist, hilft es mir nicht viel. Hoffen wir also, dass dies eine verständlichere Sprache ist, und dekodieren Sie die Nachricht gemäß der ASCII- Tabelle :

print reduce(lambda a, b: a + b, map(lambda a: chr(int(a)), "255 255 255 250 24 220 207 254 77 79 68 66 85 83 13 10".split()))
        MODBUS

Erhielt bis zu sechs Briefe. Und hier ist, was derselbe Sensor beim Laden etwas früher sagte:

print reduce(lambda a, b: a + b, map(lambda a: chr(int(a)), "96 249 2 211 215 212 17 215 204  93 151 80 143 212 255 255 255 217  16 136 252 75 66 50 48 48 13  10 ".split()))
`        ] P         KB200

Der Unterschied liegt auf der Hand - Zeile KB200 wurde in Zeile MODBUS geändert. Der Rest - es scheint, dass es überhaupt kein Text ist, nicht einmal chinesische Schriftzeichen - schon allein deshalb, weil sich die meisten von Zeit zu Zeit ändern.

Was sagt uns der Sensor? Auf Anfrage von KB200 erzeugt eine Internetsuche eine Tastatur, einen Core-Sampler, ein Bügeleisen, einen Wickeltisch, eine Steuerung zur Steuerung von PTZ-Kameras und einen Mixer, mit Ausnahme einer kahlen. Nun, aber es ist nicht klar, wie dieses Wissen auf unseren Fall angewendet werden soll. Nun, suchen wir nach MODBUS. Diesmal steht Wikipedia selbst zu unseren Diensten :

Modbus ist ein offenes Kommunikationsprotokoll, das auf der Master-Slave-Architektur basiert. Es wird in der Industrie häufig zur Organisation der Kommunikation zwischen elektronischen Geräten verwendet. Es kann zur Datenübertragung über die seriellen Kommunikationsleitungen RS-485, RS-422, RS-232 sowie ein TCP / IP-Netzwerk (Modbus TCP) verwendet werden.

Die Hypothese selbst bietet sich an - nach einem der undokumentierten Befehle hat der Sensor auf das Modbus-Protokoll umgeschaltet und informiert uns nun mit den verfügbaren Methoden darüber. Da keine anderen Optionen vorgesehen sind, werden wir diese Hypothese direkt testen, dh versuchen, den Sensor über Modbus zu kontaktieren.

Im Internet wurde eine Modbus- Implementierung für Arduine gefunden . Aber das ist ein Pech - Arduino Leonardo wird nicht unterstützt, aber ich habe zufällig nur Leonardo.

Aber wie ich bald merkte, ist dies sogar das Beste. Das Modbus-Protokoll ist so einfach wie drei Cent. Und außerdem schmerzlich ähnlich dem "nativen" Protokoll MH-Z19. Warum also böse Dinge aus dem Internet ziehen und sie schmerzhaft verstehen, wenn Sie alles, was Sie brauchen, in zwei Minuten (also zwei Stunden) selbst implementieren können?

Um die Messwerte herauszufinden, haben wir den Sensor zuvor gebeten, sie wie folgt auszugeben:

0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79

Oder in Dezimalzahl:

255, 1, 134, 0, 0, 0, 0, 0, 121

Wobei 255 die magische Zahl ist, 1 die Sensoradresse ist, 134 der Befehl ist, 121 das Byte der Prüfsumme ist.

Und wie wird es in Modbus aussehen? Es wird keine genaue Übereinstimmung geben, aber Sie können zum Beispiel Folgendes tun:

1, 4, 0, 0, 0, 4, 213, 197

1 - Sensoradresse.

4 - Teamnummer. Befehle in Modbus können an den Fingern gezählt werden, und bisher werden wir nur an zwei von ihnen interessiert sein - 3 und 4. Aus Gründen, die im Dunkeln der Jahrhunderte verborgen sind, werden sie als Read Multiple Holding Registers und Read Input Registers bezeichnet, aber tatsächlich geben sie einen Befehl zum Lesen eines bestimmten Registers die Anzahl der Doppelbyte-Nummern an einer bestimmten Adresse. Befehl 3 liest die zum Lesen / Schreiben verfügbaren Zahlen und Befehl 4 liest nur.

0, 0 ist die Adresse, die wir lesen werden (in diesem Fall 0). Wenn Sie dieselbe Adresse mit einem Team von 3 oder 4 Personen festlegen, erhalten wir im Allgemeinen unterschiedliche Ergebnisse.

0, 4 - die Anzahl der Zahlen, die wir lesen möchten (in diesem Fall 4). Hier ist ein lustiger Moment. Obwohl Sie diese Nummer bis zu 65535 angeben können, können Sie mit dem Protokoll nicht mehr als 125 Nummern gleichzeitig lesen. Und das alles, weil die Antwort die Anzahl der Bytes der gesendeten Informationen angibt und nur ein Byte benötigt (und die Zahlen zwei Byte sind). Soweit ich weiß, ist die Länge der Antwort selbst auf 255 Byte begrenzt.

213, 197 - zwei Bytes einer Prüfsumme ( CRC16 ). Im Allgemeinen ist dies der schwierigste Moment in unserer gesamten Implementierung. In Wahrheit habe ich mich nicht einmal damit befasst, wie es betrachtet wird, sondern einfach den Code von hier kopiert . Da es ein Meer verschiedener CRC16 gibt, muss man sich der Wahl der Funktion verantwortungsbewusst nähern. Überprüfen Sie, ob eine bestimmte Funktion für Modbus geeignet ist, z.hier .

Das ist in der Tat alles, was wir über Modbus wissen müssen. Zumindest für den Anfang.

Sie haben zwar lange vermutet, dass mein Appell an den MH-Z19 auf Modbus ein Erfolg war, aber tun wir so, als ob die Intrige bestehen bleibt. Bisher wissen wir noch nicht einmal, wie unsere Sensoradresse lautet (obwohl es "im Original" 1 ist, ist es weit davon entfernt, dass es bei Modbus dasselbe ist). Sie müssen den Befehl also mit verschiedenen Adressen wiederholen (und es gibt nur 255 davon) und sehen, auf was unser Sensor reagiert:

...
Command: 254 4 0 3 0 1 213 197  CRC: 213 197 Response: 
Command: 255 4 0 3 0 1 212 20  CRC: 212 20 Response: 
Command: 0 4 0 3 0 1 192 27  CRC: 192 27 Response: 
Command: 1 4 0 3 0 1 193 202  CRC: 193 202 Response: 
Command: 2 4 0 3 0 1 193 249  CRC: 193 249 Response: 1 132 2 194 193 
Command: 3 4 0 3 0 1 192 40  CRC: 192 40 Response: 
Command: 4 4 0 3 0 1 193 159  CRC: 193 159 Response: 
...

Es scheint, dass die Adresse 2 ist. Ich wiederhole mehrere Befehle mit Adresse 2 - es gibt keine Antwort. Ich ändere die Adresse auf 1 - es gibt eine Antwort! Somit ist die Sensoradresse dieselbe wie sie war - 1.

Und warum erschien die Adresse 2 in der obigen Passage? Auch hier kriecht die Hinduness meines Codes heraus. Nach der Ausgabe des Befehls überprüfe ich, ob Bytes zu empfangen sind. Da ich dies jedoch sofort mache, hat der Sensor keine Zeit, etwas zu senden, sodass die Sensorantwort erst im nächsten Zyklus vom Programm akzeptiert wird. Wie Sie im angegebenen Protokoll sehen können, ist die erste Zahl in der Antwort 1 und gibt nur die Adresse des Sensors an. Ich habe dieses Problem umgangen, indem ich einfach eine Verzögerung von 50 Millisekunden hinzugefügt habe, bevor ich eine Antwort erhalten habe.

Betrachten Sie die Sensorreaktion auf unseren Befehl:

1 132 2 194 193

1 - wie wir bereits herausgefunden haben - die Adresse des Sensors.

132 - Befehlscode und Fehlercode. Wenn es keinen Fehler gäbe, wäre diese Nummer dieselbe wie der gesendete Befehl - das ist 4. Es ist jedoch ein Fehler aufgetreten, wie durch das höchstwertige Bit auf 1 angezeigt, sodass die Nummer 4 + 128 = 132 wurde. Ein Befehl in Modbus darf keine Nummer größer als 127 haben. Für einen solchen Befehl entspricht der Erfolgscode dem Fehlercode.

2 - Fehlercode. Sagt genau, welcher Fehler aufgetreten ist. Wie Wikipedia sagt, 02 - Die in der Anfrage angegebene Datenadresse ist nicht verfügbar. An dieser Adresse gibt es also keinen Fisch und es gibt nichts zu fangen. Wir werden andere Adressen ausprobieren.

194 193 - CRC16.

Jetzt ist es endlich Zeit, den Adressraum des Sensors zu zerkratzen, um zu verstehen, wo sich der Fisch befindet. Ich habe das einfach gemacht - ich habe einen Befehl gesendet, alle 0,1 Sekunden eine Nummer mit einer neuen Adresse zu lesen. Da die Adressen 65536 sind, ist dieser Vorgang in ungefähr zwei Stunden abgeschlossen. Die Ergebnisse sind kurz wie folgt:

Befehl 1 (Read Coils) - mit einem beliebigen Adressfehler 2.
Team 2 (Read Discrete Inputs) - mit einem beliebigen Adressfehler 2.
Befehl 4 (Read Input Registers) - mit einem beliebigen Adressfehler 2.
Befehl 3 (Read Multiple) Holding Registers) - gibt Erfolg bei Adressen von 0 bis 289.
Befehle zum Schreiben von Werten (z. B. 6) scheinen zu funktionieren, aber es scheint, dass der aufgezeichnete Wert bald durch den Wert ersetzt wird, der er war. Aber ich habe dieses Problem nicht genau untersucht.

Der Suchkreis verengt sich also - wir benötigen Zahlen bei Befehl 3 und Adressen von 0 bis 289. Die Idee der reichen inneren Welt des Sensors kann aus diesen Zeilen erhalten werden:

Command: 1 3 0 0 0 64 68 58  CRC: 68 58 Response: 1 3 128 0 0 0 255 0 1 0 1 0 255 0 255 0 255 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 158 124 
Command: 1 3 0 64 0 64 69 238  CRC: 69 238 Response: 1 3 128 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 27 165 
Command: 1 3 0 128 0 64 69 210  CRC: 69 210 Response: 1 3 128 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 73 82 0 153 0 8 0 17 0 177 0 19 0 19 0 196 0 18 0 20 0 214 0 18 0 21 0 232 0 18 0 22 0 250 0 5 0 24 0 255 0 5 0 18 1 4 0 3 0 23 1 7 0 25 0 0 0 0 0 0 0 0 0 0 0 255 0 255 0 1 0 0 0 5 0 0 0 0 0 0 0 0 0 0 137 122 
Command: 1 3 0 192 0 64 68 6  CRC: 68 6 Response: 1 3 128 165 165 0 165 0 0 255 255 255 255 255 255 255 255 0 15 3 232 0 100 0 90 0 0 0 63 128 0 0 255 0 15 0 5 0 10 0 5 0 5 0 30 0 15 0 0 0 20 0 40 0 60 0 80 0 100 0 0 0 5 0 5 3 232 255 255 255 255 165 165 0 165 0 0 16 3 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 163 198

Richtig, Zahlen wurden im Archiv nur unter der Adresse 255 gespeichert. Auch hier ist 1 3 die Adresse und der Befehl, 128 die Anzahl der übertragenen Bytes, zwei Bytes am Ende sind CRC und alles andere ist der Inhalt des Speichers.

Von all dieser Pracht interessieren uns offensichtlich diejenigen Adressen, deren Inhalt sich im Laufe der Zeit ändert. Und hier stellte sich heraus, dass der Sensor zwei Neuigkeiten für mich war - gut und schlecht. Gut - es gibt solche Adressen. Und die schlechten - es gibt nur zwei von ihnen - 261 und 264. Vergleichen Sie mit dem „vergangenen Leben“, als vier Nummern gleichzeitig auf einen Befehl gegeben wurden! Ich rollte bereits mit der Lippe - ich dachte, ich würde Zugriff auf alle internen Variablen bekommen. Nun, zwei so zwei.

Zeit, wieder Diagramme zu erstellen!

Wert an Adresse 261:

Es sieht aus wie eine CO2-Konzentration. Es ist zu sehen, als ich versuchte, auf dem Sensor zu atmen. Der Minimalwert liegt zwar deutlich unter dem "Referenzwert" von 400 ppm, so dass die Kalibrierung zu wünschen übrig lässt. Auf die eine oder andere Weise wird der Sensor für wiederbelebt erklärt.

Wert bei 264:

Ungefähr gleich, nur in einem anderen Maßstab und verkehrt herum.

Und beide Größen befinden sich in derselben Grafik:

Es stellt sich natürlich die Frage, ob eine dieser Größen der sehr „rohe“ Wert ist, der vom ADC stammt und den der Sensor auf eine Slave-Weise in die CO2-Schätzung umwandelt. In diesem Fall ergeben sich große Möglichkeiten zur Neukalibrierung und Verbesserung der Genauigkeit des Sensors und möglicherweise zur Verwendung für andere Zwecke. Die Antwort auf diese Frage (und einige andere) werden wir in der nächsten Serie versuchen.

Die Kommentare und Vorschläge werden akzeptiert - wie man den MH-Z19 sonst im nächsten Artikel verspottet. Es stimmt, ich werde nichts versprechen.

Source: https://habr.com/ru/post/de401363/


All Articles