shift6out(), eine Prozedur zur seriellen Ausgabe von 6 bytes an 6 pins parallel

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

  • shift6out()
    Speziell zur Ansteuerungen von mehrfarbigen Led-Matrixen geeignet.
    Mehrfarbige Ledmatrixen mit 16X32 oder 32X64 Leuchtstellen haben in der Regel (ich kenn keine anderen) für jede Farbe ein bis 2 Sätze an Schieberegistern. In diese werden bitweise die Daten eingeschoben und per Signalflanke an einem 'Übernahme-pin' an die Ausgänge der Ledtreiber übertragen.
    Diese Schieberegister benötigen zum Übernehmen der anliegenden bits einen clock-Impuls. Dieser clock-pin ist aber von allen Schieberegistern zusammen auf einen Anschluß geschaltet. Mit jedem clock-Puls werden die Pegel an allen Eingängen der Schieberegister gleichzeitig übernommen.
    Bascom bietet zwar mit shiftout() und spiout() Prozeduren, die einzelne bits eines bytes an einem Ausgang bereit stellen und generieren auch eine clock-Flanke, um das angeschlossene Schieberegister zur Übernahme des bits zu steueren, das geht aber eben nur mit einem Ausgang.
    Shift6out() kann bis zu 6 bits von 6 verschiedenen bytes an 6 verschiedenen pins parallel ausgeben und eine clock-Flanke dazu generieren. Damit können RGB-Ledmatrixen schnell und einfach in einer interrupt-Routine mit Daten gefüllt werden.
    Shift6out() besteht aus einem Assemblercode, der hauptsächlich von @"Galahat" erdacht wurde, ich habe den dann noch ein bisschen erweitert :) .
    Sollten nur 3 bits parallel ausgegeben werden, kann der code natürlich gekürzt werden. Ich denke, man erkennt durch die Bezeichnungen und dem Kommentar, an welchen Stellen.

    Die Anwendung ist einfach.
    Hier einmal ein Beispiel für eine RGB-Matrix, 16x32,
    mit je 2 Eingängen für jede Farbe
    R1, R2, G1, G2, B1, B2
    einem clock-Eingang
    CLK
    einem latch-Eingang (Übernahme)
    LAT
    2 Eingänge, die die jeweils bediente Hälfte des displays auswählen
    Die Anzahl der Schieberegister reicht hier nur für die halbe Anzahl der Leds. Es muss daher das display 2x mit Daten gefüllt werden, um alle Leds ansprechen zu können.
    A, B
    einen OE-Eingang, mit dem die Leds gedimmt werden können
    OE
    Es müssen zuerst die benötigten Port-pins als Ausgänge konfiguriert werden. Für OE wählt man einen PWM-Ausgang des verwendeten timers.
    Der Assemblercode benötigt spezielle alias-Namen und Konstanten für die pin-Nummern.

    BASCOM-Quellcode

    1. 'ports--------------------
    2. P_r1 Alias Porte.3 : Config P_r1 = Output 'R1-Anschluß am display
    3. P_g1 Alias Porte.4 : Config P_g1 = Output 'G1-Anschluß am display
    4. P_b1 Alias Porte.5 : Config P_b1 = Output 'B1-Anschluß am display
    5. P_r2 Alias Porte.6 : Config P_r2 = Output 'R2-Anschluß am display
    6. P_g2 Alias Porte.7 : Config P_g2 = Output 'G2-Anschluß am display
    7. P_b2 Alias Portb.0 : Config P_b2 = Output 'B2-Anschluß am display
    8. P_a Alias Portf.1 : Config P_a = Output 'A-Anschluß am display
    9. P_b Alias Portf.0 : Config P_b = Output 'B-Anschluß am display
    10. P_ckl Alias Portb.1 : Config P_ckl = Output 'CLK-Anschluß am display
    11. P_lat Alias Portb.2 : Config P_lat = Output 'LAT-Anschluß am display
    12. P_oe Alias Portb.6 : Config P_oe = Output 'OE-Anschluß am display PWM timer1 channel B
    13. 'alias-Namen und Konstanten für den Assemblerteil
    14. Dout_port_r1 Alias Porte
    15. Dout_port_g1 Alias Porte
    16. Dout_port_b1 Alias Porte
    17. Dout_port_r2 Alias Porte
    18. Dout_port_g2 Alias Porte
    19. Dout_port_b2 Alias Portb
    20. Const Dout_pin_r1 = Pe3
    21. Const Dout_pin_g1 = Pe4
    22. Const Dout_pin_b1 = Pe5
    23. Const Dout_pin_r2 = Pe6
    24. Const Dout_pin_g2 = Pe7
    25. Const Dout_pin_b2 = Pb0
    26. Shift_clock_port Alias Portb
    27. Const Shift_clock_pin = Pb1
    28. ' R1 G1 B1 R2 G2 B2
    29. Declare Sub Shift6out(byreg R18 As Byte , Byreg R19 As Byte , Byreg R20 As Byte , Byreg R21 As Byte , Byreg R22 As Byte , Byreg R23 As Byte )
    30. ...
    31. 'Interrupt service
    32. Display_refresh: 'Überträgt Teile des Bildspeichers auf die displays
    33. Load Timer2 , Timer2reload
    34. Toggle Page_counter.0
    35. For Mem_ofset = 0 To 128 Step 64 'hier 3x 16x32 displays in Reihe
    36. If Page_counter.0 = 1 Then
    37. Restore Byte_order_a 'Reihenfolge, in welcher die bytes des Bildspeichers ausgegeben werden
    38. Else
    39. Restore Byte_order_b
    40. End If
    41. For B_1 = 0 To 15
    42. Read Byte_num_1
    43. Byte_number_1 = Byte_num_1 + Mem_ofset
    44. Byte_number_2 = Byte_number_1 + 32
    45. Shift6out Memory_red(byte_number_1) , Memory_green(byte_number_1) , Memory_blue(byte_number_1) , Memory_red(byte_number_2) , Memory_green(byte_number_2) , Memory_blue(byte_number_2)
    46. Next B_1
    47. Next Mem_ofset
    48. Pwm1b = 0 'display dunkel schalten, um Geisterpixel zu unterdrücken
    49. Waitus 100 'wait until PWM is 0
    50. P_lat = 1 : P_lat = 0 'neu eingeshiftete Daten an die Ausgänge/Leds übergeben
    51. P_a = Page_counter.0 'einstellen der passenden Displayhälfte
    52. P_b = Not Page_counter.0
    53. Pwm1b = Brightness 'display wieder einschalten
    54. Return
    55. ' R1 G1 B1 R2 G2 B2
    56. Sub Shift6out(byreg R18 As Byte , Byreg R19 As Byte , Byreg R20 As Byte , Byreg R21 As Byte , Byreg R22 As Byte , Byreg R23 As Byte )
    57. 'MSB first
    58. $asm
    59. LDI r17,8 'R17 als Zähler für 8 Durchgäne vorladen
    60. Loop_shift2out:
    61. in R16, dout_port_r1 'Register 16 mit dem Ausgabeport laden
    62. BST r18,7 'bit7 des Register R18 in den Zwischenspeicher
    63. BLD r16,Dout_pin_r1 'Zwischenspeicher auf die Ausgabepinnummer laden
    64. Out Dout_port_r1 , R16 'R16 an den Ausgabeport übergeben
    65. in R16, dout_port_g1
    66. BST r19,7
    67. bld r16,Dout_pin_g1
    68. Out Dout_port_g1 , R16
    69. in R16, dout_port_b1
    70. BST r20,7
    71. bld r16,Dout_pin_b1
    72. Out Dout_port_b1 , R16
    73. in R16, dout_port_r2
    74. BST r21,7
    75. BLD r16,Dout_pin_r2
    76. Out Dout_port_r2 , R16
    77. in R16, dout_port_g2
    78. BST r22,7
    79. bld r16,Dout_pin_g2
    80. Out Dout_port_g2 , R16
    81. in R16, dout_port_b2
    82. BST r23,7
    83. bld r16,Dout_pin_b2
    84. Out Dout_port_b2 , R16
    85. SBI shift_clock_Port, shift_clock_Pin 'high auf den CLK-pin legen
    86. LSl r18 'R18 nach links shiften, damit nächstes byte an der Stelle bit7 steht
    87. LSl r19
    88. lsl r20
    89. lsl r21
    90. lsl r22
    91. lsl r23
    92. dec r17
    93. CBI shift_clock_Port, shift_clock_Pin 'low auf den CLK-pin legen
    94. BRnE loop_shift2out ; if = 0 exit
    95. $end Asm
    96. End Sub
    97. Byte_order_a:
    98. 'vertical
    99. Data 20 , 28 , 21 , 29 , 4 , 12 , 5 , 13 , 22 , 30 , 23 , 31 , 6 , 14 , 7 , 15
    100. 'horizontal Data 10 , 8 , 26 , 24 , 14 , 12 , 30 , 28 , 42 , 40 , 58 , 56 , 46 , 44 , 62 , 60
    101. Byte_order_b:
    102. 'vertical
    103. Data 16 , 24 , 17 , 25 , 0 , 8 , 1 , 9 , 18 , 26 , 19 , 27 , 2 , 10 , 3 , 11
    104. 'horizontal Data 11 , 9 , 27 , 25 , 15 , 13 , 31 , 29 , 43 , 41 , 59 , 57 , 47 , 45 , 63 , 61
    Alles anzeigen
    Die im Beispiel zu findenden Tabellen 'byte_order_a' und 'byte_order_b' sind 'Übersetzungen' von meinem linearen Bildspeicher 'Memory_red(), Memory_green() und Memory_blue()' zu dem Muster, wie die in das display eingeschobene bytes auf dem display landen. Die werden nämlich, von display-Typ zu Typ unterschiedlich, nicht linear, schön in einer Reihe oder Spalte abgelegt, sondern in einem regelmäßigen Muster.
    Mit der Flanke am LAT-pin werden die zuvor eingeshifteten Daten an die Ledtreiber übergeben. Dazu sollte man das display dunkel stellen, weil im Anschluß auch noch auf eine andere Gruppe von Leds umgeschaltet wird. Hier mit A und B.
    Dabei ist zu beachten, dass die PWM nicht sofort reagiert, da der timer dazu erst wieder bei 0 starten muss. Daher wird einfach bisschen mit waitus 100 gewartet, dass die Leds wirklich aus sind und so während des Umschaltens keine Geisterpixel entstehen können.
    Das oben gezeigte Beispiel schiebt bit7 als erstes bit aus, wenn mit bit0 begonnen werden soll, dann muss der folgende code verwendet werden.

    BASCOM-Quellcode

    1. ' R1 G1 B1 R2 G2 B2
    2. Sub Shift6out(byreg R18 As Byte , Byreg R19 As Byte , Byreg R20 As Byte , Byreg R21 As Byte , Byreg R22 As Byte , Byreg R23 As Byte )
    3. 'LSB first
    4. $asm
    5. LDI r17,8 'R17 als Zähler für 8 Durchgäne vorladen
    6. Loop_shift2out:
    7. in R16, dout_port_r1 'Register 16 mit dem Ausgabeport laden
    8. BST r18,0 'bit0 des Register R18 in den Zwischenspeicher
    9. BLD r16,Dout_pin_r1 'Zwischenspeicher auf die Ausgabepinnummer laden
    10. Out Dout_port_r1 , R16 'R16 an den Ausgabeport übergeben
    11. in R16, dout_port_g1
    12. BST r19,0
    13. bld r16,Dout_pin_g1
    14. Out Dout_port_g1 , R16
    15. in R16, dout_port_b1
    16. BST r20,0
    17. bld r16,Dout_pin_b1
    18. Out Dout_port_b1 , R16
    19. in R16, dout_port_r2
    20. BST r21,0
    21. BLD r16,Dout_pin_r2
    22. Out Dout_port_r2 , R16
    23. in R16, dout_port_g2
    24. BST r22,0
    25. bld r16,Dout_pin_g2
    26. Out Dout_port_g2 , R16
    27. in R16, dout_port_b2
    28. BST r23,0
    29. bld r16,Dout_pin_b2
    30. Out Dout_port_b2 , R16
    31. SBI shift_clock_Port, shift_clock_Pin 'high auf den CLK-pin legen
    32. LSr r18 'R18 nach rechtss shiften, damit nächstes byte an der Stelle bit0 steht
    33. LSr r19
    34. lsr r20
    35. lsr r21
    36. lsr r22
    37. lsr r23
    38. dec r17
    39. CBI shift_clock_Port, shift_clock_Pin 'low auf den CLK-pin legen
    40. BRnE loop_shift2out ; if = 0 exit
    41. $end Asm
    42. End Sub
    Alles anzeigen
    Ich hoffe, dass ich es verständlich erklären konnte. Bei Fragen dazu, einfach einen thread starten.

    102 mal gelesen