Emulator für Incrementalgeber

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

    • Darum y, das wird überraschenderweise in der Main nicht verwendet.
      Hier lagen gerade 100µf rum, aber 100n sollten auch gereicht haben?
      Total Durch dreht der mit beiden Ocr1 auf 0 - darum min = 10
      Das Display hält sich erstaunlich gut. Sie mögen so einen Dauerbeschuß eigendlich nicht so gern,
      zumal es vorher in jedem Befehl ein paar isr-Unterbrechungen mitmachen musste. Es hat wohl einen guten Tag :D
    • So sieht das schon fast gut aus leide ubernimmt er es wohl nur jedes zweite mal ;(
      Und irgendwas stört gewaltig. Ein vergessenes Push? Oder falschübernehme wenn die isr während der Berechnung aufgerufen wird ?

      Source Code

      1. $regfile = "m8adef.dat"
      2. $crystal = 8000000
      3. $hwstack = 40
      4. $swstack = 40
      5. $framesize = 40
      6. $lib "YwRobot_Lcd_i2c.lib"
      7. Config Scl = Portc.5
      8. Config Sda = Portc.4
      9. I2cinit
      10. Ddrb = $c7
      11. Config Lcd = 16x2
      12. Const Pcf8574_lcd = &H7C
      13. Dim Lcd_backlight As Byte : Set Lcd_backlight
      14. Initlcd
      15. Waitms 60
      16. Cls
      17. Config Adc = Single , Prescaler = Auto , Reference = Avcc
      18. Dim N As Word , N2 As Word , Nalt As Word
      19. Dim I As Word , T As Word , T2 As Word , A As Byte
      20. Dim T3 As Word , B As Byte
      21. Dim Tx As Word , T2x As Word
      22. Lcd "Drehz.:"
      23. Locate 2 , 1
      24. Lcd "Ocr "
      25. Config Watchdog = 2048
      26. Start Watchdog
      27. On Oc1a Oca_isr Nosave
      28. Enable Oc1a
      29. On Oc1b Ocb_isr Nosave
      30. A = $f2
      31. B = $e2 'Tccr1a
      32. Ocr1b = 15000 : T2 = 15000
      33. Ocr1a = 30000 : T = 30000
      34. Icr1 = 60000
      35. Tccr1a = $f2
      36. Tccr1b = $19
      37. Enable Interrupts
      38. Do
      39. N = Getadc(0) * 6
      40. If N < 10 Then N = 10
      41. Locate 1 , 9
      42. N2 = N / 10
      43. Tx = 24000 / N2
      44. ' If T.0 = 1 Then Incr T 'ungrade Ocr vermeiden??
      45. T2x = Tx / 2
      46. N = 24000 / Tx
      47. N = N * 10
      48. Lcd N
      49. Lcd " Upm "
      50. N2 = N / 10
      51. T = 24000 / N2
      52. T2 = T / 2
      53. I = T * 2
      54. T3 = T + T2
      55. If N <> Nalt Then ' <> Nalt Then
      56. Icr1 = I
      57. Ocr1a = T
      58. ' Ocr1b = T2
      59. Nalt = N
      60. End If
      61. Locate 2 , 5
      62. Lcd T
      63. Lcd " "
      64. Lcd T2
      65. Lcd " "
      66. Reset Watchdog
      67. Loop
      68. Oca_isr:
      69. !push r16
      70. Loadadr B , Y
      71. !sbi tifr,3
      72. !ld r16,y
      73. !out Tccr1a,r16
      74. !ld r16,-y
      75. !out Ocr1bh,r16
      76. !ld r16,-y
      77. !out Ocr1bl,r16
      78. !sbi timsk,3
      79. !pop r16
      80. Return
      81. Ocb_isr:
      82. !push R16
      83. Loadadr A , Y
      84. !ld r16,y
      85. !out Tccr1a,r16
      86. !ld r16,-y
      87. !out Ocr1bh,r16
      88. !ld r16,-y
      89. !out Ocr1bl,r16
      90. !cbi timsk,3
      91. !pop R16
      92. Return
      Display All
    • So jetzt kann ich mal ein Ergebnis liefern.

      Also das AB-Signal in Software zu generieren scheitert, da es zittert (was mich stört) und die Ausgabefrequenz nach oben sehr durch den Controller-Takt begrenzt ist. 100kHz (n=6000 mit Inkrementalgeber mit 1000 Pulsen) wird nicht erreicht.

      Rein per Hardware-PWM, also nur durch interne Hardware, zu generieren scheitert auch, weil die Phasenlage nicht zu kontrollieren ist.

      Mischlösungen, also ein Signal per PWM oder Toggeln zu erzeigen und die 2. Phase per Interrupt ist auch nicht viel besser. Da hier wieder das jittern auszugleichen ist, was wieder bedeutet, dass man die 100kHz nur mit fast 100% Controller-Auslastung erreicht.

      Also alleine der Atmega-Controller schafft es nicht.

      Also dachte ich, das mal mit externer Hardware am Controller zu versuchen.
      Also den Controller nur als AD-Wandler für die gewünschte Frequenz und als Generator für die Grundfrequenz zu verwenden, und an einem Port ein 2-Bit breites Binärzählersignal auszugeben, welches dann mit Logikschaltung in das AB-Signal zu verwandeln ist.

      Also schnell mal eine Werte-Tabelle erstellt, Binärwert als Eingang und die Signale A und B als Ausgang (was eigentlich dem 2-Bit Gey-Code entspricht). Da hat sich schnell herausgestellt, dass das Signal einfach mit einem Flip-Flop und 2 Ex-Or Gatter erstellt werden kann.

      Hier das Schaltbild dazu.
      Bildschirmfoto vom 2021-04-11 08-36-53.png

      Der Controller liefert also mit toggelndem Pin am OC1A die doppelte Frequenz, bezogen auf die gewünschte Inkrementalgeber-Frequenz. Die Anschluss Phase bestimmt, ob ob das eine Signal invertiert wird oder nicht.

      Die mögliche AB-Signal Frequenz liegt jetzt bei weit über 100kHz. Mit einem Incrementalgeber mit 10000 Pulse je Umdrehung wird problemlos ein AB-Signal mit 1MHz ausgegeben.

      Das Signal wird durch 2 Standard TTL-Bausteine erzeugt. Im Test habe ich anstelle der Ex-Or Gatter (weil nicht vorhanden) diese diskret mit 4 Nand aufgebaut. Siehe Wikipedia.
      Die CPU-Auslastung ist hierbei bei praktisch 0%. Lediglich zum AD-Wandeln und das OB1A-Register setzen werden wenige Takte benötigt.

      Es ist also noch genügend Reserve vorhanden, im Falle das jemand erweitern will mit Tasten, Display und serieller Anbindung für Remote-Steuerung etc.

      Im Anhang noch das vollständige Schaltbild als PDF.

      BASCOM Source Code: Incrementalgeber Emulator-Programm

      1. $Regfile = "m168def.dat"
      2. $HWStack = 40
      3. $SWStack = 40
      4. $FrameSize = 40
      5. $Crystal = 16000000 ' Quarz
      6. Config SubMode = New
      7. Const PIN_AIN = 0 ' ADC0 Soll-Drehzahl
      8. ' mögliche Inkrementalgeber
      9. Const I_Geber_100 = 100 ' Geber mit 100 Pulse/Ump
      10. Const I_Geber_500 = 500 ' Geber mit 500 Pulse/Ump
      11. Const I_Geber_1024 = 1024 ' Geber mit 1024 Pulse/Ump
      12. Const I_GEBER_TEST = 10000
      13. Const I_Geber = I_GEBER_1024 ' Geber setzen
      14. Dim F_Out as Long ' Ausgabefrequenz des Gebers
      15. ' ------------------------------------
      16. ' Routinen
      17. ' ------------------------------------
      18. ' Berechnung der Ausgabefrequenz des Gebers
      19. Function getFOut() as Long
      20. Local n as Integer ' Drehzahl
      21. Local f as Single ' Frequenz
      22. ' n-max * Adc 6000 * Adc
      23. ' frq = -------------- = -----------
      24. ' adc-max * 60 1000 * 60
      25. n = GetAdc(PIN_AIN) * 6 ' Soll-Drehzahl einlesen
      26. ' Drehzahl (rpm) in Frequenz umrechnen
      27. f = n ' in Single wandeln
      28. f = f / 60 ' Umrechnung Drehzahl in Frq
      29. ' Berechnung Ausgabe-Frequenz mit gewähltem Inkremental-Geber
      30. f = f * I_GEBER
      31. getFOut = f ' in Long umwandeln
      32. End Function
      33. ' Registerwerte Timer1 berechnen und setzen
      34. Sub setTimer()
      35. Local R_ICR as Long
      36. Local tmp as Word
      37. ' Register berechnen / setzen
      38. R_ICR = _xtal \ F_Out ' ICR1-Registerwert berechnen
      39. R_ICR = R_ICR \ 2 ' Da Pin getoggelt wird, brauche ich doppelte Frequenz
      40. tmp = LowW(R_ICR) ' berechneter Registerwert in Word wandeln
      41. OCR1A = tmp ' Register setzen
      42. End Sub
      43. ' ------------------------------------
      44. ' Initialisierung
      45. ' ------------------------------------
      46. Config ADC = Single , Prescaler = Auto , Reference = AVCC
      47. Config Portb.0 = Input : Set PortB.0 ' PullUp an
      48. Signal_A Alias PortB.1
      49. Signal_B Alias PortB.2
      50. Config Signal_A = Output ' OC1A
      51. Config Signal_B = Output ' OC1B
      52. Config Timer1 = Timer , Compare_A = Toggle , Prescale = 1 , CLEAR_TIMER = 1
      53. Enable Interrupts
      54. ' ------------------------------------
      55. ' Hauptschleife
      56. ' ------------------------------------
      57. Do
      58. F_Out = GetFOut() ' Ausgabe-Frequenz des Gebers berechnen
      59. Call SetTimer() ' Register für Frequenzausgabe setzen
      60. Waitms 100
      61. Loop
      Display All
      Files
      • Geber.pdf

        (20.6 kB, downloaded 8 times, last: )