Stromzähler 400A IR Schnittstelle ABB b24 b23 b21 M-Bus

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Stromzähler 400A IR Schnittstelle ABB b24 b23 b21 M-Bus

      Source Code

      1. $regfile = "m168pdef.dat"
      2. $crystal = 16000000
      3. '$hwstack = 150
      4. ' $swstack = 150
      5. '$framesize = 10
      6. Config Com1 = 9600 , Synchrone = 0 , Parity = Even , Stopbits = 1 , Databits = 8 , Clockpol = 0
      7. Enable Interrupts
      8. On Urxc Onrxd
      9. Enable Urxc
      10. Dim Bytezaehler As Integer
      11. Bytezaehler = 1
      12. Dim Anfrage As String * 6
      13. Dim Anfrage2 As String * 6
      14. Dim Anfrage3 As String * 6
      15. Dim I As Integer
      16. Dim Zeichen As String * 400
      17. Dim Bytezeichenarray(400) As Byte At Zeichen Overlay
      18. Dim Spannungl1(2) As Byte
      19. Dim Wspannungl1 As Word At Spannungl1 Overlay
      20. Dim Single_spannungl1 As Single
      21. Dim Spannungl2(2) As Byte
      22. Dim Wspannungl2 As Word At Spannungl2 Overlay
      23. Dim Single_spannungl2 As Single
      24. Dim Spannungl3(2) As Byte
      25. Dim Wspannungl3 As Word At Spannungl3 Overlay
      26. Dim Single_spannungl3 As Single
      27. Dim Dwamperel1 As Dword
      28. Dim Amperel1(4) As Byte At Dwamperel1 Overlay
      29. Dim Single_amperel1 As Single
      30. Dim Dwamperel2 As Dword
      31. Dim Amperel2(4) As Byte At Dwamperel2 Overlay
      32. Dim Single_amperel2 As Single
      33. Dim Dwamperel3 As Dword
      34. Dim Amperel3(4) As Byte At Dwamperel3 Overlay
      35. Dim Single_amperel3 As Single
      36. Dim Dwtotalwatt As Dword
      37. Dim Btotalwatt(4) As Byte At Dwtotalwatt Overlay
      38. Dim Single_totalwatt As Single
      39. Dim Herz(2) As Integer
      40. Dim Skilowattstunden As String * 12
      41. Dim Bkilowattstunden(12) As Byte At Skilowattstunden Overlay
      42. Do
      43. Zeichen = ""
      44. Bytezaehler = 1
      45. Anfrage = Chr(&H10) + Chr(&H40) + Chr(&Hfe) + Chr(&H3e) + Chr(&H16)
      46. Serout Anfrage , 0 , C , 0 , 9600 , 1 , 8 , 1
      47. Waitms 1000
      48. Anfrage2 = Chr(&H10) + Chr(&H7b) + Chr(&Hfe) + Chr(&H79) + Chr(&H16)
      49. Serout Anfrage2 , 0 , C , 0 , 9600 , 1 , 8 , 1
      50. Waitms 1000
      51. Anfrage3 = Chr(&H10) + Chr(&H5b) + Chr(&Hfe) + Chr(&H59) + Chr(&H16)
      52. Serout Anfrage3 , 0 , C , 0 , 9600 , 1 , 8 , 1
      53. Waitms 1000
      54. ' For I = 1 To Bytezaehler
      55. ' Print I ;
      56. ' Print " ";
      57. ' Print Chr(bytezeichenarray(i)) ;
      58. ' Next I
      59. Print "Voltage L1>N"
      60. Spannungl1(1) = Bytezeichenarray(200)
      61. Spannungl1(2) = Bytezeichenarray(201)
      62. Single_spannungl1 = Wspannungl1 / 10
      63. Print Fusing(single_spannungl1 , "#.#");
      64. Print " V"
      65. Print "Voltage L2>N"
      66. Spannungl2(1) = Bytezeichenarray(210)
      67. Spannungl2(2) = Bytezeichenarray(211)
      68. Single_spannungl2 = Wspannungl2 / 10
      69. Print Fusing(single_spannungl2 , "#.#");
      70. Print " V"
      71. Print "Voltage L3>N"
      72. Spannungl3(1) = Bytezeichenarray(220)
      73. Spannungl3(2) = Bytezeichenarray(221)
      74. Single_spannungl3 = Wspannungl3 / 10
      75. Print Fusing(single_spannungl3 , "#.#");
      76. Print " V"
      77. Print "Frequenz"
      78. Herz(1) = Makedec(bytezeichenarray(289) )
      79. Herz(2) = Makedec(bytezeichenarray(288) )
      80. Print Herz(1);
      81. Print ".";
      82. Print Herz(2);
      83. Print " Hz"
      84. Print "AmpereL1"
      85. Amperel1(1) = Bytezeichenarray(260)
      86. Amperel1(2) = Bytezeichenarray(261)
      87. Amperel1(3) = Bytezeichenarray(262)
      88. Amperel1(4) = Bytezeichenarray(263)
      89. Single_amperel1 = Dwamperel1 / 1000
      90. Print Fusing(single_amperel1 , "#.###");
      91. Print " A"
      92. Print "AmpereL2"
      93. Amperel2(1) = Bytezeichenarray(270)
      94. Amperel2(2) = Bytezeichenarray(271)
      95. Amperel2(3) = Bytezeichenarray(272)
      96. Amperel2(4) = Bytezeichenarray(273)
      97. Single_amperel2 = Dwamperel2 / 1000
      98. Print Fusing(single_amperel2 , "#.###");
      99. Print " A"
      100. Print "AmpereL3"
      101. Amperel3(1) = Bytezeichenarray(280)
      102. Amperel3(2) = Bytezeichenarray(281)
      103. Amperel3(3) = Bytezeichenarray(282)
      104. Amperel3(4) = Bytezeichenarray(283)
      105. Single_amperel3 = Dwamperel3 / 1000
      106. Print Fusing(single_amperel3 , "#.###");
      107. Print " A"
      108. Print "TotalEnergy"
      109. Btotalwatt(1) = Bytezeichenarray(163)
      110. Btotalwatt(2) = Bytezeichenarray(164)
      111. Btotalwatt(3) = Bytezeichenarray(165)
      112. Btotalwatt(4) = Bytezeichenarray(166)
      113. Single_totalwatt = Dwtotalwatt / 100
      114. Print Fusing(single_totalwatt , "#.##");
      115. Print " W"
      116. Print "Kilowattstunden"
      117. Bkilowattstunden(1) = Makedec(bytezeichenarray(24)) 'Nachkommastellen
      118. Bkilowattstunden(1) = Str(bkilowattstunden(1))
      119. Bkilowattstunden(2) = Makedec(bytezeichenarray(25))
      120. Bkilowattstunden(3) = Makedec(bytezeichenarray(26))
      121. Bkilowattstunden(4) = Makedec(bytezeichenarray(27))
      122. Bkilowattstunden(5) = Makedec(bytezeichenarray(28))
      123. Print Skilowattstunden ;
      124. Print " kW/h"
      125. Loop
      126. Onrxd:
      127. Bytezeichenarray(bytezaehler) = Udr
      128. Bytezaehler = Bytezaehler + 1
      129. Return
      Display All
      Hallo zusammen,
      ich lese mit einem AVR die IR-Schnittstelle eines Wandler-Stromzählers aus.
      Soweit funktioniert alles super.
      Bei den Kilowattstunden habe ich jedoch Probleme.

      Der Zähler hat bisher 00,06Kw/h auf der "Uhr".
      Wenn ich zB. den Wert der Nachkommastellen in BCD decodiere und in ein anderes Datenformat lege,
      tilgt er mir die Null.
      Ich bekomme es seit 2h nicht elegant gelöst.
      Es kann natürlich auch sein, dass ich das Datenblatt nicht richtig interpretiert habe.

      Bisher nehme ich an, dass ich jeded Byte in BCD-Werte decodiere und dann zusammenflicke.

      zB: &h06 KOMMA &h66 &h55 &h44 &h33 > Dezimal 33445566,06
      Damit mir der Printbefehl nicht wieder Nullen entsorgt, möchte ich alles in einem String haben, um dies zu vermeiden.
      Files
    • sk8erboi wrote:

      Print " kW/h"
      Das tut weh.

      kWh ist die Einheit der Energie, nicht kW pro Stunde.


      Dein Skilowattstunden ist ein Overlay auf dein Bkilowattstunden Array.
      Wird das in der richtigen Reihenfolge ausgegeben bei Print?

      Wenn du nur printen willst dann kannst du ja mit ein paar Ifs die Ausgabe korrigieren.
      Wenn du mit dem Wert rechnen willst, solltest du das auch in eine entsprechend große Variable packen.

      *
      Dim Fuehrendenullen as bit

      Fuehrendenullen = 0
      For i = 5 to 2 step -1
      If Bkilowattstunden(i) > 0 Then Fuehrendenullen = 1
      If Fuehrendenullen = 1 Then
      If Bkilowattstunden(i) < 10 Then

      Print "0"

      End if
      Print Bkilowattstunden(i)

      End If
      Next
      Print ","

      If Bkilowattstunden(1) < 10 Then
      Print "0"
      End if
      Print Bkilowattstunden(1)
    • ich habe mich etwas belesen und unter Kapitel 4 etwas über nibbles gefunden. dl6gl.de/jonglieren-mit-bits.html
      Wohl genau das, was ich brauche.
      Ich trenne den Hexwert eines Bytes in zwei variablen und füge sie mit overlay in einen String zusammen. Dann dürften die Nullen erhalten bleiben.

      Alternativ zum "and" und shiften, könnte ich die Bits des Bytes in zwei Hilfsbytes an entsprechender Position kopieren.
      Quellenbyte.0=zielbytelow.0
      Quellenbyte.1=zielbytelow.1
      ....
      Quellenbyte.4=zielbytelow.3
      Quellenbyte.5=zielbytehigh.0
      ....
      Quellenbyte.7=zielbytehigh.3
      Dann:
      Sting besteht dann aus zielbytehigh,zielbyteLow usw



      Musste eigentlich so gehen, oder?
    • Den String brauche ich, weil ich nicht weiß wie ein single aufgebaut ist. Wie Bytes im single angeordnet sind. Word,dword sind mir geläufig. Die kann ich mit Bits und Bytes zuordnen.
      Single benötige ich wegen der Größe und den Nachkommastellen.
      Zudem würde ich gerne in Zukunft ressourcenschonend und sauberer arbeiten. Das overlay gefällt mir da sehr gut. Der String wird von mir sonst absolut nicht benötigt. Das war bisher nur immer Mittel zum Zweck um in andere Datentypen zu springen.

      The post was edited 1 time, last by sk8erboi ().

    • Wenn du Ressourcen sparen willst, dann solltest du auf Single verzichten.
      Für Nachkommastellen würde ich in deinem Fall den Wert um 100 oder 1000 erweitern und als Ganzzahl speichern.
      Single sind immer eine Näherung, für Sinusberechnungen z.B. ok, aber in deinem Fall ungeeignet.
      Ein Array auf einen String zu "overlayen" ist möglich, aber in deinem Fall aufwändig in der Nachbearbeitung wegen Ascii-Wandlung und Terminierung.

      Ist deine Grafik oben korrekt?
      Wenn ja, dann ist die Umwandling in BCD nichtgut, da ja schon BCD vorliegt.
    • sk8erboi wrote:

      Single benötige ich wegen der Größe und den Nachkommastellen.
      Muß denn damit gerechnet werden? Sonst wäre es auch möglich zwei Strings zu nutzen Centiwh*2 für die Nackkommas und Kilowh*10 für die Ganzzahl
      Das BCD Format läßt sich auch sehr ressourcenschonend in Ascci bringen. Bei den Nachkomma wird jedes Nibble zu einem Byte or $30 im String . Bei der Ganzzahl das or $30 erst ab den ersten das nicht 0 ist.
      sonst würde "0000000000.06 kWh" angezeigt
    • In Bezug auf den 1. Post.

      In der Abbildung dort ist angegeben (mit Beispiel), wie der Wert für kWh vorliegt, und wie er zu interpretieren ist.
      So wie ist das sehe werden zuerst die least signifikant Bytes in dem Array abgelegt. Und jedes Byte ist BCD-Kodiert.

      Man muss also nur rückwärts durch das Array gehen und die Nibbles zu einem Wert aufaddieren.
      Stellenwert der Nibbles muss beachtet werden! Das wird dann in einer Variable, z.B. Long, verrechnet.
      Also die Variable * 10 + Nibblewert.

      Lange Rede kurzer Sinn:

      Hier eine Demo:

      BASCOM Source Code: Umwandlung kWh in BCD im Array nach long-Variable

      1. $Regfile = "m328pdef.dat"
      2. $HWStack = 32
      3. $SWStack = 32
      4. $Framesize = 32
      5. $Crystal = 16000000
      6. Config SubMode = New
      7. Config Base = 0
      8. Dim byteArray(6) as Byte
      9. Declare Function getLowNibble(Byval value as Byte) as Byte
      10. Declare Function getHighNibble(Byval value as Byte) as Byte
      11. Declare Function getKiloWattStd() as long
      12. ' so liegen die Werte im Array
      13. byteArray(0) = &h36
      14. byteArray(1) = &h77
      15. byteArray(2) = &h0
      16. byteArray(3) = &h0
      17. byteArray(4) = &h0
      18. byteArray(5) = &h0
      19. Dim lngkWh as long
      20. Dim sngkWh as Single
      21. ' kWh als Long-Wert x100
      22. Print "Ergebnis als Integer:"
      23. lngkWh = getKiloWattStd()
      24. print "Long: " ; lngkWh ; " kWh x 100"
      25. ' kWh als Single umgerechnet
      26. Print
      27. Print "Ergebnis als Single:"
      28. sngkWh = lngkWh / 100
      29. print "Single: " ; sngkWh ; " kWh"
      30. End
      31. ' Gibt Low-Nibbel zurück
      32. Function getLowNibble(Byval value as Byte) as Byte
      33. getLowNibble = value and &h0F
      34. End Function
      35. ' Gibt High-Nibble zurück
      36. Function getHighNibble(Byval value as Byte) as Byte
      37. Swap value
      38. getHighNibble = value and &h0F
      39. End Function
      40. ' Gibt kWh aus dem Array zurück als Long mit 2 Nachkommastellen
      41. ' Bzw. gibt den Wert in kWh x 100 zurück
      42. Function getKiloWattStd() as long
      43. Local tmpkWh as Long
      44. Local tmpDigit as Byte
      45. Local tmpIndex as Byte
      46. tmpkWh = 0
      47. For tmpIndex = 5 to 0 Step -1
      48. tmpkWh = tmpkWh * 10
      49. tmpDigit = getHighNibble(byteArray(tmpIndex))
      50. tmpkWh = tmpkWh + tmpDigit
      51. tmpkWh = tmpkWh * 10
      52. tmpDigit = getLowNibble(byteArray(tmpIndex))
      53. tmpkWh = tmpkWh + tmpDigit
      54. Next tmpIndex
      55. getKiloWattStd = tmpkWh
      56. End Function
      Display All
      Wenn du die Demo im Simulator laufen lässt, werden genau die Werte aus dem 1. Post in der Abbildung umgerechnet und einmal als Long-Wert ausgegeben und einmal in Single.

      Je nachdem was du damit machen willst, nur im Display anzeigen oder damit was im AVR rechnen, ist das eine oder andere Format besser geeignet.
      Ich würde den Long-Wert vorziehen. Integer-Rechnungen sind schneller als Fließkommazahlen. Außerdem ist der Longwert wegen Rundungsfehler genauer.

      Dies ist nur ein Beispiel, wie man es machen kann.
      Es gibt sicherlich noch einige andere Möglichkeiten.