PCA9685 12 Bit PWM Controller

    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!

    • PCA9685 12 Bit PWM Controller

      Der PCA9685 ist ein 16Kanal I2C PWM Controller mit 12 Bit Auflösung, geeignet für LED und oft auch für Servo Ansteuerung benutzt da das Servo Signal an sich ja nichts anderes als ein PWM Signal ist.

      Leider liefen die vom mir gefundenen Programmbeispiele für den PCA9685 nicht richtig und kommentiert war da auch nicht viel. Die ist jetzt kein umfassendes Werk, ein Blick ins Datenblatt wird noch mehr Features als meine Beispiele hier zeigen. Auch sind die eingestellten Werte eher als grober Startwert zu sehen, z.b. ist der Oszillator bei meinem IC ist nicht der genaueste, ich benötige z.b. den Vorteiler von 133 um auf 50 Hz zu kommen um mein Servo hat auch einen wesentlich grösseren Verstellbereich als 2ms.

      Zuerst muss man dem IC den zur Ausgangsfrequenz passenden Vorteiler/Prescaler einstellen, standardmäßig läuft er sonst auf 200Hz Ausgangsfrequenz. Möglich sind werte von 24 bis 1625Hz. Leider lässt sich die Frequenz nur einstellen wenn der Interne 25MHz Oszillator im Sleep Mode (also aus) ist. Das automatische Hochzählen der I2C Adressen ist auch nicht automatisch eingeschaltet, das wird gleich mit erledigt, ansonsten müsste man jede Adresse einzeln anwählen anstatt aufeinanderfolgende Adressen einfach nacheinander schreiben zu können:

      Quellcode

      1. 'Prescalerregister setzen, dafür muss das Oszillator bit5 von Mode 1ausgeschaltet sein sein
      2. 'Auto increment der Adressregister ist per default aus, einschalten mit bit6 vom Mode 1
      3. I2cstart
      4. I2cwbyte adressPCA9685_write
      5. I2cwbyte &H00
      6. I2cwbyte &B0011_0000 '&H21, auto increment on, sleep mode on
      7. I2cstop
      8. 'Servo signal 20MS=50Hz, impulslänge 1-2ms, verstellbereich min/max demnach 205 schritte;bereich min/max= 205-410
      9. I2cstart
      10. I2cwbyte adressPCA9685_write
      11. I2cwbyte &B1111_1110 '&HFE = set to PRE_SCALE register
      12. I2cwbyte &B0111_1001 '50 hz Osc_CLK=( 25000000/(4096*50)-1 = 121) set prescale, sleep mode must be 1 to set scaler
      13. I2cstop
      14. I2cstart
      15. I2cwbyte adressPCA9685_write
      16. I2cwbyte &H00
      17. I2cwbyte &B0010_0000 'auto increment on, sleep mode off
      18. I2cstop
      Alles anzeigen





      Der PCA9685 hat einen internen 25MHz Oszillator, die Ausgangsfrequenz berechnet sich nach dem Vorteiler und der Auflösung von 12Bit: =( 25000000/(4096*50)-1 für 50Hz welche die Servos benötigen also einen Vorteiler von 121.

      Jetzt muss noch eingestellt werden welche Art von Last am IC hängt, er kann nämlich FETs direkt schalten sowie auch LEDs bis 20mA pro Kanal direkt Versorgen. In diesem Fall stellen wir Servo ein:

      Quellcode

      1. I2cstart
      2. I2cwbyte adressPCA9685_write
      3. I2cwbyte &H01
      4. 'I2cwbyte &B0001_0000 'ausgang definieren INV=1 /outdrv =0 for direct led connection
      5. I2cwbyte &B0000_0100 'ausgang definieren INV=0 /outdrv =1 for direct servo connection
      6. I2cstop
      pic1.jpg
      Ausgangsfrequenz und Ausgangscharakteristik können leider nur global pro IC eingestellt werden. Das bedeutet alle Ausgänge laufen mit der gleichen Frequenz und theoretisch nur LEDs oder nur Servos. Wenn man die ein und ausschaltpunkte neu anpasst läuft das Servo aber auch mit einem Pullup unter der LED Einstellung, in dieser Einstellung ist das Signal ja invertiert und das Servo würde in den mechanischen Anschlag fahren.

      Ein Servo Signal ist zwischen 1ms und 2 ms lang und kommt mit 50 Hz (20ms Wiederholung), ein durchlauf (signalperiode) des PCA9685 hat 12 Bit bzw. 4095 Takte. 1 Millisekunde sind also knapp 205 Takte womit das Servosignal zwischen 205 und 410 Takten für mix/max liegt.

      servo1.jpg

      Der PCA hat zwei Schaltpunkte pro Kanal, den Einschaltpunkt und Ausschaltpunkt.

      pic2.jpg

      Beide werden durch eine Word-Variable gesetzt, zuerst wird das niedrigwertigere Byte übertragen, dann das höherwertige jedes Punktes. Im Beispiel hier wird bei Zählerstand 0 eingeschaltet und bei 205 wieder ausgeschaltet und somit ein 1ms Signal erzeugt. Auch werden in diesem Beispiel hier werden gleichzeitigallen 16 Kanäle mit den gleichen Werten eingestellt:


      Quellcode

      1. 'Alle 16 kanäle gleichzeitig ansprechen ab adresse FA servo minimalwert
      2. PCFword_on =0
      3. PCFword_off= 205 'beginn des signals immer bei 0
      4. I2cstart
      5. I2cwbyte adressPCA9685_write
      6. I2cwbyte &HFA
      7. I2cwbyte LOW(PCFword_on)
      8. I2cwbyte High(PCFword_on)
      9. I2cwbyte LOW(PCFword_off)
      10. I2cwbyte High(PCFword_off)
      11. I2cstop
      12. wait 5
      13. 'Alle 16 kanäle gleichzeitig ansprechen ab adresse FA servo maximalwert
      14. PCFword_on =0
      15. PCFword_off= 410 'beginn des signals immer bei 0
      16. I2cstart
      17. I2cwbyte adressPCA9685_write
      18. I2cwbyte &HFA
      19. I2cwbyte LOW(PCFword_on)
      20. I2cwbyte High(PCFword_on)
      21. I2cwbyte LOW(PCFword_off)
      22. I2cwbyte High(PCFword_off)
      23. I2cstop
      24. Wait 5
      Alles anzeigen
      Sieht dann so aus:
      2nd.jpg


      Wenn man alle Kanäle gleichzeitig ein oder ausschalten will kann man statt den 4 Bytes für ON und OFF auch einfach das 5te Bit aus dem höheren Byte schreiben:


      Quellcode

      1. 'vor dem nächsten test alle ausgänge abschalten, 100% on or off funktioniert auch über h-bit5:
      2. I2cstart
      3. I2cwbyte adressPCA9685_write
      4. I2cwbyte &HFD
      5. I2cwbyte &B0001_0000
      6. I2cstop

      Das vorherige Beispiel hat den nachteil das alle Signale zur gleichen Zeit beginnen, für die Stromversorgung ist so etwas eine sehr hohe belastung. Besser wäre es wenn man das Signal an jeden Kanal etwas zeitverzögert ausgibt:

      Quellcode

      1. 'default werte damit Servo nicht in Anschlag fährt
      2. PCFword_on=0
      3. PCFword_off= 307
      4. do
      5. PCFword_on_add = PCFword_on + 255
      6. PCFword_off_add = PCFword_off + 255
      7. 'Ausgänge einzeln ansprechen, Ausgang 0:
      8. I2cstart
      9. I2cwbyte adressPCA9685_write
      10. I2cwbyte Aus0
      11. I2cwbyte LOW(PCFword_on)
      12. I2cwbyte HIGH(PCFword_on)
      13. I2cwbyte Low(PCFword_off)
      14. I2cwbyte High(PCFword_off)
      15. I2cstop
      16. 'Ausgänge einzeln ansprechen, Ausgang 1:
      17. I2cstart
      18. I2cwbyte adressPCA9685_write
      19. I2cwbyte AUS1
      20. I2cwbyte LOW(PCFword_on_add)
      21. I2cwbyte High(PCFword_on_add)
      22. I2cwbyte Low(PCFword_off_add)
      23. I2cwbyte High(PCFword_off_add)
      24. I2cstop
      25. ' Ausgänge kontinuierlich schreiben Ausgang 2-3:
      26. I2cstart
      27. I2cwbyte adressPCA9685_write
      28. I2cwbyte AUS2
      29. I2cwbyte LOW(PCFword_on)
      30. I2cwbyte HIGH(PCFword_on)
      31. I2cwbyte Low(PCFword_off)
      32. I2cwbyte High(PCFword_off)
      33. I2cwbyte LOW(PCFword_on_add) 'Hier beginnt Speicherbereich Ausgang 3
      34. I2cwbyte High(PCFword_on_add)
      35. I2cwbyte Low(PCFword_off_add)
      36. I2cwbyte High(PCFword_off_add)
      37. I2cstop
      38. 'Hochzählen bis zum maximum, Wenn erreicht zählrichtung umkehren
      39. if direction = 0 then
      40. incr PCFword_off
      41. if PCFword_off = 440 then direction = 1
      42. end if
      43. 'Runterzählen bis zum minimum, wenn erreicht zählrichtung umkehren
      44. if direction = 1 then
      45. decr PCFword_off
      46. if PCFword_off = 209 then direction = 0
      47. end if
      48. waitms 500
      49. loop
      Alles anzeigen
      Dadurch das man Start und Stopp Punkte pro Kanal setzen kann ist ein Versatz ohne Probleme möglich. Im vorherigen Beispiel fährt das Servo langsam hin und her. Das Signal vom zweiten Kanal wird um ca 1,2ms später (wert 255) ausgegeben.


      3rd.jpg

      Zur Erreichung einer Position muss man die Signalwerte aber nicht wie eben gezeigt hochzählen, das Servo vergleicht ja selber Soll-wert vom Signal und Ist-Stellung und fährt dann automatisch in die Soll- Position.


      Das vom mir eingesetzte Modul:

      PCA9685.jpg




      Alle Adresseingänge liegen per Default auf logisch null somit ist der PCA9685 unter der schreibdresse Hex 80 zu erreichen. Spannungsversorgung der Servo Stiftleisten über PIN „V+“ oder die Schraubklemme. Spannungsversorgung vom PCA über PIN „VCC“.

      Alle Ausgänge sind über 220Ohm Widerstände herausgeführt. SDA und SCL haben 10K Pullups.

      Im Gegensatz zum Adafruit Modell hat der Chinaman die Verpolschutzschaltung an „V+“ eingespart.



      Tobias
      Dateien

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von Schraubbaer () aus folgendem Grund: Testprogramm angefügt

    • Schraubbaer schrieb:

      fand den nicht gut genug fürs lexikon, kann ich aber ja immer noch machen...

      Tobias
      Naja, das beschreibt ja schon einen speziellen Schaltkreis und derjenige, der eine Beschreibung dafür sucht wird sicher sehr dankbar dafür sein. Ich finde das paßt schon.

      Gruß Christian
      Wenn das die Lösung ist, möchte ich mein Problem wieder haben.
    • So ein Mist, just wie es der Teufel will, bin ich auch gerade am PCA9685 dran gewesen.
      Ich hab jetzt die Config zum Teil von dir übernommen, schraubbaer ;)
      Ich habe die Software für alle 16 Servos geschrieben, wobei der Servowert in einem Word-Array steckt.
      Es hängen 9 Servos dran, mehr hab ich nicht auspacken wollen und mehr passen auch nicht an die Aufhängung.
      Die Wiederholrate liegt bei 100Hz, also 10ms, die Servos sind so etwas schneller beim Ansprechen.
      Die Pulse werden zeitversetzt gesendet, um die angesprochene Stromaufnahme in Grenzen zu halten.
      Trotzdem wird die kleine Schutzdiode auf dem PCA9685 Board mächtig heiß.

      Gruß, Michael

      BASCOM-Quellcode: PCA9685 mit Arduimo Nano und 9 Servos

      1. 'Beispiel Servosteuerung mit PCA9685
      2. 'Michael @ bascomforum . de
      3. $regfile = "M328pdef.dat"
      4. $crystal = 16000000
      5. $baud = 9600
      6. $hwstack = 40
      7. $swstack = 20
      8. $framesize = 40
      9. Config Scl = Portc.5 'SCL
      10. Config Sda = Portc.4 'SDA
      11. Const Schreibadresse = &B10000000
      12. Const Leseadresse = &B10000001
      13. Led Alias Portb.5 'LED auf Arduino Nano Board (D13)
      14. Ddrb.5 = 1
      15. Dim Servo(16) As Word 'Alle Servos im Bereich zw.ca 409 und 820
      16. Dim P_low As Word
      17. Dim P_high As Word
      18. Dim I As Byte 'Hilfsvariable
      19. Dim Z As Byte 'Hilfsvariable
      20. Dim Richtung As Bit
      21. Richtung = 1
      22. 'Software Reset
      23. I2cstart
      24. I2cwbyte Schreibadresse
      25. I2cwbyte &B00000110 'Soft Reset
      26. I2cstop
      27. Waitms 1
      28. I2cstart
      29. I2cwbyte Schreibadresse
      30. I2cwbyte &H00
      31. I2cwbyte &B0011_0000 '&H21, auto increment on, sleep mode on
      32. I2cstop
      33. 'Servo signal 10ms, impulslänge 1-2ms, verstellbereich min/max 410 Schritte
      34. I2cstart
      35. I2cwbyte Schreibadresse
      36. I2cwbyte &B1111_1110 '&HFE = set to PRE_SCALE register
      37. I2cwbyte &B0011_1100 '100 hz Osc_CLK=( 25000000/(4096*50)-1 = 60)
      38. I2cstop
      39. I2cstart
      40. I2cwbyte Schreibadresse
      41. I2cwbyte &H00
      42. I2cwbyte &B0010_0000 'auto increment on, sleep mode off
      43. I2cstop
      44. Waitus 500 'Aufwachen wegen Sleep
      45. Do
      46. Toggle Led
      47. 'Spielerei
      48. If Richtung = 1 Then
      49. Incr Z
      50. Else
      51. Decr Z
      52. End If
      53. If Z >= 205 Then
      54. Richtung = 0
      55. End If
      56. If Z = 0 Then
      57. Richtung = 1
      58. End If
      59. 'Servosignale werden ab hier generiert, der Bereich liegt zw.409 und 820
      60. Servo(1) = Z
      61. Servo(1) = Servo(1) + Servo(1)
      62. Servo(1) = Servo(1) + 409
      63. Servo(2) = Z
      64. Servo(2) = Servo(2) + Servo(2)
      65. Servo(2) = 410 - Servo(2)
      66. Servo(2) = Servo(2) + 409
      67. Servo(3) = Servo(1)
      68. If Richtung = 0 Then
      69. Servo(4) = 409
      70. Else
      71. Servo(4) = 819
      72. End If
      73. Servo(5) = Z / 38
      74. Servo(5) = Servo(5) * 81
      75. Servo(5) = 410 - Servo(5)
      76. Servo(5) = Servo(5) + 409
      77. Servo(6) = Servo(1)
      78. Servo(7) = Servo(1)
      79. Servo(8) = Z + 615
      80. Servo(9) = Servo(2)
      81. 'Bereich begrenzen für den Notfall
      82. For I = 1 To 16
      83. If Servo(i) < 360 Then Servo(i) = 360
      84. If Servo(i) > 870 Then Servo(i) = 870
      85. Next
      86. 'Werte an PCA9685 schicken
      87. I2cstart
      88. I2cwbyte Schreibadresse
      89. I2cwbyte 6 'Adresse erstes Servo
      90. P_low = 0
      91. For I = 1 To 16
      92. P_high = P_low + Servo(i)
      93. I2cwbyte Low(p_low)
      94. I2cwbyte High(p_low)
      95. I2cwbyte Low(p_high)
      96. I2cwbyte High(p_high)
      97. P_low = P_low + 200 'nächster Puls fängt zeitversetzt an
      98. Next
      99. I2cstop
      100. Waitms 1
      101. Loop
      102. End
      Alles anzeigen
      PCA9685_Arduino_9_Servos.jpg

    • Mit 100Hz hatte ich auch probiert, da kam aber mein Dampfbetriebenes Servo von Anfang der 80er nicht mehr mit. Da das Lexikon zumindest mal angedacht war hab ich mich dann für die Offizielle version mit 50Hz entschieden damit keiner in die Falle läuft.
      Der chip an sich kann ja noch mehr, z.b. gruppenbefehle an einstellbare sub-adressen auf die dann mehrere chips gleichzeitig reagieren. Hab momentan nur ein modul, die nächsten sind aber schon geordert.

      Tobias
      P.s.
      Halterung??!! Einschubholz sagt der Schreiner dazu, weils genau in den Einschub vom Ofen passt :whistling: