3D LED Candle
PCBWay recently and very kindly sent me some PCBs that I designed to give a more realistic candle effect.
I made a video and a blog about this PCB in another context, using it to make a solar temperature indicator.
The theory is based on separation - a "single point" candle is only going to vary light strength (and possibly frequency), but it cannot give that "side to side" movement that a real flame experiences as it sways in the vortex of it's own gases.
And so I thought as the Padauk PFS154 has three available PWM channels I would make a large-ish LED PCB that fits three lights and perhaps would give that "real world" swaying 3D effect missing from all of my previous incarnarnations.
Very simple to solder up, the PCB works a treat - but will it be candley enough for me in this configuration?
The code to drive this simulation is constantly being tinkered with, but basically this version is as follows:
/* Candle with Three PWM Pseudo-random flickering to simulate a candle. Output is via 3xPWM channels, variables can be changed to alter the simulation Tue 17 Jan 2023 13:50:35 AEDT */ #include <stdint.h> #include <stdlib.h> #include "../device.h" #include "../easy-pdk/calibrate.h" #include "../auto_sysclock.h" #include "../delay.h" #include <stdbool.h> #define LED4_BIT 4 #define LED0_BIT 0 #define LED3_BIT 3 uint16_t myrand = 2901; // happy birthday uint8_t slowcounter = 0; uint8_t medcounter = 0; uint8_t fastcounter = 0; uint8_t slowstart = 0; uint8_t slowend = 0; uint8_t medstart = 0; uint8_t medend = 0; uint8_t faststart = 0; uint8_t fastend = 0; uint8_t faster = 0; uint8_t waveslow[] = {20, 30, 70, 100}; uint8_t wavemed[] = {25, 40, 100, 120}; uint8_t wavefast[] = {20, 30, 120, 140}; bool fastup = true; bool slowup = true; bool medup = true; void mydelay(uint8_t counter) { for (uint8_t thiscount = 0; thiscount <= counter; thiscount++) { _delay_us(1); } } uint16_t gimmerand(uint16_t small, uint16_t big) { myrand ^= (myrand << 13); myrand ^= (myrand >> 9); myrand ^= (myrand << 7); if (abs(myrand) % 13 == 0) { myrand = myrand - 23; } if (abs(myrand) % 17 == 0) { myrand = myrand + 11; } return abs(myrand) % 23 * (big - small) / 23 + small; } void getnewslow() { slowstart = gimmerand(waveslow[0], waveslow[1]); slowend = gimmerand(waveslow[2], waveslow[3]); } void getnewmed() { medstart = gimmerand(wavemed[0], wavemed[1]); medend = gimmerand(wavemed[2], wavemed[3]); } void getnewfast() { faststart = gimmerand(wavefast[0], wavefast[1]); fastend = gimmerand(wavefast[2], wavefast[3]); faster = gimmerand(1, 3); } // Main program void main() { PAC |= (1 << LED4_BIT) | (1 << LED0_BIT) | (1 << LED3_BIT); // see datasheet PWMG1DTL = 0x00; PWMG1DTH = 0x00; PWMG1CUBL = 0xff; PWMG1CUBH = 0xff; PWMG1C = 0b10100111; PWMG1S = 0b00000000; PWMG0DTL = 0x00; PWMG0DTH = 0x00; PWMG0CUBL = 0xff; PWMG0CUBH = 0xff; PWMG0C = 0b10100111; PWMG0S = 0b00000000; PWMG2DTL = 0x00; PWMG2DTH = 0x00; PWMG2CUBL = 0xff; PWMG2CUBH = 0xff; PWMG2C = 0b10100111; PWMG2S = 0b00000000; getnewfast(); getnewslow(); getnewmed(); slowcounter = slowstart; fastcounter = faststart; medcounter = medstart; // Main processing loop while (1) { // ramp up slow if (slowup) { slowcounter++; if (slowcounter > slowend) { // ramp finished so switch boolean slowup = !slowup; } } else { // ramp down slow slowcounter--; if (slowcounter < slowstart) { // ramp finished so switch boolean slowup = !slowup; getnewslow(); } } // ramp up med if (medup) { medcounter++; if (medcounter > medend) { // ramp finished so switch boolean medup = !medup; } } else { // ramp down med medcounter--; if (medcounter < medstart) { // ramp finished so switch boolean medup = !medup; getnewmed(); } } // ramp up fast if (fastup) { fastcounter = fastcounter + faster; if (fastcounter > fastend) { // ramp finished so switch boolean fastup = !fastup; } } else { // ramp down fast fastcounter = fastcounter - faster; if (fastcounter < faststart) { // ramp finished so switch boolean fastup = !fastup; getnewfast(); } } // delay + a re-purposed random for ramp speeds mydelay(2 + faster); PWMG1DTL = slowcounter & 255; PWMG1DTH = slowcounter; PWMG0DTL = fastcounter & 255; PWMG0DTH = fastcounter; PWMG2DTL = medcounter & 255; PWMG2DTH = medcounter; } } // Startup code - Setup/calibrate system clock unsigned char _sdcc_external_startup(void) { // AUTO_INIT_SYSCLOCK(); PDK_SET_SYSCLOCK(SYSCLOCK_ILRC_DIV4); // AUTO_CALIBRATE_SYSCLOCK(TARGET_VDD_MV); EASY_PDK_CALIBRATE_ILRC(19000, 4000); return 0; }
Finally I made up a Padauk based stable joule thief PCB to link to the LEDs as a solar based power source, and here's the result.
Let me know if you want any gerber files for these boards, and I'd love some feedback on the whole concept of a fake 3D candle!
Comments under the YT video shown below would be awesome.
No comments:
Post a Comment