Loop Until Schleife wird zu früh verlassen.

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    Aufgrund technischer Veränderungen ist der Mailverkehr innerhalb des Forums (Private Nachrichten) nur noch eingeschränkt möglich. Die Einschränkung ist notwendig, um zusätzliche Betriebskosten für das Forum zu vermeiden. Näheres zu den Hintergründen im Thread "Aktuelles zum Forum".Wir bitten um Verständnis.

    Hinweis kann nach Kenntnisnahme deaktiviert werden!

    • Loop Until Schleife wird zu früh verlassen.

      Anbei der abgespeckte Programmtiel, in dem der Fehler auftritt.
      Mittels einer IR-Fernbedienung sol ein Stepper dabei im Schrittbetrieb betrieben werden.
      Das übrige Programm funktioniert wie es soll (deshalb mal gelöscht)

      Der Fehler äüßert sich wie folgt, die Variable Ds (hier einfach mal feszt vorgegeben steuert die Anzahl der Impulse für den Stepper
      Dazu gibt es die Schleife Do... Loop Until Impuls >=Ds
      Impuls wird in der ISR inkrementiert,
      Nun passiert folgendes, die Schleife zählt fast immer bis 1000 und die Stepperschritte sind i.O., aber völlig unregelmäßig wird die Schleife bei 768 Impulsen verlassen, und zwar immer bei 768,
      dies passiert manchmal 3 innerhalb von 10 Versuchen, manchmal funktioniert es 30mal, was mich eben wundert ist die Zahl 768 (=3x256),
      die Zeile 250, 252 habe ich zur Kontrolle eingefügt, es wird im Fehlerfall stets exakt 768 angezeigt, ansonsten korrekterweise 1000
      Bin mit meinen Versuchen und meinem Latein etwas am Ende, vielleicht siht ja jemand den Fehler, für den ich offensichtlich zu blind bin.
      Nebenbemerkung:
      Das übrige Programm, also beliebige Steuerung des Motors (Vorwärts, Rückwärts, usw. fiunktioniert einwandfrei, nur der Stepbetrieb spinnt)


      PS wie fügt man denn den Codes so ein, dass er im Fenster erscheint? Edit habs gefunden!!

      Quellcode

      1. 'Version 20.10.21
      2. 'Bascom ATmega328
      3. 'LCD 16 x 4
      4. 'Drehzahleingang über ROD 426, 500 Striche an Spindel
      5. 'Vorschub eingang über ROD 1000 Striche an Vorschubmotor
      6. '
      7. 'Vorschub:
      8. 'Frequenz 1000Hz
      9. 'Treiber 1000 Schritte
      10. 'Spindel
      11. 'Frequenz variabel, abhängig von Ds
      12. 'Treiber 1000 Schritte
      13. $regfile = "m328pdef.dat"
      14. $crystal = 16000000
      15. $hwstack = 94
      16. $swstack = 64
      17. $framesize = 48
      18. Baud = 9600
      19. '---------------------------------------------------------------------------------
      20. 'Definition LCD
      21. '---------------------------------------------------------------------------------
      22. Config Lcd = 16x4
      23. Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portc.5 , Rs = Portc.4
      24. '---------------------------------------------------------------------------------
      25. 'Definition der Ein- und Ausgänge
      26. '---------------------------------------------------------------------------------
      27. Config Pind.0 = Input 'Eingang für RC5
      28. Config Pind.1 = Input 'Inkrementalgeber Kanal B
      29. Config Pind.4 = Input 'Inkrementalgeber Kanal A (Trigger)
      30. Config Pind.2 = Input 'Anschlag links
      31. Config Pind.3 = Input 'Anschlag rechts
      32. Config Portb.0 = Output 'Ausgang Takt Vorschub
      33. Config Portb.1 = Output 'Ausgang Richtung Vorschub
      34. Config Portb.2 = Output 'Ausgang Enable Vorschub
      35. Config Portb.3 = Output 'für Oszi Spindel nur für Test
      36. Config Portd.5 = Output 'Ausgang Enable Spindel
      37. Config Portd.7 = Output 'Ausgang Takt Spindel
      38. '-----------------------------------
      39. 'Portb.6 Quarz
      40. 'Portb.7 Quarz
      41. '-----------------------------------
      42. '-------------------------------
      43. 'Definition der RC5-parameter
      44. '--------------------------------
      45. Config Rc5 = Pind.0 , Wait = 2000 'Wait2000 = 131ms
      46. '---------------------------------------
      47. 'Definition der Variablen
      48. '---------------------------------------
      49. Dim Address As Byte
      50. Dim Command As Byte
      51. Dim Command_a As Byte
      52. Dim N_soll As Long
      53. Dim N_ist As Long
      54. Dim Ds As Word
      55. Dim Ds1000 As Single
      56. Dim Striche As Long
      57. Dim Rod As Integer
      58. Dim Delay_von_d As Integer
      59. Dim Timer_preload_spindel As Word
      60. Dim Step_soll As Integer
      61. Dim Impuls As Word
      62. '---------------------------------------
      63. 'Definition Interrupt's
      64. '---------------------------------------
      65. '---------------------------------------------------
      66. 'Configuration Timer0 ist für GETRC5 belegt
      67. '---------------------------------------------------
      68. '---------------------------------------------------
      69. 'Configuration Timer2 (8bit) für Vorschub
      70. '---------------------------------------
      71. Config Timer2 = Timer , Prescale = 128 'Timer 1ms
      72. On Timer2 Isr_timer_vorschub '1 Khz = 500 Impuls
      73. Const Timer_preload2 = 131
      74. Timer2 = Timer_preload2 'Preload theor. 131
      75. '---------------------------------------
      76. 'Configuration der ALIAS
      77. '---------------------------------------
      78. Takt_vorschub Alias Portb.0 'Ausgang auf Vorschubantrieb
      79. Takt_spindel Alias Portd.7 'Ausgang auf Spindel
      80. Direction Alias Portb.1 'Richtung Vorschub
      81. Enable_vorschub Alias Portb.2 'Freigabe Vorschub
      82. Enable_spindel Alias Portd.5 'Freigabe für Wickelspindel
      83. Oszi Alias Portb.3 'für Takt Spindel Oszi, kann entfallen
      84. Anschlag_links Alias Pind.2
      85. Anschlag_rechts Alias Pind.3
      86. Kanal_a Alias Pind.4 'Pcint Inkrementalgeber Kanal A
      87. Kanal_b Alias Pind.1 'Inkrementalgeber Kanal B
      88. '---------------------------------------
      89. 'Definition der Input_PullUP
      90. '---------------------------------------
      91. Pind.0 = 1
      92. Pind.1 = 1 'Pullup (ist das nötig?
      93. Pind.4 = 1 'Pullup
      94. Pind.2 = 1
      95. Pind.3 = 1
      96. '---------------------------------------
      97. 'Definition der Output_PullUP
      98. '---------------------------------------
      99. Portb.1 = 1 'Pullupm Drehrichtung bei Start festlegen
      100. '---------------------------------------
      101. 'Definition der Output_PullDown
      102. '---------------------------------------
      103. 'Portd.5 = 0 'Spindel AUS
      104. 'Portb.2 = 0 Nötiig???
      105. '---------------------------------------
      106. 'Vorbelegung der Variablen
      107. '---------------------------------------
      108. Enable_vorschub = 1
      109. Enable_spindel = 1
      110. Takt_vorschub = 0
      111. Direction = 1
      112. Oszi = 0
      113. Takt_spindel = 0
      114. Takt_vorschub = 0
      115. Rod = 500
      116. Const Delete_line = " "
      117. Enable Interrupts
      118. '---------------------------------------
      119. 'Hauptschleife
      120. '---------------------------------------
      121. Do
      122. Cls
      123. Gosub Untermenue 'MENU-Taste
      124. Loop
      125. '---------------------------------------
      126. 'Lesen der Fernbedienung
      127. '---------------------------------------
      128. Getzahl:
      129. Do
      130. Getrc5(address , Command)
      131. Command = Command And &B01111111
      132. Loop Until Address < 255 'meine FB sendet Adresse 5
      133. Do 'Prüfung, ob
      134. Getrc5(address , Command_a) 'Taste losgelassen
      135. Loop Until Address = 255
      136. Return
      137. End
      138. '---------------------------------------
      139. 'Untermenü für Schrittbetrieb
      140. '---------------------------------------
      141. Untermenue:
      142. Cls
      143. Ds = 1000
      144. Enable_vorschub = 0
      145. Lcd "Step-Betrieb"
      146. Do
      147. Gosub Getzahl
      148. Select Case Command
      149. Case 3 : Gosub Step_links
      150. Case 4 : Gosub Step_rechts
      151. End Select
      152. Loop Until Command = 82
      153. Enable_vorschub = 1
      154. Return
      155. '-------------------------------------
      156. 'Stepbetrieb
      157. '-----------------------------------
      158. Step_links:
      159. Cls
      160. Locate 1 , 1
      161. Lcd "Step Links"
      162. Direction = 0
      163. Gosub Schleife
      164. Return
      165. Step_rechts:
      166. Cls
      167. Locate 1 , 1
      168. Lcd "Step Rechts"
      169. Direction = 1
      170. Gosub Schleife
      171. Return
      172. Schleife:
      173. Impuls = 0
      174. Enable Timer2
      175. Do
      176. 'Zeit zum Abarbeiten der Schleife bzw. ISR
      177. Loop Until Impuls >= Ds
      178. Disable Timer2
      179. Locate 2 , 1 'zur Fehlersuche eingefügt
      180. Lcd Impuls 'zur Fehlersuche eingefügt
      181. Return
      182. '---------------------------------------
      183. 'Interruptbearbeitung
      184. '---------------------------------------
      185. '---------------------------------------
      186. 'Takterzeugung für den Schrittmotor (Vorschub)
      187. '---------------------------------------
      188. Isr_timer_vorschub:
      189. Timer2 = Timer_preload2
      190. Incr Impuls
      191. Toggle Takt_vorschub
      192. Return
      Alles anzeigen
      Dateien
      Gruß
      Hans

      Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von Hans_L ()

    • djmsc schrieb:

      Das Problem sehe ich hier, denn Config Rc5 benutzt auch den Timer2.
      Das glaube ich nicht. Da er keinen Timer in Config RC5 angegeben hat, wird der Default Timer 0 benutzt.

      Hans_L schrieb:

      Do 'Zeit zum Abarbeiten der Schleife bzw. ISR


      Loop Until Impuls >= Ds
      Das Problem liegt darin, dass die Variable Impuls in der Do-Loop abgefragt wird und evtl gleichzeitig in der ISR incrmentiert wird. Um dies sicher auszuführen, wurde die Option SAFE in die DIM Anweisung eingebaut. Versuche es mal damit, vielleicht reicht das ja.
      Ansonsten musst du die Abfrage mit Disable/Enable Interrupt klammern, was aber in deinem Konstrukt seltsam aussieht, aber geht:

      BASCOM-Quellcode

      1. Do 'Zeit zum Abarbeiten der Schleife bzw. ISR
      2. Enable Interrupts
      3. Disable Interrupts
      4. Loop Until Impuls >= Ds
      Nach dem Enable kann die ISR ausgeführt werden. Steht keine an, werden die Ints sofort wieder abgeschaltet und dann der Vergleich ausgeführt.
    • der Reihe nach:
      RC5 benötigt nur Timer 0,

      Die Lösung mit SAFE bewirkt nichts, ich habe probehalber von Word auf Int gewechselt, auch keine Auswirkung

      Der Vorschlag aus Post 3 (Interrupts in die Schleife) führt zum totalen Stop des Programms, offensichtlich bleibt gar keine Zeit, nach etwa 30min hing das Programm immer noch in der Schleife fest.

      Der letzte (.... Impuls=Ds) brachte die Lösung,
      Verstehen tu ich das nicht,
      wieso wird die Schleife bei größer gleich eher verlassen, und warum immer bei 768?? das ist mir zu hoch
      Gruß
      Hans
    • Hans_L schrieb:

      Der letzte (.... Impuls=Ds) brachte die Lösung,
      Verstehen tu ich das nicht,
      Ein Bedingung nach = ist eher unsicherer. Wird es eins zu groß läuft sie noch 65535 mal durch bis zum nächsten Treffer.
      Die 768 erklären sich mit der Abfrage: er vergleicht immer nur ein Byte. Ist das Low-byte nun 255 und die Isr springt rein bevor er das Highbyte vergleichen kann. Da wird das um eins höher (3). Nun ist 3x256 plus die 255 vom Lowbyte Vergleich = 1023 also größer als 1000. Das das Lowbyte dann 0 geworden ist erfasst er nicht mehr. Bei =1000 ist das Lowbyte 232 da ändert sich das Higbyte nicht, heißt er kommt ach auf die richtige Lösung selbst wenn sich das Lowbyte mitten während der Abfrage ändert. Geht aber schief wenn die isr evt zweimal pro Schleife aufgerufen werden sollte. s.o.

      Es birgt immer Gefahren innerhalb einer Isr die selben Variablen zu verwenden wie im restlichem Programm. Sicherer ist es ein Flag zu setzen z.B. der Vergleich findet in der Isr statt und wenn es (größer)gleich ist setzt sie DS_fertig=1. In der Schleife: dann do..loop until DS_Fertig=1

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Pluto25 ()

    • Hans_L schrieb:

      Der Vorschlag aus Post 3 (Interrupts in die Schleife) führt zum totalen Stop des Programms, offensichtlich bleibt gar keine Zeit, nach etwa 30min hing das Programm immer noch in der Schleife fest.
      Ok, da wirst du wohl zwischen die beiden Befehle noch ein NOP einfügen müssen. Anscheinend wird sonst kein Interrupt aufgerufen.

      Hans_L schrieb:

      Verstehen tu ich das nicht,
      wieso wird die Schleife bei größer gleich eher verlassen, und warum immer bei 768?? das ist mir zu hoch
      Beim Vergleichen lädt der Compiler erst das Low-Byte dann das High-Byte.
      Wenn Impuls jetzt bei 767 steht, also low=255 und high=2. Nun wird in der Schleife das Low Byte in die Vergleichsregister geladen, also 255. In dem Moment kommt der Int und dort wird Impuls inkrementiert. Danach ist also in Impuls low=0 und high=3.
      Nun wird in der Schleife noch das High Byte in die Vergleichsregister geladen, also 3. In den Vergleichsregistern steht jetzt für Impuls 255/3 (=1023) und für Ds 232/3 (=1000). 1023 >= 1000 also springt er aus der Do-Loop.
      Bei Abfrage auf = passiert das nicht. Und solange sichergestellt ist, dass nicht zweimal inkrementiert wird bevor wieder verglichen wird, klappt das auch.
    • das Risiko, dass 2x inkrementiert wird hatte ich auch gesehen, deshalb die Variante mit >=, aber der Schuß ist nach hinten losgegangen.
      Das Risiko besteht aber im eigentlichen Programm trotzdem, da dort noch 2 Interrupts mehr am werkeln sind.
      Das mit Disable Interrupts gefällt mir halt nicht, weil eben noch zwei andere aktiv sind, deshalb habe ich ja nur den betreffenden Timer geschaltet, das scheint aber nicht ausreichend zu sein.
      Gruß
      Hans
    • Hans_L schrieb:

      ja nur den betreffenden Timer geschaltet
      Seine int ausschalten ist auch ohne weiteres möglich. In Deinem Fall aber eher ungünstig da die loop nichts anderes machen würde als das Timer2enable zu schalten. Selbst mit einem nop würde das eher unschön da er länger deaktiviert wie aktiv wäre. (NOP und Enable Timer2 - 2 Takte, do loop until.. ca 20 Takte) Dann stimmt nichts mehr mit dem Timing.
      Eine Möglichkeit wäre wenn er sich selber stoppt/abschaltet und die Loop darauf wachtet das er aus ist. (Loop until TCCR2=0/Timsk2.Toie=0)
      PS Ist es egal das sein Ausgang zufällig bei Low oder Hight stehen bleibt? Dann brennt kein Motor? :D