Ich habe eine Funktion für den PIC18(F45k22) und eine für den
PIC12(F1840) geschrieben um WS2812LED streifen anzusteuern. Der PIC
muss mit 32MHz laufen.
Weiter Unten ist auch ein Code für PIC24 in C und ASM.
Im Anhang befinden sich zwei Programme, die die erste LED Gelb, die
Zweite Cyan und dritte Magenta einschalten.
Die Funktion funktioniert ungefähr so:
1. Es wird die Anzahl der LEDs*3 definiet:
1
#define number_rgb_bytes 9 ; 3 LEDs
2. Die Variablen, in denen die RGB Bytes gespeichert werden und zwei
Variablen, di die Sendefunktion als Zwischenspeicher braucht, werden mit
CBLOCK (und equ) definier.
-PIC18:
1
CBLOCK 0x00
2
tx_cnt
3
tx_buf
4
rgb_byte: number_rgb_bytes
5
ENDC
Die Variablen tx_cnt und tx_buf müssen alle in der access Bank sein,
die rgb_bytes alle in der selben Bank.
-PIC12:
1
CBLOCK 0x20
2
rgb_byte: number_rgb_bytes
3
ENDC
4
tx_cnt equ 0x70
5
tx_buf equ 0x71
Hier gild ähnliches: tx_cnt und tx_buf müssen im Common RAM
(0x70 - 0x7F) liegen und die rgb_bytes alle in der selben bank.
3. Der PIC muss mit 32MHz internem oder externen oszillator laufen
4. Das SPI Modul muss initalisier werten, die LEDs kommen an den SDO
Ausgang.
5. Die gewünschten Werden in die rgb_byte geschrieben
6. Die Sendefunktion wir aufgerugen:
1
call transmit_WS2812
Ich hoffe ich konnte verständlich genug erklären, wie die Funktion
angewendet wird…
Viel Spaß mit der WS2812 Funktion.
Gruß Max
Ich habe den Code für den PIC12 erfolgreich mit 10 LEDs eingesetzt.
Ich habe keinen PIC16 hier um es zu testen, der Code für den PIC12
könnte auch auf einem PIC16 funktionieren, wenn man das moviw ++FSR0
durch incf FSR0,f mowf INDF,w ersetzt.
Der Code sollte auch für WS2812B LEDs passen:
| WS2812 | WS2812B | Programm
T1H | 0.7µs | 0.8µs | 0.75µs
T1L | 0.6µs | 0.45µs | 0.625µs
| | |
T0H | 0.35µs | 0.4µs | 0.375µs
T0L | 0.8µs | 0.85µs | 1µs
Wie einige vielleicht mitbekommen haben, habe ich vor kurzem angefangen
PIC24 (ASM) zu programmieren. Bei meiner Übung zum SPI Modul ist eine
Funktion für die WS2812LEDs entstanden. Geschrieben wurde der Code für
einen PIC24FV32KA302 mit 32MHz.
Er ist ähnlich anzuwenden, wie der für den 8bit PIC:
-Die Anzahl der RGB Bytes (LEDs*3) wir definier:
1
.equ number_rgb_bytes, 9
-Es wird Speicher im RAM für die RGB-Bytes reservier:
1
.section MAINRAM, bss, address(0x850)
2
RGB_bytes: .space number_rgb_bytes
Variblem wie tx_cnt/tx_buf brauch es nicht, das der PIC24 16
Arbeitsregister hat.
-Dann wird das SPI Modul initialisiert.
-Dann erden die RGB Werte byteweise mit mov.b in die Register
geschrieben.
-Danach kann die Senderoutine mit call transmit_WS2812 aufgerufen
werden.
Die Senderoutine verwende die Arbeitsregister W0, W1, W2, W3 und W4. Wer
will kann sie auch vorher auf den Stack legen.
Ich habe den Streifen mit 12 LEDs getestet:
1
.equ number_rgb_bytes, 36
2
3
.section MAINRAM, bss, address(0x850)
4
RGB_bytes: .space number_rgb_bytes
5
6
.
7
.
8
.
9
10
mov #0x0F,w0
11
mov #RGB_bytes,w1
12
repeat #35
13
mov.b w0,[w1++]
14
15
call transmit_WS2812
Alle 12 LEDs leuchten "Dunkelweiß"
@Mods: Es wäre sehr nett, wenn einer von euch den PIC24 im Betreff
hinzufügen könnte.
Ich habe noch eine WS2812 Funktion für den PIC24F(V32KA302) in C
(XC16) geschrieben. Der PIC läuft mit 32MHz und das SPI Modul mit
5.333MHz (Secondary presvaler 1:3)
In der Datei sind, zusätzlich zur main, zwei WS2812-Funktionen:
1
voidWS2812_Init(void);
Diese Funktion muss am Anfang aufgerufen werden um das SPI Modul zu
Initialisieren.
Diese Funktion sendet die Daten an die LEDs. Sie hat als
Übergabeparameter die Anzahl der LEDs und ein unsigned char array, in
dem die zu Bytes stehen, die an die gesendet werden. Sie werden in der
reihenfolde data[0], data[1], data[2], ..., data[nuber_led*3] gesendet.
Im Anhang noch ein C Code, getestet auf dem PIC12F1840 und PIC16F1825,
kompiliert mit dem XC8. In der Main wird einfach die erste LED grün, die
Zweite rot und die Dritte blau eingeschalten.
Der Code ist eigentlich ganz einfach zu verwenden:
In der WS2812.h wird der Pin an dem die LEDs hängen definiert.
In der main muss die WS2812_Init(); aufgerufen werden, diese stellt
eigentlich nur den Pin auf Output und initialisiert den Pin mit low.
Um die Daten an die LEDs zu senden wird die Funktion
aufgerufen. Als Übergrabe Parameter brauch die Funktion:
*data : Ein Array aus unsigned char in dem die RGB werte in der
Reihenfolge G1,R1,B1,G2,R2,B2,G3,R3,B3,G4,R4,B4,... stehen
number_leds : Die Anzahl der LEDs an die die Daten gesendet werden
sollen
Das Timing ist für Fosc=32MHz geschrieben. Wenn jemand eine andere
Taktfrequenz verwenden will muss das Timing in der WS2812_WriteBit
Funktion angepasst werden.
Hier noch was für den PIC16F1509, ist zwar nicht von mir, passt aber gut
zum Thema WS2812 mit PIC. Der Vorteil dieses Codes ist, dass er die CPU
beim Schreiben nicht zu 100% auslastet.
http://ww1.microchip.com/downloads/en/AppNotes/00001606A.pdf
Thread ist uralt, aber das folgende ist nur eine Variation des Codes für
16, 32 und 64MHz und dieser Thread ist schon im WS2812 Artikel
verlinkt...
<edit>getestet mit einem PIC18FxxK22. Compiler XC8 Free
Timing bei 16MHz Clock
T0H 250us
T1H 750us
TxL
- zwischen zwei Bytes sind es 31 Cycles → 7,75us (bei 16MHz Takt)
- zwischen zwei kurzen High (0 code) 5 Cycles→ 1,25us
- zwischen „0“ und folgender „1“ 6 Cycles→ 1,50us
- zwischen „1“ und folgender „0“ 4 Cycles→ 1,00us
- zwischen zwei langen High (1 code) 5 Cycles→ 1,25us
Die "inline" Version hätte mir schon auch gefallen und hat auch mit
16MHz funktioniert. Allerdings verlängert sie die Übertragungszeit um
mehr als 50%. Bei 24 WS2812 von ~1,4ms auf ~2,3ms
Hi, could you please give me Volker S. little explanation about the code
you added? because I am not sure with what function should I use your
code exactly like main file etc? and does this WS2812_DAT define as
port which I am using?
Mitihi schrieb:> I am not sure with what function should I use your> code exactly like main file etc?
Sorry for delayed answer. Here an example of usage for 24 LEDs: