Betriebsdaten eines Wechselrichters über UART auslesen

romeo

Neues Mitglied
11. Juli 2008
19
0
0
Sprachen
Hallo,

ich beschäftige mich gerade damit, einen meiner Wechselrichter, welcher eine RS232 Schnittstelle besitzt mit einem Atmega8 auszulesen.

Hab mir dazu die Bedienungsanleitung des Gerätes angesehen in welcher die Parameter für die Verbindung angegeben sind:

Baudrate: 9600
Datenbits: 8
Parität: Keine
Stopbits: 1
Protokoll: Kein

Ausserdem wird auch noch eine Beispiel-Übertragung abgebildet:

bedienungsanleitungpe6.jpg


Hab mir also mein µC-Lehrbuch (Roland Walter) zur Hand genommen und das Kapitel UART durchgelesen. Nun bin ich soweit gekommen das ich die Daten des Wechselrichters einlese und diese weiter an den PC sende wo sie mit einem Terminal Programm angezeigt werden, was folgendermaßen aussieht:

empfangenif2.jpg


Sieht also schonmal sehr gut aus, verwendet habe ich dazu folgendes Listing:

listeningib2.gif


Ok, soweit so gut. Nun, mein Ziel ist es erstmal die Daten auf einem Display auszugeben. Jetzt schwieren mir folgende Fragen im Kopf rum:

- Wie lange (Byte) sind die empfangenen Daten?
- Wie kann ich das empfangene jetzt auseinander trennen um es weiter zu verarbeiten? (Sind 10 Werte, siehe erstes Bild)
- Gibt es bessere Methoden die Werte auszulesen?

Hab schon nach einer Lösung gesucht und es sollte ungefähr so hinhauen: Die Empfangenen Daten bestehen ja aus mehreren Bytes, diese werden hintereinander in eine Variable geschrieben. Mit Hilfe von Overlay-Variablen kann man dann die Variable auftrennen/aufteilen.

Ist das der richtige Weg, oder liege ich total falsch?

Gruß und danke!
 
Also um mein Problem nochmal etwas genauer zu beschreiben, habe ich eine kleine Grafik erstellt:

wclfv0.jpg


- Der Wechselrichter sendet alle 10 Sekunden einen Code, in welchen die aktuellen Betriebsdaten angegeben sind (Datum, Uhrzeit, Spannungen...)

- Diesen Code würde ich gerne mit dem Mikrocontroller empfangen und in die jeweiligen Werte aufteilen (Eine Variable für Datum, eine Variable für Uhrzeit, eine für Spannung, eine für Strom...)

Welche Methode für den Datenempfang wär hier dann am besten angebracht, es gibt ja mehrere (Input, UDR auslesen, mit und ohne Interrupt, gepuffert...)

Am einfachsten wäre es ja, wenn ich die Empfangenen Daten erst einmal in einen String speichern würde oder? Woher weiß ich dann wie lange mein String sein muss? Anschließen zerlegt man diesen String dann mit Overlay Variablen oder?

Ich wär echt über jede Hilfe und Ratschlag dankbar!

Gruß!
 
Hallo Romeo!

Ich kann kein BASCOM, aber da ich gerne mal mit Perl (Linux) Logdaten analysiere,
kann ich evtl ein paar Tips liefern ... :)

Der Wechselrichter sendet alle 10 Sekunden einen Code, in welchen die aktuellen Betriebsdaten angegeben sind (Datum, Uhrzeit, Spannungen...)
Der Wechselrichter liefert also alle 10sec von sich aus ohne Anstoß die Daten.

Diesen Code würde ich gerne mit dem Mikrocontroller empfangen und in die jeweiligen Werte aufteilen (Eine Variable für Datum, eine Variable für Uhrzeit, eine für Spannung, eine für Strom...)
Ich würde im Eingangs-Datenstrom auf CRLF (CariageReturn/LineFeed) oder etwas
ähnliches triggern. Anscheinend sind die Datensätze ja als Zeilen getrennt, wenn man
deinen ersten Eintrag ansieht.
Code:
00.00.0000 00:05:30   4   363.8   0.37   134   226.1  0.53   103   23 

00.00.0000<sp>00:05:30<tab>4<tab>363.8<tab>0.37<tab>134<tab>226.1<tab>0.53<tab>103<tab>23<cr><lf>
Die zweite Zeile ist jetzt mal ne Annahme. Ich würde dafür die Daten mal mit nem
Terminalprogramm in ne Logdatei schreiben lassen und mit nem Hexeditor nachsehen,
was da wirklich ankommt.

Man könnte also folgendes annehmen ...
Datum/Uhrzeit : 19 Zeichen danach <tab>
Betriebsart : 1 Zeichen danach <tab>
Spannung : 5 Zeichen danach <tab>
Strom : 4 Zeichen danach <tab>
...
Zum Schluß ein <CR><LF> (0x0D 0x0A)
Die Datensätze sind also wie bei CSV-Dateien eine Trennzeichen separierte Liste
oder eine Liste mit fester Spaltenbreite.

Also den eingehenden Datenstrom bis zum Zeilenende (crlf) in einen String schreiben
und danach (als Trigger crlf verwenden) in eine Auswerteroutine gehen, die den
String an den Tabs trennt und in einzelne Stringvariablen aufteilt.
Eventuell hat man aber keine Tabs sondern mehrere Leerzeichen. Dann muß man alle
Gruppen von Leerzeichen zu einem zusammenschmelzen (da gibt es unter Perl
schöne Befehle für - unter BASCOM ???) und dann an diesen Leerzeichen den String
trennen und wieder in einzelnen Stringvariablen ablegen.
Zum Schluß die einzelnen extrahierten ASCII-kodierten Werte in "richtige" Zahlenwerte
umwandeln. Dann kann man damit auch rechnen. Geht glaube ich unter Basic mit
VALUE oder VAL oder sowas.

Welche Methode für den Datenempfang wär hier dann am besten angebracht, es gibt ja mehrere (Input, UDR auslesen, mit und ohne Interrupt, gepuffert...)
??? Ich programmier das Teil in Assembler :D

Am einfachsten wäre es ja, wenn ich die Empfangenen Daten erst einmal in einen String speichern würde oder? Woher weiß ich dann wie lange mein String sein muss? Anschließen zerlegt man diesen String dann mit Overlay Variablen oder?
Wie gesagt, erst mal sehen wie die Daten in ihrer ganzen Schönheit (Hexeditor)
wirklich aussehen.
Bei ner Liste mit fester Spaltenbreite (also nur Spaces zur Trennung) kennst Du dann
schon die Stringlänge. Da ändert sich auch nix mehr. Deine Werte sind in der Liste
dann wohl rechts-bündig eingetragen und wandern in die links neben dem Wert stehenden
Spaces ein.
Code:
44    44.3
44   345.6
22  1234.5
Also werden mit längerwerdendem Wert die Trenn-Spaces weniger.

Bei ner TAB-separierten Liste würde ich die maximal möglichen Wertlängen plus die Trenn-TABs
als Stringlänge ansehen.

Ich wär echt über jede Hilfe und Ratschlag dankbar!
Ich hoffe mal, es hilft, damit du jetzt Rad-Schlagen (aua) kannst :D

Gruß
Dino
 
Super, danke!

Hab das jetzt genauso gemacht wie du gesagt hast und dabei ist folgendes rausgekommen (Obere Zeile vom Terminalprogramm, untere von mir übersetzt):

Code:
0a 30 34 2e 31 31 2e 32 30 30 38 20 31 30 3a 30 36 3a 34 30 20 20 20 34 20 35 33 38 2e 30 20 20 30 2e 36 31 20 20 20 33 32 38 20 32 33 31 2e 31 20 20 31 2e 32 32 20 20 20 32 36 39 20 20 33 35 20 0d

