This code is a bit of example code for WS2812 RGB LEDs.
Project by Peter Mather.
I was able to properly test the code for sending out the pulse sequences. The attached code contains a simple example that fades in and out the colours and rotates them around the ring – I wish I had some artistic flair but that will have to do as an example!
The code should be able to handle any number of WS2812 LEDs in the string – power supply and cost will be the limiting factors. The Cfunction code is included as comments.
The WS2812.init routine sets the CPU speed to 48, the Cfunction will only operate correctly at this speed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
OPTION DEFAULT NONE OPTION EXPLICIT ' ' Function and subroutine calls ' ' WS2812.pulses: number of LEDs, PIC port numer (0=A..2=C), Pin number within the port, array of colour codes, buffer array used by the CFunction ' sub WS2812.pulses(numleds as integer, portnum as integer, pinnum as integer, colours() as integer, buffer() as integer) ' ' WS2812.getcolour: Get the green, red, and blue components for a specific LED from the colour array ' sub WS2812.getcolour(led as integer, greenness as integer, redness as integer, blueness as integer) ' ' WS2812.setcolour: Load the colour array for a specific LED from the green, red, and blue components ' sub WS2812.setcolour(led as integer, greenness as integer, redness as integer, blueness as integer) ' ' WS2812.INIT: set the pin to use for output to the LEDs and the number of LEDs in the string and sets up the required global variables and CPU speed ' SUB WS2812.INIT(LED_PIN as integer,NUMLEDS as INTEGER) ' ' WS2812.getpin: uses the pin number to get the port number and the pin number on the port by reference to the Device ID; returns true if a valid pin, false otherwise ' function WS2812.getpin(MMpin as integer,portnum as integer,pinnum as integer) as integer WS2812.INIT(16,7) 'set the pin for output and the number of LEDs ' EXAMPLE 'execute the example program ' end '___________________________________________________________ ____________________________________________________________ _______________ ' 'number of LEDs, PIC port numer (0=A..2=C), Pin number within the port, array of colour codes, buffer array used by the CFunction ' CFunction WS2812.Pulses 00000000 8fa30010 24020001 8ccc0000 01826004 8ca60000 14c20003 8ca50004 10a00009 3c0ebf88 24020002 14c20003 3c0ebf88 50a00007 25cd6234 25cd6034 10000005 25ce6038 25cd6134 10000002 25ce6138 25ce6238 34058000 3c02bf80 ac450600 8c820004 1c400005 8c880000 14400025 00000000 11000023 00000000 0060c021 00007821 1000001c 240bffff 30490020 8ce80004 00085040 00022827 00aa5004 8ce50000 00452806 01452825 00484007 0109280b 30a50001 a0c50000 2442ffff 144bfff2 24c60001 25ef0001 8c880000 8c820004 27180018 000f2fc3 00a2302a 14c00005 24e70008 14450006 01e8482b 11200004 00000000 03003021 1000ffe3 24020017 5c400006 3c02bf80 1440000b 3c05bf80 2d08001d 15000008 3c02bf80 8c460c00 3c05ffff 24a57fff 00c52824 ac450c00 10000006 8c820000 8ca20c10 2c420065 1040fffd 00000000 8c820000 000228c0 00021140 00453823 10e00025 00001021 3c05bf80 00623021 90c60000 10c0000f 00000000 adcc0000 aca00610 8ca60610 2cc60019 14c0fffd 00000000 adac0000 aca00610 8ca60610 2cc6000d 14c0fffd 00000000 1000000e 24420001 adcc0000 aca00610 8ca60610 2cc60005 14c0fffd 00000000 adac0000 aca00610 8ca60610 2cc60014 14c0fffd 00000000 24420001 1447ffe1 00623021 10000003 8c830004 00e01021 8c830004 5c600008 3c03bf80 14600009 00000000 8c830000 2c63001d 14600005 00000000 3c03bf80 8c640c00 34848000 ac640c00 adac0000 03e00008 00001821 End CFunction ' 'long long WS2812.Pulses(long long *numleds, long long *portname,long long *mypin,long long parray[], unsigned char sarray[]){ ' #define tmr4 *(volatile unsigned int *)0xbf800C10 //timer 1 configuration register ' #define tmr4con *(volatile unsigned int *)0xbf800C00 //timer 1 configuration register ' #define tmr1con *(volatile unsigned int *)0xbf800600 //timer 1 configuration register ' #define tmr1 *(volatile unsigned int *)0xbf800610 //timer 1 counter ' unsigned int index,pin=1<<*mypin; ' int k,bpos; ' unsigned int volatile * mysetport; ' unsigned int volatile * myclearport; ' if(*portname==0) { ' mysetport=(volatile unsigned int *)0xbf886038; ' myclearport=(volatile unsigned int *)0xbf886034; ' } ' if(*portname==1) { ' mysetport=(volatile unsigned int *)0xbf886138; ' myclearport=(volatile unsigned int *)0xbf886134; ' } ' if(*portname==2) { ' mysetport=(volatile unsigned int *)0xbf886238; ' myclearport=(volatile unsigned int *)0xbf886234; ' } ' tmr1con=0x8000; //turn on timer at full speed ' index=0; ' for(k=0;k<*numleds;k++){ //move the data into a single dimensional array that we can step though in even time ' for(bpos=23;bpos>=0;bpos--){ ' sarray[index]=(parray[k]>>bpos) & 1; ' index++; ' } ' } ' if(*numleds > 28) { //Decide how to avoid RTC interrupts ' tmr4con &= 0xFFFF7FFF; //turn off the real time clock if it is going to interfere ' } else { ' while(tmr4>100); //synchronise with the RTC to avoid interrupts ' } ' k=*numleds * 24;; //get the number of bytes to output ' for (index=0;index<k;index++){ //step through the input data ' // Note the timer settings are not obvious as the execution of the loop elongates the low pulses ' if (sarray[index]){ ' *mysetport=pin; ' tmr1=0; ' while(tmr1<25); //Tuned for the 700ns pulse ' *myclearport=pin; ' tmr1=0; ' while(tmr1<13); //Tuned for the 600ns pulse ' } else { ' *mysetport=pin; ' tmr1=0; ' while(tmr1<5); //Tuned for the 350ns pulse ' *myclearport=pin; ' tmr1=0; ' while(tmr1<20); //Tuned for the 800ns pulse ' } ' } ' if(*numleds > 28) tmr4con |= 0x0008000; //turn the clock back on ' *myclearport=pin; //Set the output low to create the reset pulse which loads the data ' return index; '} ' ' Load the colour array for a specific LED from the green, red, and blue components ' sub WS2812.setcolour(led as integer, greenness as integer, redness as integer, blueness as integer) colours(led)= ((greenness and &HFF)<<16) + ((redness and &HFF)<<8) + (blueness and &HFF) end sub ' ' Get the green, red, and blue components for a specific LED from the colour array ' sub WS2812.getcolour(led as integer, greenness as integer, redness as integer, blueness as integer) greenness=colours(led)>>16 redness=(colours(led)>>8) and &HFF blueness= colours(led) and &HFF end sub ' ' uses the pin number to get the port number and the pin number on the port by reference to the Device ID ' function WS2812.getpin(MMpin as integer,portnum as integer,pinnum as integer) as integer const P28$="N/AA00A01B00B01B02B03N/AA02A03B04A04N/AB05B06B07B08B09N/AN/AB10B11B12B13B14B15N/AN/A" const P40$="B09C06C07C08C09N/AN/AB10B11B12B13A10A07B14B15N/AN/AN/AA00A01B00B01B02B03C00C01C02N/AN/AA02A03A08B04A04A09C03C04C05N/AN/AB05B06B07B08" local integer i local a$ length 3 i=(MMpin-1)*3 +1 if (peek(word &HBF80F220) and &HFFFFFFF) = &H6610053 then if MMpin>=1 and MMpin<=28 then a$=mid$(p28$,i,3) else a$="N/A" endif else if MMpin>=1 and MMpin<=40 then a$=mid$(p40$,i,3) else a$="N/A" endif endif if a$="N/A" then WS2812.getpin=0 else portnum=asc(left$(a$,1))-65 pinnum=val(right$(a$,2)) WS2812.getpin=1 endif end function ' ' Initialise required global variables depending on the number of LEDs and set up the output pin and CPU speed ' SUB WS2812.INIT(LED_PIN as integer,nLEDs as INTEGER) CPU 48 'This speed is fixed for the Cfunction to work ' Global variables DIM INTEGER NUMLEDS=nLEDS DIM integer buffer(NUMLEDS*3-1) dim INTEGER colours(NUMLEDS) dim integer portnum,pinnum setpin LED_PIN,dout LOCAL INTEGER i=WS2812.getpin(LED_PIN,portnum,pinnum) end sub ' sub EXAMPLE local integer i,j,green,red,blue,maxbright=40 WS2812.setcolour(0,maxbright,maxbright,maxbright) 'white WS2812.setcolour(1, maxbright,0,0) 'green WS2812.setcolour(2,maxbright,maxbright,0) 'yellow WS2812.setcolour(3,0,maxbright,0) 'red WS2812.setcolour(4,0,maxbright,maxbright) 'magenta WS2812.setcolour(5,0,0,maxbright) 'blue WS2812.setcolour(6,maxbright,0,maxbright) 'cyan Do for j=1 to maxbright-1 i=WS2812.pulses(NUMLEDS,portnum,pinnum,colours(),buffer()) for i=0 to 6 WS2812.getcolour(i,green,red,blue) if green<>0 then green=green-1 if red<>0 then red=red-1 if blue<>0 then blue=blue-1 WS2812.setcolour(i,green,red,blue) next i pause 10 next j rotate for j=1 to maxbright-1 i=WS2812.pulses(NUMLEDS,portnum,pinnum,colours(),buffer()) for i=0 to 6 WS2812.getcolour(i,green,red,blue) if green<>0 then green=green+1 if red<>0 then red=red+1 if blue<>0 then blue=blue+1 WS2812.setcolour(i,green,red,blue) next i pause 10 next j loop end sub ' sub rotate 'rotates the colours round the edge of the display leaving white in the middle local integer i,j i=colours(6) for j=5 to 1 step -1 colours(j+1)=colours(j) next j colours(1)=i end sub |
Leave a Reply