[Erklärung?]Variable auf Änderung prüfen

  • VB.NET

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von DannyDee.

    [Erklärung?]Variable auf Änderung prüfen

    Halli-Hallö'chen Leute,

    Ich hab ein Problem. Und zwar lese ich in meinem Projekt momentan alle 50ms per Timer den Status eines Schalters aus. Das permanente Auslesen möchte ich beibehalten ,jedoch möchte ich ,dass nur bei Änderung der Variable ein Counter as Integer +1 gezählt wird.
    Diesbezüglich habe ich ein wenig rumgegooglet und folgendes gefunden :


    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private WithEvents test As New myVar
    3. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    4. test.Variable = CInt(TextBox1.Text)
    5. End Sub
    6. Private Sub VariableChanged(ByVal NewValue As Integer) Handles test.VariableChanged
    7. MessageBox.Show(NewValue)
    8. End Sub
    9. End Class
    10. Public Class myVar
    11. Private mValue As Integer
    12. Public Event VariableChanged(ByVal mvalue As Integer)
    13. Public Property Variable() As Integer
    14. Get
    15. Variable = mValue
    16. End Get
    17. Set(ByVal value As Integer)
    18. mValue = value
    19. RaiseEvent VariableChanged(mValue)
    20. End Set
    21. End Property
    22. End Class


    Ich habe diesen Code Testweise in eine Testform eingebettet und es mal ausprobiert, jedoch wird dort das Event ja durch Button_click ausgelöst und nicht weil sich die Variable ändert.

    Ich wollte euch deswegen Fragen ob ihr mir diese Funktion/diesen Code mal genauer erklären könnt ,damit ich dahitner steige was dort genau vorgeht.
    Wäre super nett. Ich will diesen Code nur verstehen. Mir wäre es schon eine Hilfe wenn ihr mir sagt, ob dieser Code im Prinzip das ist ,was ich für meien Umstände brauche.

    Mit freundlichen Grüßen ,
    Danny der Dee
    Beim Setzen (Set) der Variable wird ein Event ausgelöst, egal, ob der Wert sich geändert hat oder nicht.

    Ich finde das Ganze für dein Vorhaben viel zu kompliziert. Wieso googelst du nach Lösungen und denkst nicht selbst nach?

    Du willst einen neuen Wert mit dem vorherigen vergleichen und bei Änderung einen Counter erhöhen.
    Dann speichere dir doch jedes Mal den alten Wert separat ab und vergleiche ihn mit dem neuen. Bei Änderung erhöhst du den Counter.

    VB.NET-Quellcode

    1. Dim old_var As .... 'was auch immer der Typ ist
    2. Dim counter As Integer
    3. Sub ..Timer-Event..
    4. var=GetSchalterStatus()
    5. If old_var<>var Then counter=counter+1
    6. old_var=var

    sonne75 schrieb:

    Ich finde das Ganze für dein Vorhaben viel zu kompliziert. Wieso googelst du nach Lösungen und denkst nicht selbst nach?

    Du willst einen neuen Wert mit dem vorherigen vergleichen und bei Änderung einen Counter erhöhen.
    Dann speichere dir doch jedes Mal den alten Wert separat ab und vergleiche ihn mit dem neuen. Bei Änderung erhöhst du den Counter.


    A: weil ich nach reiflichem Überlegen nicht darauf kam.
    B: so hatte ich es dann auch versucht zu lösen ,doch ich bleibe gerade irgendwie mit den Gedanken in einer Sackgasse stecken.


    EaranMaleasi schrieb:

    Wovon reden wir hier? einen Schalter als Control? oder i-was externes?

    Etwas externes.


    Falls Interesse besteht hier eine Beschreibung meines Projektes :
    Spoiler anzeigen

    Als Projekt habe ich einen Inkremental-Drehgeber selbst gebaut und durch 2 Näherungssensoren realisiert. Diese kann ich durch ein firmeninternes Bussystem auslesen. Um die Drehrichtung zu bestimme muss ich die Flankenposition der beiden Sensoren vergleichen.
    Dies war soweit kein Problem.
    Dann sollte das Projekt in sofern erweitert werden ,dass ich eine Flankenanzeige der Sensoren je nach Drehrichtung habe, welche die 90° Phasenverschiebung anzeigt.
    Gesagt ,getan.
    Nun bin ich dabei einen Frequenzmesser zu implementieren. Dessen Grundfunktion klappt auch super, nur bei zu hohem hz-Wert "verschluckt" er sich und gibt falsche Rückgabewerte (z.B.: Linkslauf obwohl er nach Rechts gedreht wird). Bei hz-Werten bis 10hz klappt das ohne Probleme.
    Dementsprechend schätze ich liegt es entweder am Auslesen der Sensoren oder an der Performance.

    Hier der Quellcode des gesamten Projektes :

    VB.NET-Quellcode

    1. Option Strict On
    2. Imports System.IO
    3. Imports FirmacXP.BusPort
    4. Imports FirmaXP.BusFunctions
    5. Public Class Main
    6. Private DT As DataTable 'Datentabelle zum Anzeigen der Feldmodule(Firmenintern)
    7. Dim sekcounter As Double 'Sekundenzähler für Frequenzberechnung
    8. Dim Pulscounter As Integer 'Zähler der Pulse für Sensor A
    9. Dim Frequenz As Double 'Ergebnis der Frequenzberechnung
    10. Dim Rechtslauf As Boolean 'Rückgabewert für den Rechtslauf
    11. Dim Linkslauf As Boolean 'Rückgabewert für den Linkslauf
    12. Dim Aold As Boolean 'vergleichswert für Sensor A
    13. Dim A As Boolean 'Status Sensor A
    14. Dim B As Boolean 'Status Sensor B
    15. Dim max As Integer = 120 'Maximum Lautstärke
    16. Dim mini As Integer = 0 'Minimum Lautstärke
    17. 'Datentabelle initialisieren
    18. Private Sub init()
    19. DT = New DataTable
    20. With DT
    21. .Columns.Add("Name")
    22. .Columns.Add("KurzAdr")
    23. .Columns.Add("TypNR")
    24. .Columns.Add("LangAdr")
    25. End With
    26. With Me.DataGridView1
    27. .DataSource = DT
    28. .AllowUserToAddRows = False
    29. .ReadOnly = True
    30. .RowHeadersVisible = False
    31. End With
    32. End Sub
    33. 'Datentabelle füllen
    34. Private Sub fillDT()
    35. DT.Rows.Clear()
    36. Dim devices As List(Of FirmaXP.Device) = FirmaXP.BusFunctions.devScan()
    37. If devices Is Nothing Then Exit Sub
    38. Dim dr As DataRow
    39. For Each d As FirmaXP.Device In devices
    40. dr = DT.NewRow
    41. dr("Name") = d.DevName
    42. dr("TypNR") = d.TypeNr
    43. dr("LangAdr") = d.LongAdr
    44. dr("KurzAdr") = d.ShortAdr
    45. DT.Rows.Add(dr)
    46. Next
    47. End Sub
    48. 'Module im Bussystem suchen
    49. Private Sub bt_search_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bt_search.Click
    50. init()
    51. fillDT()
    52. End Sub
    53. 'Aktivierung/Deaktivierung des Timers zum Auslesen des Registers (Gegenseitige Verriegelung)
    54. Private Sub cmd_lesen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmd_lesen.Click
    55. Timer_sek.Enabled = Not Timer_sek.Enabled
    56. If timer_lesen.Enabled = False Then
    57. cmd_dia.Enabled = True
    58. cmd_lesen.Text = "Bestimmung beenden."
    59. tb_shadr.ReadOnly = True
    60. tb_reg.ReadOnly = True
    61. timer_lesen.Enabled = True
    62. Else
    63. cmd_dia.Enabled = False
    64. cmd_lesen.Text = "Drehrichtung bestimmen."
    65. tb_shadr.ReadOnly = False
    66. tb_reg.ReadOnly = False
    67. timer_lesen.Enabled = False
    68. End If
    69. End Sub
    70. 'Timer zum auslesen und Umsetzen des Codes in eine Anzeige der einzelnen Flanken
    71. Private Sub timer_lesen_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timer_lesen.Tick
    72. Select Case readReg(CInt(tb_shadr.Text), CInt(tb_reg.Text))
    73. Case 1536
    74. A = False
    75. B = False
    76. Case 1537
    77. A = True
    78. B = False
    79. Case 1538
    80. A = False
    81. B = True
    82. Case 1539
    83. A = True
    84. B = True
    85. End Select
    86. If A <> Aold Then
    87. Pulscounter += 1
    88. End If
    89. tb_flanke()
    90. Aold = A
    91. PictureBox1.Invalidate()
    92. PictureBox2.Invalidate()
    93. End Sub
    94. 'Weißt den Textboxen den Wert der dazu gehörigen Variable zu.
    95. Public Sub tb_flanke()
    96. tb_flankea.Text = CStr(A)
    97. tb_flankeb.Text = CStr(B)
    98. End Sub
    99. 'Ruft die Sub ChecksensorA auf ,sobald ein neuer Wert eingetragen wird
    100. Private Sub tb_flankea_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb_flankea.TextChanged 'Richtungserkennung Flanke A / Lautstärkenanzeige-Update
    101. ChecksensorA()
    102. End Sub
    103. 'Ruft die Sub ChecksensorB auf ,sobald ein neuer Wert eingetragen wird
    104. Private Sub tb_flankeb_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb_flankeb.TextChanged 'Richtungserkennung Flanke B / Lautstärkenanzeige-Update
    105. ChecksensorB()
    106. End Sub
    107. 'Füllt je nach Begebenheit die UI für A mit Rückgabewerten
    108. Private Sub ChecksensorA() 'Überprüft die Drehrichtung anhand der Sensorstellung des Sensors A
    109. If A > B AndAlso TextBox1.TextLength < max Then
    110. tb_drehrichtung.Text = "Drehrichtung : Mit dem Uhrzeigersinn."
    111. TextBox1.Text = TextBox1.Text + "||| "
    112. Rechtslauf = True
    113. Linkslauf = False
    114. ElseIf A = B AndAlso TextBox1.TextLength > mini Then
    115. tb_drehrichtung.Text = "Drehrichtung : Gegen den Uhrzeigersinn."
    116. TextBox1.Text = TextBox1.Text.Remove(TextBox1.Text.Length - 4, 4)
    117. Linkslauf = True
    118. Rechtslauf = False
    119. End If
    120. End Sub
    121. 'Füllt je nach Begebenheit die UI für B mit Rückgabewerten
    122. Private Sub ChecksensorB() 'Überprüft die Drehrichtung anhand der Sensorstellung des Sensors B
    123. If B > A AndAlso TextBox1.TextLength > mini Then
    124. tb_drehrichtung.Text = "Drehrichtung : Gegen den Uhrzeigersinn."
    125. TextBox1.Text = TextBox1.Text.Remove(TextBox1.Text.Length - 4, 4)
    126. Linkslauf = True
    127. Rechtslauf = False
    128. ElseIf B = A AndAlso TextBox1.TextLength < max Then
    129. tb_drehrichtung.Text = "Drehrichtung : Mit dem Uhrzeigersinn."
    130. TextBox1.Text = TextBox1.Text + "||| "
    131. Rechtslauf = True
    132. Linkslauf = False
    133. End If
    134. End Sub
    135. 'Zeichnet je nach Drehrichtung die Flankenposition für A
    136. Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    137. Dim Points As New List(Of Point)
    138. If Rechtslauf = False AndAlso Linkslauf = False Then
    139. Points.Add(New Point(0, 75))
    140. Points.Add(New Point(400, 75))
    141. End If
    142. If Rechtslauf = True Then
    143. Points.Add(New Point(0, 75))
    144. Points.Add(New Point(50, 75))
    145. Points.Add(New Point(50, 25))
    146. Points.Add(New Point(100, 25))
    147. Points.Add(New Point(100, 75))
    148. Points.Add(New Point(150, 75))
    149. Points.Add(New Point(150, 25))
    150. Points.Add(New Point(200, 25))
    151. Points.Add(New Point(200, 75))
    152. Points.Add(New Point(250, 75))
    153. Points.Add(New Point(250, 25))
    154. Points.Add(New Point(300, 25))
    155. Points.Add(New Point(300, 75))
    156. ElseIf Linkslauf = True Then
    157. Points.Add(New Point(0, 75))
    158. Points.Add(New Point(75, 75))
    159. Points.Add(New Point(75, 25))
    160. Points.Add(New Point(125, 25))
    161. Points.Add(New Point(125, 75))
    162. Points.Add(New Point(175, 75))
    163. Points.Add(New Point(175, 25))
    164. Points.Add(New Point(225, 25))
    165. Points.Add(New Point(225, 75))
    166. Points.Add(New Point(275, 75))
    167. Points.Add(New Point(275, 25))
    168. Points.Add(New Point(300, 25))
    169. End If
    170. Dim PointArray() As Point = Points.ToArray
    171. 'Zeichnen
    172. Draw(e.Graphics, PointArray)
    173. End Sub
    174. 'Zeichnet je nach Drehrichtung die Flankenposition für B
    175. Private Sub PictureBox2_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox2.Paint
    176. Dim Points As New List(Of Point)
    177. If Rechtslauf = False AndAlso Linkslauf = False Then
    178. Points.Add(New Point(0, 75))
    179. Points.Add(New Point(400, 75))
    180. End If
    181. If Rechtslauf = True Then
    182. Points.Add(New Point(0, 75))
    183. Points.Add(New Point(75, 75))
    184. Points.Add(New Point(75, 25))
    185. Points.Add(New Point(125, 25))
    186. Points.Add(New Point(125, 75))
    187. Points.Add(New Point(175, 75))
    188. Points.Add(New Point(175, 25))
    189. Points.Add(New Point(225, 25))
    190. Points.Add(New Point(225, 75))
    191. Points.Add(New Point(275, 75))
    192. Points.Add(New Point(275, 25))
    193. Points.Add(New Point(300, 25))
    194. ElseIf Linkslauf = True Then
    195. Points.Add(New Point(0, 75))
    196. Points.Add(New Point(50, 75))
    197. Points.Add(New Point(50, 25))
    198. Points.Add(New Point(100, 25))
    199. Points.Add(New Point(100, 75))
    200. Points.Add(New Point(150, 75))
    201. Points.Add(New Point(150, 25))
    202. Points.Add(New Point(200, 25))
    203. Points.Add(New Point(200, 75))
    204. Points.Add(New Point(250, 75))
    205. Points.Add(New Point(250, 25))
    206. Points.Add(New Point(300, 25))
    207. Points.Add(New Point(300, 75))
    208. End If
    209. Dim PointArray() As Point = Points.ToArray
    210. 'Zeichnen
    211. Draw(e.Graphics, PointArray)
    212. End Sub
    213. 'Zeichnungssub
    214. Sub Draw(ByVal Gra As Graphics, ByVal points() As Point)
    215. Dim Pen As New Pen(Color.Black, 5)
    216. With Gra
    217. .Clear(Color.White)
    218. .DrawLines(Pen, points)
    219. End With
    220. End Sub
    221. 'Timer für die Frequenzmessung/berechnung
    222. Private Sub Timer_sek_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer_sek.Tick
    223. If sekcounter < 10 Then
    224. sekcounter += 1
    225. Else
    226. Frequenz = (Pulscounter / sekcounter) / 2
    227. tb_frequenz.Text = "Die durchschnittliche Frequenz beträgt " & CStr(Frequenz) & "hz."
    228. Pulscounter = 0
    229. sekcounter = 0
    230. End If
    231. End Sub
    232. End Class


    Ich bin für jede Verbesserung offen , sofern sie mir auch ausreichend erklärt wird. (Newbie, undso).
    Vor allem bei Performance-Vorschlägen bin ich super dankbar.



    Zum Thema oben :
    Ließe sich der Code oben , in sofern verändern ,dass er das Ereignis bei Änderung der Variable ausführt?

    DannyDee schrieb:

    Ließe sich der Code oben , in sofern verändern ,dass er das Ereignis bei Änderung der Variable ausführt?

    Dann schau in den Link von Post 2, da ist es mit zig Zeilen Code gelöst.Und im Endeffekt wird im Kern genau das Gleiche gemacht: die alte Variable mit der neuen verglichen.

    Warum passen dir die paar Zeilen meines Codes nicht?
    Mir gefällt der Code da garnicht (der von DannyDee). Du vermischst Daten und GUI - das sehe ich daran, dass du iwelche Werte aus den Textboxen puhlst xD Objektorientiert programmiert sieht anders aus...

    Du sagst, bis 10Hz läuft es problemlos und deine Abtastrate liegt bei 20Hz (=> 50ms Timer-Tick). Kann es nicht sein, dass bei höheren Drehgeschwindigkeiten ein Sensor-High genau zwischen zwei Messzeitpunkten liegt und darum nicht erkannt wird? Oder das ein High nur so kurz andauert, dass es deswegen 'verschluckt' wird?

    Dann ist es die Frage, wo du nachbessern musst:
    a) Softwareseitig => höheres Abfrageintervall ist das einzige was mir einfällt..
    b) Hardwareseitig => mehr Sensoren? andere Sensoren? weitere Hardware, welche die Daten für die Software aufbereitet?

    FreakJNS schrieb:

    das sehe ich daran, dass du iwelche Werte aus den Textboxen puhlst xD Objektorientiert programmiert sieht anders aus...
    Dürfte ich dich bitten die Stelle zu zitieren? Denn ich finde bei bestem Willen ,nicht eine Stelle an dem ich mir Daten aus den Textboxen "puhle". Ich ändere lediglich den Text der Textbox je nach Lage der Rückgabewerte ändere.
    Oder meinst du die TextChanged-Events damit?



    FreakJNS schrieb:

    Kann es nicht sein, dass bei höheren Drehgeschwindigkeiten ein Sensor-High genau zwischen zwei Messzeitpunkten liegt und darum nicht erkannt wird? Oder das ein High nur so kurz andauert, dass es deswegen 'verschluckt' wird?

    Das ist ein Gedanke den ich bisher noch nciht weiter verfolgt hatte. Das werde ich auf jeden Fall mal durchprobieren.

    FreakJNS schrieb:

    b) Hardwareseitig => mehr Sensoren? andere Sensoren? weitere Hardware, welche die Daten für die Software aufbereitet?


    Das ganze funktioniert mit nur 2 Sensoren, da diese mit 90° Phasenverschiebung die Signale senden. Dadurch lässt sich anhand des Musters festlegen in welche Richtung der "Regler" gedreht wird.

    Die Sensoren sollten gut sein , die schalten mit bis zu 1khz.

    Und das mit der Hardware ,die die Daten aufbereitet , da sehe ich (in meinem Aufbau) vllt die große Schwachstelle. Denn ich gehe vom Schaltsignal ,auf Relais ,darüber auf direkte Eingänge eines der Firmenmodule ,und diese schicken es über Bus an einen Busverteiler ,welcher wiederum auf ein Bus-to-USB Interface schickt ,von dem cih es letztendlich auslese. Ich könnte mir gut vorstellen ,dass diese "riesige" Distanz dafür verantwortlich sien könnte ,dass es eben nur bis ca 10-15 hz sauber arbeitet.

    Nun wie gesagt , ich werde es mal versuchen mit dem Abfrageintervall.

    Und bezüglich meines Codes. Wenn er dir nciht gefällt , gehe ich davon aus ,dass er unsauber ist. Richtig? Falls ja würde ich mcih freuen ,wenn Hilfestellungen und Tipps gegeben werden die etwas konkreter sind als "gefällt mir nicht , objektorientiert sieht anders aus".


    @sonne75 Doch doch, habe es ja auch ähnlich implementiert. Ich wollte nur wissen ,ob der Code oben anpassbar gewesen wäre. (btw den Link habe ich mir angesehen. Werde es demnächst noch genauer studieren.)
    MfG Danny Dee

    DannyDee schrieb:

    Ließe sich der Code oben , in sofern verändern ,dass er das Ereignis bei Änderung der Variable ausführt?
    Also der gezeigte Code besteht ja aus 2 Klassen:
    • einmal ein Form, zu Testzwecken.
      dass da der code fragwürdig ist, scheint mir keine Totsünde.
    • zum anneren die myVar-Klasse
      Die finde ich nun sehr nah an durchaus gängigen Vorgehensweisen - noch bischen weiter gedacht, und sie würde sogar Databinding unterstützen.
      Schon das Anliegen "Ein Ereignis feuern, wenn sich der Wert effektiv ändert" ist genau das Grundprinzip Databinding - nur halt die selbst erfundene Implementierung erreicht nicht ganz den Standard.
      Das meinte vmtl. xtts02 mit seiner Bemerkung, dasses dafür ein Interface gebe - nämlich für Databinding gibts ein Interface.
    Also Standard-Mäßig sähe es so aus:

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Public Class Form1
    3. Private WithEvents test As New myVar
    4. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    5. test.Variable = CInt(TextBox1.Text)
    6. End Sub
    7. Private Sub test_PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Handles test.PropertyChanged
    8. 'hier könnte auch je nach e.PropertyName getestet unterschiedlich reagiert werden
    9. MessageBox.Show(test.Variable.ToString)
    10. End Sub
    11. End Class
    12. Public Class myVar : Implements INotifyPropertyChanged
    13. Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    14. Private _Variable As Integer
    15. Public Property Variable() As Integer
    16. Get
    17. Variable = _Variable
    18. End Get
    19. Set(ByVal value As Integer)
    20. If _Variable = value Then Return
    21. _Variable = value
    22. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Variable"))
    23. End Set
    24. End Property
    25. End Class

    Aber auch ohne den Databinding-Pattern zu unterstützen (der dir vmtl. garnet bekannt ist - du hast da das Rad neu erfunden) ist deine Implementation ganz ganz nah an standardmäßigen Vorgehensweisen, etwa:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private WithEvents test As New myVar
    3. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    4. test.Variable = CInt(TextBox1.Text)
    5. End Sub
    6. Private Sub VariableChanged(sender As System.Object, ByVal e As System.EventArgs) Handles test.VariableChanged
    7. MessageBox.Show(test.Variable.ToString)
    8. End Sub
    9. End Class
    10. Public Class myVar
    11. Private _Variable As Integer
    12. Public Event VariableChanged As EventHandler
    13. Public Property Variable() As Integer
    14. Get
    15. Variable = _Variable
    16. End Get
    17. Set(ByVal value As Integer)
    18. If _Variable = value Then Return
    19. _Variable = value
    20. RaiseEvent VariableChanged(Me, EventArgs.Empty)
    21. End Set
    22. End Property
    23. End Class
    (und in WinForms würde sogar das Databinding unterstützen - gugge auch Alles über Events)

    Also imo ist der Code für einen Anfänger, der dieses Buch lesen (hingegen das Galileio-Openbook ist Mist) noch nicht gelesen hat, aussergewöhnlich gut.
    Insbesondere, dass die Neu-Erfindung des Rades "Databinding" garnet schlecht getroffen ist.

    Zu Performance-Fragen: An diesem Muster liegts nicht, wenns Performance-Probleme gibt - das sollte hinreichend schnell sein.

    ErfinderDesRades schrieb:

    Also imo ist der Code für einen Anfänger, der dieses Buch lesen (hingegen das Galileio-Openbook ist Mist) noch nicht gelesen hat, aussergewöhnlich gut.


    Danke, sowas hört man gern. :)

    So wie du es erklärst ist es für mich auch recht verständlich. Ich werde mich an das Thema mal weiter rantasten. Und mit Databinding hast du mir ein gutes Stichwort gegeben. Bisher kannte ich das nicht (Da vor ca 10 Tagen erst aktiv angefangen mit Programmierung) und werde es mir mal etwas genauer anschauen.

    Vielleicht kannst du mir bei folgendem Problem auch eine Hilfestellung geben:
    (Da für das Hauptthema nicht zwingend relevant hier im Expander, bei Interesse reinschauen)

    Spoiler anzeigen

    Ich möchte ja einen Inkremental Drehgeber auslesen. Dies klappt soweit ja ganz gut. Die Drehrichtungsbestimmung wird normalerweise von einem speziellen Mikrocontroller übernommen ,der den Verlauf der beiden Schaltstellen (Bei mir induktive Näherungssensoren) erkennt und dann die Drehrichtung daraus erschließt ,welche Schaltstelle als erstes das "1"-Signal schickt. Denn durch die Anordnung der beiden Sensoren erschließt sich eine 90° Phasenverschiebung. Diese Phasenverschiebung erzeugt folgendes Muster :

    Drehrichtung rechts(Mit dem Uhrzeigersinn ; Pfeil symbolisiert Bewegung des Drehreglers)
    A=0 & B=0 -> A=1 & B=0 -> A=1 & B=1 -> A=0 & B=1 -> A=0 & B=0 [...]
    Drehrichtung links (Gegen den Uhrzeigersinn)
    A=0 & B=0 -> A=0 & B=1 -> A=1 & B=1 -> A=1 & B=0 -> A=0 & B=0 [...]
    Diesen Effekt wollte ich auslesen und erkennen können.
    Anfangs sah das so aus(Code wird weiter unten Stück für Stück erklärt) :

    VB.NET-Quellcode

    1. 'Timer zum auslesen und Umsetzen des Codes in eine Anzeige der einzelnen Flanken
    2. Private Sub timer_lesen_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timer_lesen.Tick
    3. Select Case SenosorAuslesen
    4. Case 1536
    5. A = False
    6. B = False
    7. Case 1537
    8. A = True
    9. B = False
    10. Case 1538
    11. A = False
    12. B = True
    13. Case 1539
    14. A = True
    15. B = True
    16. End Selecttb_flanke()
    17. End Sub
    18. 'Weißt den Textboxen den Wert der dazu gehörigen Variable zu.
    19. Public Sub tb_flanke()
    20. tb_flankea.Text = CStr(A)
    21. tb_flankeb.Text = CStr(B)
    22. End Sub
    23. 'Ruft die Sub ChecksensorA auf ,sobald ein neuer Wert eingetragen wird
    24. Private Sub tb_flankea_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb_flankea.TextChanged 'Richtungserkennung Flanke A / Lautstärkenanzeige-Update
    25. ChecksensorA()
    26. End Sub
    27. 'Ruft die Sub ChecksensorB auf ,sobald ein neuer Wert eingetragen wird
    28. Private Sub tb_flankeb_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb_flankeb.TextChanged 'Richtungserkennung Flanke B / Lautstärkenanzeige-Update
    29. ChecksensorB()
    30. End Sub
    31. 'Füllt je nach Begebenheit die UI für A mit Rückgabewerten
    32. Private Sub ChecksensorA() 'Überprüft die Drehrichtung anhand der Sensorstellung des Sensors A
    33. If A > B AndAlso TextBox1.TextLength < max Then
    34. tb_drehrichtung.Text = "Drehrichtung : Mit dem Uhrzeigersinn."
    35. TextBox1.Text = TextBox1.Text + "||| "
    36. Rechtslauf = True
    37. Linkslauf = False
    38. ElseIf A = B AndAlso TextBox1.TextLength > mini Then
    39. tb_drehrichtung.Text = "Drehrichtung : Gegen den Uhrzeigersinn."
    40. TextBox1.Text = TextBox1.Text.Remove(TextBox1.Text.Length - 4, 4)
    41. Linkslauf = True
    42. Rechtslauf = False
    43. End If
    44. End Sub
    45. 'Füllt je nach Begebenheit die UI für B mit Rückgabewerten
    46. Private Sub ChecksensorB() 'Überprüft die Drehrichtung anhand der Sensorstellung des Sensors B
    47. If B > A AndAlso TextBox1.TextLength > mini Then
    48. tb_drehrichtung.Text = "Drehrichtung : Gegen den Uhrzeigersinn."
    49. TextBox1.Text = TextBox1.Text.Remove(TextBox1.Text.Length - 4, 4)
    50. Linkslauf = True
    51. Rechtslauf = False
    52. ElseIf B = A AndAlso TextBox1.TextLength < max Then
    53. tb_drehrichtung.Text = "Drehrichtung : Mit dem Uhrzeigersinn."
    54. TextBox1.Text = TextBox1.Text + "||| "
    55. Rechtslauf = True
    56. Linkslauf = False
    57. End If
    58. End Sub


    Ich lese mit Schritt 1 über einen Timer die Positionen der Sensoren und ordne den Wert der tatsächlichen Schalterstellung zu :

    VB.NET-Quellcode

    1. 'Timer zum auslesen und Umsetzen des Codes in eine Anzeige der einzelnen Flanken
    2. Private Sub timer_lesen_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timer_lesen.Tick
    3. Select Case SenosorAuslesen
    4. Case 1536
    5. A = False
    6. B = False
    7. Case 1537
    8. A = True
    9. B = False
    10. Case 1538
    11. A = False
    12. B = True
    13. Case 1539
    14. A = True
    15. B = True
    16. End Selecttb_flanke()
    17. End Sub

    Danach wird die Sub "tb_flanke" aktiviert.

    Diese gibt den Wert der beiden Sensorvariablen (A & B) als Text an eine Textbox.

    VB.NET-Quellcode

    1. 'Weißt den Textboxen den Wert der dazu gehörigen Variable zu.
    2. Public Sub tb_flanke()
    3. tb_flankea.Text = CStr(A)
    4. tb_flankeb.Text = CStr(B)
    5. End Sub

    Dies brauche ich ,da ich über die Text_Changed-Events der beiden Textboxen die Subs ChecksensorA und ChecksensorB aufrufe
    (Diesen Umweg über den Text_Changed-Event will ich durch mein Hauptthema [Variablen auf Änderung überprüfen] umgehen, da ich vermute ,dass er sich dadurch eventuell "verschluckt" und das Anzeigen darunter leidet, denn bei zu hoher Drehzahl bzw Frequenz der Schalter , wechselt er im Programm die gelesene Drehrichtung ,obwohl die tatsächliche Drehrichtung sich nicht ändert.)

    VB.NET-Quellcode

    1. 'Ruft die Sub ChecksensorA auf ,sobald ein neuer Wert eingetragen wird
    2. Private Sub tb_flankea_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb_flankea.TextChanged 'Richtungserkennung Flanke A / Lautstärkenanzeige-Update
    3. ChecksensorA()
    4. End Sub
    5. 'Ruft die Sub ChecksensorB auf ,sobald ein neuer Wert eingetragen wird
    6. Private Sub tb_flankeb_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tb_flankeb.TextChanged 'Richtungserkennung Flanke B / Lautstärkenanzeige-Update
    7. ChecksensorB()
    8. End Sub



    Diese Subs dienen zum Vergleich der Sensor-Schaltstellung und zeigen je nach Positionskombination die Drehrichtung an.
    (Als kleines "Augenzierlein" habe ich noch eine Textbox die sozusagen als "Fortschrittsanzeige" dient. Vergleichbar mit einer Digitalanzeige eines Lautsprechersystems.)

    VB.NET-Quellcode

    1. 'Füllt je nach Begebenheit die UI für A mit Rückgabewerten
    2. Private Sub ChecksensorA() 'Überprüft die Drehrichtung anhand der Sensorstellung des Sensors A
    3. If A > B AndAlso TextBox1.TextLength < max Then
    4. tb_drehrichtung.Text = "Drehrichtung : Mit dem Uhrzeigersinn."
    5. TextBox1.Text = TextBox1.Text + "||| "
    6. Rechtslauf = True
    7. Linkslauf = False
    8. ElseIf A = B AndAlso TextBox1.TextLength > mini Then
    9. tb_drehrichtung.Text = "Drehrichtung : Gegen den Uhrzeigersinn."
    10. TextBox1.Text = TextBox1.Text.Remove(TextBox1.Text.Length - 4, 4)
    11. Linkslauf = True
    12. Rechtslauf = False
    13. End If
    14. End Sub
    15. 'Füllt je nach Begebenheit die UI für B mit Rückgabewerten
    16. Private Sub ChecksensorB() 'Überprüft die Drehrichtung anhand der Sensorstellung des Sensors B
    17. If B > A AndAlso TextBox1.TextLength > mini Then
    18. tb_drehrichtung.Text = "Drehrichtung : Gegen den Uhrzeigersinn."
    19. TextBox1.Text = TextBox1.Text.Remove(TextBox1.Text.Length - 4, 4)
    20. Linkslauf = True
    21. Rechtslauf = False
    22. ElseIf B = A AndAlso TextBox1.TextLength < max Then
    23. tb_drehrichtung.Text = "Drehrichtung : Mit dem Uhrzeigersinn."
    24. TextBox1.Text = TextBox1.Text + "||| "
    25. Rechtslauf = True
    26. Linkslauf = False
    27. End If
    28. End Sub


    Und das wars eigentlich auch schon ,was allein das Auslesen und Anzeigen der Drehrichtung angeht.
    Wenn ich jetzt aber den Code in sofern ändere ,dass "ChecksensorA" und "ChecksensorB" aufgerufen werden ,sobald sich A ändert, springt er alle 2 Pulse zwischen den Drehrichtungen hin und her.
    Ich hab mich da irgendwie total festgefahren , und wüsste nicht ,wie ich das ändern oder beheben kann (eventuell durch gleichzeitiges Vergleichen von B und B_old? Denn bisher schaue ich nur ob A sich ändert und löse dann beide Subs aus.)

    Im Anhang ein Bild des selbstgebauten Inkremental Drehgebers zum besseren Verständniss:


    imagebanana.com/view/90vyc9rz/IMG_13631.JPG


    Sobald ich neue Ergebnisse habe ,was Databinding und das Vergleichen angeht, werde ich mich melden.

    MfG Danny Dee
    also zum DrehgeberLeser im allgemeinen: Da stimme ich FreakJNS zu - dassis grauselig, was du da anstellst mitte Textboxen. Textboxen sind für textuelle Interaktion mittm User da, und du mißbrauchst die iwie als Event-Erzeuger.
    Dabei kannst du doch inzwischen Events selbst erzeugen (klasse myVar) - da brauchste nicht Textboxen für zu mißbrauchen.

    Jo, zu deim Drehgeberleser erstmal konzipieren, insbesondere Begriffe schaffen.
    Habe mit "DrehgeberLeser" schomal angefangen, dabei habichmir gedacht, du willst etwas auslesen, iwas mit einem Drehgeber, wassich nicht verstanden hab, denn die Rede ist ja ausschließlich von Sensoren, also Input-Elemente, da weiß ich nicht, was daran "DrehGeber" ist, es ist doch eher ein "DrehNehmen" - egal.

    Der Drehgeberleser wird regelmäßig geupdatet mit den neuesten Positionen der Sensoren.

    Das verstehe ich schon wieder nicht: Muß man da wirklich mit einem Timer die Sensor-Positionen abrufen? Vorstellbar (bzw. bei Drehzahlmessung glaub üblich) wären doch aktive Sensoren, die einen Output genau dann generieren, wenn ein Messpunkt vorbei-rotiert.

    Hmm - eigentlich kann man hier schon nicht mehr weitermachen, ehe diese Frage eindeutig beantwortet ist.
    Weil diese Alternativen führen auf unterschiedliche Architekturen hin.



    egal, mal angenommen, es wäre so, und man müsste wirklich mit Timer die SensorPositionen abfragen.
    Aus den SensorPositionen kann der Drehgeberleser Drehrichtung und Frequenz berechnen, oder?

    Womit die Architektur doch eiglich klar ist:
    Schaff eine Klasse Drehgeberleser (oder finde einen passenderen Namen dafür), und gib ihr die Properties Forward As Boolean und Frequency As Double
    Gib ihr ausserdem eine Sub Update(pos1, pos2), in der vorgenannte Properties neu bestimmt werden.
    Vermutlich nützlich wäre nun, den Databinding-Pattern für die beiden Properties zu implementieren, und sich dabei haarklein ans vorgeführte Schema halten.
    Nachdem ich das Bild gesehen habe bin ich ja überzeugt, dass Fehler aufgrund der viel zu niedrigen Messfrequenz kommen (Timer mit 50ms Intervall = 20Hz). Dreht sich das Rad mit 10Hz ist jede Messfläche (10 Stück an der Zahl, jede macht eine 0 oder eine 1) nur 10ms 'sichtbar'. Für eine anständige Messung brauchst du doch sicher jedes mögliche High/Low eines Sensors (und damit ein Timerintervall von 10ms um bei 10Hz Drehfrequenz richtig arbeiten zu können)?

    (Bitte verbessert mich, kann auch sein, dass es 'anders' funktioniert xD)
    @FreakJNS:: Da gebe ich Dir vollkommen Recht.
    @DannyDee:: Drehzahlgeber werden üblicherweise an einer Zählerkarte (Hardware) betrieben, damit ist gesichert, dass kein Impuls verlorengeht.
    Windows ist nun mal kein Echtzeit-Betriebssystem, da kann wer weiß was passieren.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    ErfinderDesRades schrieb:

    Textboxen sind für textuelle Interaktion mittm User da, und du mißbrauchst die iwie als Event-Erzeuger.
    Dabei kannst du doch inzwischen Events selbst erzeugen (klasse myVar) - da brauchste nicht Textboxen für zu mißbrauchen.

    Die Sache mit den Textboxen hatte ich ja erklärt. Mir fehlt eben noch die Erfahrung und das Wissen um das auf Anhieb perfekt umzusetzen. Deswegen wende ich mich ja in diesem Forum unter "Grundlagen" an erfahrenere Leute , um Erklärungen etc zu erhaschen.
    Der Grund weswegen ich es über die Textboxen gemacht hatte, war lediglich weil ich die hier besprochene Methode Variablen zu überprüfen noch nicht verstanden hatte.

    ErfinderDesRades schrieb:

    Habe mit "DrehgeberLeser" schomal angefangen, dabei habichmir gedacht, du willst etwas auslesen, iwas mit einem Drehgeber, wassich nicht verstanden hab, denn die Rede ist ja ausschließlich von Sensoren, also Input-Elemente, da weiß ich nicht, was daran "DrehGeber" ist, es ist doch eher ein "DrehNehmen" - egal.

    Der gesamte Aufbau ist vom Prinzip her ein "Inkremental Drehgeber". Deswegen blieb ich bei diesem Namen.


    ErfinderDesRades schrieb:

    Das verstehe ich schon wieder nicht: Muß man da wirklich mit einem Timer die Sensor-Positionen abrufen? Vorstellbar (bzw. bei Drehzahlmessung glaub üblich) wären doch aktive Sensoren, die einen Output genau dann generieren, wenn ein Messpunkt vorbei-rotiert.


    Leider ja ,denn die Positionen der Sensoren lese ich über ein firmeninternes Bussystem aus, welches aus Einzelmodulen besteht ,welche verschiedenste Aufgaben haben. Also habe ich mir ein Modul zum erkennen von Schaltstellungen rausgesucht und dort die Sensoren angeklemmt. Diese Module warten auf Befehle von Master(PC bzw das Programm), sprich ich muss ihm sagen "ModulAuslesen" und daraufhin bekomme ich einen Wert als Feedback (Oben 1536/1537/1538/1539) für jede mögliche Stellungskombination der beiden Sensoren.

    Zwischenfrage : Könnte ich diesen Befehl "ModulAuslesen" eventuell ohne Timer immer wieder neu aufrufen lassen? Eventuell über einen Thread? Ich dachte da an eine Art rekursives Aufrufen. (Werde mich mal schlau lesen).


    RodFromGermany schrieb:

    @DannyDee:: Drehzahlgeber werden üblicherweise an einer Zählerkarte (Hardware) betrieben, damit ist gesichert, dass kein Impuls verlorengeht.
    Windows ist nun mal kein Echtzeit-Betriebssystem, da kann wer weiß was passieren.


    Ich verstehe. An sich ist mein Ziel ja erreicht, wie schnell es ausliest und reagiert ist erstmal Nebensache ,da dieser Aufbau in der Praxis keine Anwendung finden wird. Dies ist rein praktisches Lernen für meine Ausbildung. Aber da mich der Ehrgeiz gepackt hat , will ich das Programm so flüssig und zuverlässig wie möglich machen.
    Diesbezüglich frage ich hier ja auch nach anderen Methoden udn Varianten um den Code stabiler zu machen.
    Denn die Grundfunktion bringt das Programm. (Es tut was es soll, aber eben vom Code her weder schön ,noch stabil)

    FreakJNS schrieb:

    Nachdem ich das Bild gesehen habe bin ich ja überzeugt, dass Fehler aufgrund der viel zu niedrigen Messfrequenz kommen (Timer mit 50ms Intervall = 20Hz). Dreht sich das Rad mit 10Hz ist jede Messfläche (10 Stück an der Zahl, jede macht eine 0 oder eine 1) nur 10ms 'sichtbar'. Für eine anständige Messung brauchst du doch sicher jedes mögliche High/Low eines Sensors (und damit ein Timerintervall von 10ms um bei 10Hz Drehfrequenz richtig arbeiten zu können)?


    An sich hast du da Recht , stimmt. Habe den Intervall auch schon zu 10ms geändert ,jedoch bringt es nicht viel.(Da wahrscheinlich die Ausführung durch die "Nicht-Trennung" von Daten und UI unzuverlässig ist?)
    Die "Drehscheibe" hat 12 Messflächen (6x1 & 6x0).


    Wie dem auch sei, ich werde mich jetzt erstmal dran machen ,die Text_Changed rauszuschmeißen und das ganze durch die myVar-Klasse zu ersetzen.
    Danach werde ich mich an die Sache mit dem Auslesen des Drehgebers ran machen, und versuchen es durch einen Thread (rekursiv?) zu ersetzen. Vielleicht erreiche ich dann eine höhere Lesgeschwindigkeit.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „DannyDee“ ()

    paar punkte: vmtl. weißt du nicht, was Rekursion ist, jdfs. hat Rekursion bei dieser Problemstellung nix verloren.

    schneller getacktete Timer als 10ms sind problematisch, also für deine Übungen mach erstmal mit langsameren Werten, aber dasses funzt.
    Hab mir die Drehgeberei jetzt mal angeguckt, für mich sieht das sehr danach aus, dass ein Drehgeber bei Bewegung aktiv ein Signal ausgibt. Was dann auf eine Architektur ohne Timer hinausliefe.

    Insgesamt nennt man sowas polling, wenn andauernd aktuelle Werte abgefragt werden, und das ist sehr unschön, da es kontinuirlich CPU-Leistung zieht, und damit letztendlich den ganzen Rechner verlangsamt.

    Wesentlich sinniger wäre die Architektur für aktive Sensoren, aber du sagst ja, die seien unverrückbar passiv, was mit iwelchen Bussen zu tun hat.

    genau.
    Setze das mit deiner Klasse um, aber nenn die um Himmelswillen nicht "myVar".

    ErfinderDesRades schrieb:

    schneller getacktete Timer als 10ms sind problematisch, also für deine Übungen mach erstmal mit langsameren Werten, aber dasses funzt.
    Habe das Bussystem mal beobachtet , dun es scheint ,dass Systemabhängig keine schnellere Frequenz als 20hz erreicht werden können. Dementsprechend würde ich dein Tiemr auf 20ms einstellen.

    ErfinderDesRades schrieb:

    Wesentlich sinniger wäre die Architektur für aktive Sensoren, aber du sagst ja, die seien unverrückbar passiv, was mit iwelchen Bussen zu tun hat.

    Wenn das möglich wäre , hätte ich es schon umgesetzt, doch leider mit diesem Aufbau nciht möglich.



    ErfinderDesRades schrieb:


    Setze das mit deiner Klasse um, aber nenn die um Himmelswillen nicht "myVar".

    Hatte ich nicht vor :D

    Programm ist soweit umgeschrieben , und muss jetzt nur noch verfeinert werden.
    Ich verabschiede mich damit erstmal und schreie.
    CLOSED!

    (Btw thanks für die Hilfe)

    DannyDee schrieb:

    keine schnellere Frequenz als 20hz erreicht werden können. Dementsprechend würde ich dein Tiemr auf 20ms einstellen.
    20 Hz <==> 50 ms :!:
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!