LF  0  4  .  1  1  .  2  0  0  8 SPC 1  0  :  0  6  :  4  0 SPCSPCSPC 4 SPC 5  3  8  .  0 SPCSPC 0  .  6  1 SPCSPCSPC [COLOR="DarkOrchid"]3  2  8[/COLOR] SPC 2  3  1  .  1 SPCSPC 1  .  2  2 SPCSPCSPC [COLOR="#9932cc"]2  6  9 [/COLOR]SPCSPC 3  5 SPC CR

Somit müsste meine Stringlänge 66 Bytes sein.

In diesem Code wird auch die Leistung welche von der Photovoltaikanlage erbracht wird angegeben (oben 328 W und 269 W, lila markiert). Diese Leistungen können aber locker über 1000 W betragen. Ist das der Fall wird mein String um zwei Stellen länger, also 68 Bytes.

Dieses Problem sollte man so lösen können oder?:

1. Einen String mit 68 Bytes erstellen (Dim s As String*68)

2. Die empfangenen Bytes nacheinander in den String schreiben

3. Die länge des Strings überprüfen, wenn er 66 Bytes erreicht hat noch kurz warten, Falls die Leistung über 1000 W ist und somit noch zwei weitere Bytes übertragen werden

If Len(s) >66 Then
Wait 1
Print s

Eine Sekunde sollte locker ausreichen um die 2 Bytes zu empfangen und da der Wechselrichter nur alle 10 Sekunden sendet ist auch die Gefahr ausgeschlossen das Daten überschrieben werden bevor sie weitergeschickt werden.

Würde das so hinhauen?

Und wie Trenne ich dann einen String auf? Damit ich alle Daten einzeln habe? Optimal wäre es wenn eine Variable für Datum, eine für Uhrzeit, eine für Spannung usw. entstehen würde. Bei der Methode mit Overlay-Variablen habe ich ja für jedes zeichen eine extra Variable also insgesamt 68 Variablen oder?

Vielen dank!
 
Hi Romeo!

Hab das jetzt genauso gemacht wie du gesagt hast und dabei ist folgendes rausgekommen (Obere Zeile vom Terminalprogramm, untere von mir übersetzt):
Code:
0a 30 34 2e 31 31 2e 32 30 30 38 20 31 30 3a 30 36 3a 34 30 20 20 20 34 20 35 33 38 2e 30 20 20 30 2e 36 31 20 20 20 33 32 38 20 32 33 31 2e 31 20 20 31 2e 32 32 20 20 20 32 36 39 20 20 33 35 20 0d

LF  0  4  .  1  1  .  2  0  0  8 SPC 1  0  :  0  6  :  4  0 SPCSPCSPC 4 SPC 5  3  8  .  0 SPCSPC 0  .  6  1 SPCSPCSPC [COLOR="DarkOrchid"]3  2  8[/COLOR] SPC 2  3  1  .  1 SPCSPC 1  .  2  2 SPCSPCSPC [COLOR="#9932cc"]2  6  9 [/COLOR]SPCSPC 3  5 SPC CR
Somit müsste meine Stringlänge 66 Bytes sein.
Sieht ganz danach aus ;) Und man erkennt, das es sich um ne Liste mit festen
Spaltenbreiten handelt. Darum auch teilweise die 2 oder 3 Spaces.

In diesem Code wird auch die Leistung welche von der Photovoltaikanlage erbracht wird angegeben (oben 328 W und 269 W, lila markiert). Diese Leistungen können aber locker über 1000 W betragen. Ist das der Fall wird mein String um zwei Stellen länger, also 68 Bytes.
Das glaube ich nicht. Wegen fester Spaltenbreite :D
Das wird dann wohl so aussehen ...
Code:
 2  2 SPCSPCSPC [COLOR="#9932cc"]2  6  9 [/COLOR]SPCSPC
 |  |  |  |  |  |  |  |  |  |  
 2  2 SPCSPC [COLOR="#9932cc"]1  2  6  9 [/COLOR]SPCSPC
Es wird also die Zahl rechtsbündig in der Spalte stehen bleiben und die
davorstehenden Spaces werden weniger.

Dieses Problem sollte man so lösen können oder?:
1. Einen String mit 68 Bytes erstellen (Dim s As String*68)
2. Die empfangenen Bytes nacheinander in den String schreiben
....
....
Würde das so hinhauen?
Ich glaube, es gibt gar kein Problem :cool:

Und wie Trenne ich dann einen String auf? Damit ich alle Daten einzeln habe? Optimal wäre es wenn eine Variable für Datum, eine für Uhrzeit, eine für Spannung usw. entstehen würde. Bei der Methode mit Overlay-Variablen habe ich ja für jedes zeichen eine extra Variable also insgesamt 68 Variablen oder?
Waaaaahhh :banghead: 68 Variablen ???
Schneide den String doch einfach mit fester Länge klein. Da gibt es doch sowas wie
MIDSTRING, LEFTSTRING, RIGHTSTRING ... oder so ähnlich ... wenn ich mich
richtig erinnere ..

also teil$ = MID(gesamt$,start,länge)

oder sowas (gibt es das in BASCOM ???)

Mach es dir doch nicht so kompliziert :stop: !

Code:
  chomp ($zeile);            # Zeilenende entfernen
  $zeile =~ s/ +/ /g;        # Alle Leerzeichen durch eins ersetzen
  ($datum,$zeit,$art,Spannung,$strom,$wert6,$wert7,$wert8,$wert9,$wert10) = split(/ /,$zeile);
Das Beispiel würde auf jeden Fall in Perl so funktionieren.
Oder auch so ..
Code:
 $datum = substr( $zeile, 0, 10);         #  tt.mm.jjjj
 $zeit = substr( $zeile, 11, 8);         #  -hh:mm:ss
 $art = substr( $zeile, 19, 5);         #  ----a
Die Minus-Zeichen stehen jetzt mal für die Leerzeichen. Die müßte man danach
noch entfernen. Auf jeden Fall sind die Teilbereiche der Zeile schon mal in einzelnen
Strings.

So geht das .... :to_pick_ones_nose:

Sieht doch garnicht so schwer aus :D

Nun mußt Du den Kram nur noch in Bascom umsetzen ...

Gruß
Dino
 
Hallo Dino03! Nochmals herzlichen Dank für deine Hilfe, jetzt hat alles wunderbar geklappt!
 

Anhänge

  • firsttrywechselrichter.JPG
    firsttrywechselrichter.JPG
    20,3 KB · Aufrufe: 25
Hab eine kurze Frage zur seriellen Datenübertragung und wollt nicht extra einen neuen Thread aufmachen, deswegen hier in meinen alten.

Und zwar geht es darum, wie sendet man einen Ascii Wert? Ich würde gerne folgende Ascii Zeichen senden:

...42 46 44 30 36 1A

Hierfür bräuchte ich ja eigentlich nur "BFD06" senden, das Problem ist das letzte Zeichen, 1A, hierbei handelt es sich um "sub" (strg+Z). Kann mir einer sagen wie ich das sende?

Achja, in Bascom bräucht ich die Lösung. Danke!
 
Ich brauch die Lösung für ein Geburtstagsgeschenk, deswegen eilts ein bisschen, sorry für Doppelpost.

Also es geht um folgendes Zeichen:

character.JPG


Wie sende ich das per UART?
 
Die Lösung ist ganze einfach:

Print Chr(ascii-zeichen)

Danke für eure tolle Hilfe :rolleyes:
 
Sorry Romeo,

habs leider auch übersehen! War gestern und heute ziemlich busy nur nur Minutenweise im Forum. So ich ich gesehen habe bist Du aber selbst auf die Lösung gekommen. Glückwunsch!

Grüße,
Markus
 
Passt schon, ich war nur ein bisschen gestreßt weil es sich um ein Geburtstagsgeschenk für heute Abend handelt und ich nur an dieser Kleinigkeit hängen blieb. Ja die Lösung hab ich dann selber gefunden nur leider hab ich dafür 3 Stunden im Internet gesucht, obwohls so simple ist. Jetzt wo ichs weiß wies funktioniert finde ich die Lösung überall^^
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)