2019-3-20 14:13:05 [显示全部楼层]
2056浏览
查看: 2056|回复: 2

[项目] Arduino项目|仿真蜡烛

[复制链接]
截图201903201350405496.png

“Keith's Test Garage”想要一支LED蜡烛。虽然已经有了一些很逼真的项目,而且很容易找到,但他正在寻找更像实际的东西,经过几年的工作后,他们想出了一个相当惊人的复制品。

截图201903201351131833.png

该设备的蜡嵌入式玻璃外壳内装有Arduino,内置一系列六个RGBW LED,随机闪烁以模拟火焰。

截图201903201351353042.png


下面把原作者的相关代码和连线图分享出来了

代码:
[mw_shl_code=applescript,true]<p>// FIRST TEST OF MIC AND FLAME SENSOR<br>// Keith Kelly 2019-03-04 <a href="http://www.KeithsTestGarage.com"> www.KeithsTestGarage.com
</a>
// Milestone 1 of 3</p><p>#define MIC_PIN A1   // Microphone Pin
#define FLAME_PIN A3 // IR Sensor Pin</p><p>#define FLAME_DURATION 2000 // millis- duration of flame before lighting candle
#define FLAME_THRESHOLD 800 // 0...1023 - analog reading of FLAME value to detect
#define MIC_THRESHOLD 950 // 0...1023 - analog reading of MIC value to detect</p><p>// Vars to keep track of things
bool smoking = false;
bool flaming = false;</p><p>bool lit = false;
int flame_val = 0;
int mic_val = 0;</p><p>// Vars for tracking pseudo-async times
unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long flameStartedMillis = 0;    // will store last time LED was updated</p><p>void setup(){</p><p>    Serial.begin(9600); // uncomment this to figure sensor readings.</p><p>    // initialize pins
    pinMode(FLAME_PIN, INPUT);
    pinMode(MIC_PIN, INPUT);
    pinMode(LED_BUILTIN, OUTPUT); </p><p>    digitalWrite(LED_BUILTIN, LOW); // Turn OFF built-in LED</p><p>    blowOutCandle();  // Make sure candle is off (but don't smoke)</p><p>}</p><p>void loop(){
    checkSensors(); // Check for fire and strong winds
}</p><p>// Checks for fire and strong winds every 50 milliseconds
void checkSensors(){
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= 50) { // only check every 50ms
    flame_val = analogRead( FLAME_PIN );
    mic_val = analogRead( MIC_PIN );
    previousMillis = currentMillis;
   
    //  Uncomment below to check sensor readings.  
    Serial.print(mic_val);
    Serial.print(" : ");
    Serial.println(flame_val);
  }</p><p>  if (lit && mic_val > MIC_THRESHOLD){ // MIC REGISTERED SOUND.  BLOW OUT.
    blowOutCandle(); // Turn off light (and start SMOKING!)
    lit = false;
  }</p><p>  if (!lit){ // if candle isn't lit
    if (flame_val > FLAME_THRESHOLD)  { // if flame is detected
        
        // record the starting time (if flame not yet detected)
        if (!flaming){  // if not flaming
          flaming = true;
          flameStartedMillis = millis();  // record time that flaming begins
        }
        else if (checkFlame()){ // has flame been flaming long enough?         
          lightCandle(); // ok finally light it up.
          lit = true;
        }
    }
    else{ // no flame detected
      flaming = false;
    }   
  }  
}</p><p>// Check if flame has been detected long enough.
bool checkFlame(){   
  unsigned long currentMillis = millis(); // get current time
  if (currentMillis - flameStartedMillis >= FLAME_DURATION) {
    return true;  
  }
  else
    return false;
}</p><p>// (pseudo)ASYNC light the candle by starting the animations
void lightCandle(){
    digitalWrite(LED_BUILTIN, HIGH);
}</p><p>void blowOutCandle(){   
  digitalWrite(LED_BUILTIN, LOW);
}</p>[/mw_shl_code]

[mw_shl_code=applescript,true]// Using technique from here  https://learn.adafruit.com/multi-tasking-the-ardu...

//    see link above for a good tutorial on this multi-task-ish way of doing things.

// Flicker Realistic Candle
// Keith Kelly 2019-03-04  www.KeithsTestGarage.com

// Milestone 2 of 3

#ifdef __AVR__
#include
#endif

// NeoPatterns will require the Adafruit NeoPixel library.  Be sure to install that.  
#include "NeoPatterns.h"

#define NEO_PIN 5    // First RGBW Strip Pin
#define NEO2_PIN 9   // Second RGBW Strip Pin
#define NEO_COUNT 3  // First RGBW Strip Count
#define NEO2_COUNT 3 // Second RGBW Strip Count
#define MIC_PIN A1   // Microphone Pin
#define FLAME_PIN A3 // IR Sensor Pin

#define FLAME_DURATION 2000 // millis- duration of flame before lighting candle
#define FLAME_THRESHOLD 800 // 0...1023 - analog reading of FLAME value to detect
#define MIC_THRESHOLD 950 // 0...1023 - analog reading of MIC value to detect

void Strip1Complete();
void Strip2Complete();

NeoPatterns Strip1(NEO_COUNT, NEO_PIN, NEO_RGBW + NEO_KHZ800, &Strip1Complete);
NeoPatterns Strip2(NEO_COUNT, NEO2_PIN, NEO_RGBW + NEO_KHZ800, &Strip2Complete);

uint32_t baseColor; // What is the ON resting color?
uint32_t offColor;  // What is the OFF resting color?

// Vars to keep track of things
bool flaming = false;

bool lit = false;
int flame_val = 0;
int mic_val = 0;
byte rnd = 0;

// Vars for tracking pseudo-async times
unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long flameStartedMillis = 0;        // will store last time LED was updated

void setup(){

    //Serial.begin(9600); // uncomment this to figure sensor readings.

    // initialize pins
    pinMode(FLAME_PIN, INPUT);
    pinMode(MIC_PIN, INPUT);
    pinMode(LED_BUILTIN, OUTPUT);

    // Make sure the following pins are OFF
    digitalWrite(LED_BUILTIN, LOW);

    // Initialize NeoPixel Strip 1
    Strip1.begin();
    Strip1.show();
    baseColor = Strip1.Color(2, 110, 0, 100);// GRBW
    Strip1.Color1 = baseColor;

    // Initialize NeoPixel Strip 2
    Strip2.begin();
    Strip2.show();
    baseColor = Strip2.Color(2, 110, 0, 100);// GRBW
    Strip2.Color1 = baseColor;
   
    blowOutCandle();  // Make sure candle is off
}

void loop(){
    checkSensors(); // Check for fire and strong winds
    Strip1.Update();
    Strip2.Update();
}

// Checks for fire and strong winds every 50 milliseconds
void checkSensors(){
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= 50) { // only check every 50ms
    flame_val = analogRead( FLAME_PIN );
    mic_val = analogRead( MIC_PIN );
    previousMillis = currentMillis;
   
    //  Uncomment below to check sensor readings.  
    //    Serial.print(mic_val);
    //    Serial.print(" : ");
    //    Serial.println(flame_val);
  }

  if (lit && mic_val > MIC_THRESHOLD){ // MIC REGISTERED SOUND.  BLOW OUT.
    blowOutCandle(); // Turn off light
    lit = false;
  }

  if (!lit){ // if candle isn't lit
    if (flame_val > FLAME_THRESHOLD)  { // if flame is detected
        
        // record the starting time (if flame not yet detected)
        if (!flaming){  // if not flaming
          flaming = true;
          flameStartedMillis = millis();  // record time that flaming begins
        }
        else if (checkFlame()){ // has flame been flaming long enough?         
          lightCandle(); // ok finally light it up.
          lit = true;
        }
    }
    else{ // no flame detected
      flaming = false;
    }
   
  }  
}

// Check if flame has been detected long enough.
bool checkFlame(){   
  unsigned long currentMillis = millis(); // get current time
  if (currentMillis - flameStartedMillis >= FLAME_DURATION) {
    return true;  
  }
  else
    return false;
}

//------------------------------------------------------------
//Completion Routines - get called on completion of a pattern
//------------------------------------------------------------

// The below configuration routines are the same except for the strip
// being used.  I kept them separate so the strips can be configured
// with different ranges if desired.

void Strip1Complete(){
    Strip1.Reverse();

    if (Strip1.Direction == REVERSE){ // go back down
        Strip1.Interval = random(5,22); // choose random speed in range
    }
    else{  // pattern ended.  Stop, then trigger re-flicker
        
        /*  This needs an explanation:  
            
              rnd = random(random(45,55),random(80,255));


            You'd think that we could just do random(45,255), right?


            Selecting the low and high randoms first helps make sure that
            the ending random number is *more likely* to fall within a limited range.  


            When observing the flickering of a real candle, the flame generally bounces
            around in a certain range.  But, every once in a while, it spikes high or low.


            This random(random, random) solves that problem!  #proudnerddadmoment


        */
        rnd = random(random(45,55),random(80,255));

        Strip1.Pixel = random(0,Strip1.numPixels()); // pick a random Pixel
        Strip1.Interval = 1;
        Strip1.Color2 = Strip1.Color(2,rnd,0,rnd-10); //GRBW random red and random white-10
    }
}

void Strip2Complete(){
    Strip2.Reverse();

    if (Strip2.Direction == REVERSE){ // go back down        
        Strip2.Interval = random(5,22); // choose random speed in range
    }
    else{  // pattern ended.  Stop, then trigger re-flicker
        rnd = random(random(45,55),random(80,255)); // see explanation in Strip1Complete().
        Strip2.Pixel = random(0,Strip2.numPixels()); // pick a random Pixel
        Strip2.Interval = 1;
        Strip2.Color2 = Strip2.Color(2,rnd,0,rnd-10); //GRBW random red and random white-10
    }
}

// (pseudo)ASYNC light the candle by starting the animations
void lightCandle(){
    Strip1.Flicker(Strip1.Color1, Strip1.Color2, 20, 5);
    Strip2.Flicker(Strip2.Color1, Strip2.Color2, 20, 5);
}

void blowOutCandle(){   
  cWipe(offColor, 10); // synchronously turn the candle off.

  // We don't want no stinking patterns.
  Strip1.ActivePattern = NONE;
  Strip2.ActivePattern = NONE;
}

// synchronous color wipe
void cWipe(uint32_t c, uint8_t wait) {
  for (uint16_t i = 0; i < Strip1.numPixels(); i++) {
    Strip1.setPixelColor(i, c);
    Strip1.show();
    delay(wait);
  }
  for (uint16_t i = 0; i < Strip2.numPixels(); i++) {
    Strip2.setPixelColor(i, c);
    Strip2.show();
    delay(wait);
  }
}[/mw_shl_code]

[mw_shl_code=applescript,true][Code segment omitted for clarity.  See attached file.]   


    // *****************************************
    // START Custom animation for LED candle
    // *****************************************
   
    // Initialize for a Flicker
    void Flicker(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval, direction dir = FORWARD)
    {
        ActivePattern = FLICKER;
        Interval = interval;
        TotalSteps = steps;
        Color1 = color1;
        Color2 = color2;
        Index = 0;
        Direction = dir;
        Pixel = random(0,numPixels()); // random(min,max) --max is EXCLUSIVE
    }
   
    // Initialize for a Flicker
    void FlickerUpdate()
    {
        // Calculate linear interpolation between Color1 and Color2
        // Optimize order of operations to minimize truncation error
        uint8_t red = ((Red(Color1) * (TotalSteps - Index)) + (Red(Color2) * Index)) / TotalSteps;
        uint8_t green = ((Green(Color1) * (TotalSteps - Index)) + (Green(Color2) * Index)) / TotalSteps;
        uint8_t blue = ((Blue(Color1) * (TotalSteps - Index)) + (Blue(Color2) * Index)) / TotalSteps;
        uint8_t white = ((White(Color1) * (TotalSteps - Index)) + (White(Color2) * Index)) / TotalSteps;
        setPixelColor(Pixel,Color(red, green, blue, white));
        show();
        Increment();
    }

    // *****************************************
    // END Custom animation for LED candle
    // *****************************************

[Code segment omitted for clarity.  See attached file.]

Attachments
KeithsCandle_M2_NoSmoke.inoKeithsCandle_M2_NoSmoke.ino[/mw_shl_code]
截图201903201353051640.png
截图201903201354076568.png
[mw_shl_code=applescript,true]// Using technique from here  https://learn.adafruit.com/multi-tasking-the-ardu...

//    see link above for a good tutorial on this multi-task-ish way of doing things.

// Flicker Realistic Candle
// Keith Kelly 2019-03-04  www.KeithsTestGarage.com

// Milestone 2 of 3

#ifdef __AVR__
#include
#endif

// NeoPatterns will require the Adafruit NeoPixel library.  Be sure to install that.  
#include "NeoPatterns.h"

#define NEO_PIN 5    // First RGBW Strip Pin
#define NEO2_PIN 9   // Second RGBW Strip Pin
#define NEO_COUNT 3  // First RGBW Strip Count
#define NEO2_COUNT 3 // Second RGBW Strip Count
#define MIC_PIN A1   // Microphone Pin
#define FLAME_PIN A3 // IR Sensor Pin

#define FLAME_DURATION 2000 // millis- duration of flame before lighting candle
#define FLAME_THRESHOLD 800 // 0...1023 - analog reading of FLAME value to detect
#define MIC_THRESHOLD 950 // 0...1023 - analog reading of MIC value to detect

void Strip1Complete();
void Strip2Complete();

NeoPatterns Strip1(NEO_COUNT, NEO_PIN, NEO_RGBW + NEO_KHZ800, &Strip1Complete);
NeoPatterns Strip2(NEO_COUNT, NEO2_PIN, NEO_RGBW + NEO_KHZ800, &Strip2Complete);

uint32_t baseColor; // What is the ON resting color?
uint32_t offColor;  // What is the OFF resting color?

// Vars to keep track of things
bool flaming = false;

bool lit = false;
int flame_val = 0;
int mic_val = 0;
byte rnd = 0;

// Vars for tracking pseudo-async times
unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long flameStartedMillis = 0;        // will store last time LED was updated

void setup(){

    //Serial.begin(9600); // uncomment this to figure sensor readings.

    // initialize pins
    pinMode(FLAME_PIN, INPUT);
    pinMode(MIC_PIN, INPUT);
    pinMode(LED_BUILTIN, OUTPUT);

    // Make sure the following pins are OFF
    digitalWrite(LED_BUILTIN, LOW);

    // Initialize NeoPixel Strip 1
    Strip1.begin();
    Strip1.show();
    baseColor = Strip1.Color(2, 110, 0, 100);// GRBW
    Strip1.Color1 = baseColor;

    // Initialize NeoPixel Strip 2
    Strip2.begin();
    Strip2.show();
    baseColor = Strip2.Color(2, 110, 0, 100);// GRBW
    Strip2.Color1 = baseColor;
   
    blowOutCandle();  // Make sure candle is off
}

void loop(){
    checkSensors(); // Check for fire and strong winds
    Strip1.Update();
    Strip2.Update();
}

// Checks for fire and strong winds every 50 milliseconds
void checkSensors(){
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= 50) { // only check every 50ms
    flame_val = analogRead( FLAME_PIN );
    mic_val = analogRead( MIC_PIN );
    previousMillis = currentMillis;
   
    //  Uncomment below to check sensor readings.  
    //    Serial.print(mic_val);
    //    Serial.print(" : ");
    //    Serial.println(flame_val);
  }

  if (lit && mic_val > MIC_THRESHOLD){ // MIC REGISTERED SOUND.  BLOW OUT.
    blowOutCandle(); // Turn off light
    lit = false;
  }

  if (!lit){ // if candle isn't lit
    if (flame_val > FLAME_THRESHOLD)  { // if flame is detected
        
        // record the starting time (if flame not yet detected)
        if (!flaming){  // if not flaming
          flaming = true;
          flameStartedMillis = millis();  // record time that flaming begins
        }
        else if (checkFlame()){ // has flame been flaming long enough?         
          lightCandle(); // ok finally light it up.
          lit = true;
        }
    }
    else{ // no flame detected
      flaming = false;
    }
   
  }  
}

// Check if flame has been detected long enough.
bool checkFlame(){   
  unsigned long currentMillis = millis(); // get current time
  if (currentMillis - flameStartedMillis >= FLAME_DURATION) {
    return true;  
  }
  else
    return false;
}

//------------------------------------------------------------
//Completion Routines - get called on completion of a pattern
//------------------------------------------------------------

// The below configuration routines are the same except for the strip
// being used.  I kept them separate so the strips can be configured
// with different ranges if desired.

void Strip1Complete(){
    Strip1.Reverse();

    if (Strip1.Direction == REVERSE){ // go back down
        Strip1.Interval = random(5,22); // choose random speed in range
    }
    else{  // pattern ended.  Stop, then trigger re-flicker
        
        /*  This needs an explanation:  
            
              rnd = random(random(45,55),random(80,255));


            You'd think that we could just do random(45,255), right?


            Selecting the low and high randoms first helps make sure that
            the ending random number is *more likely* to fall within a limited range.  


            When observing the flickering of a real candle, the flame generally bounces
            around in a certain range.  But, every once in a while, it spikes high or low.


            This random(random, random) solves that problem!  #proudnerddadmoment


        */
        rnd = random(random(45,55),random(80,255));

        Strip1.Pixel = random(0,Strip1.numPixels()); // pick a random Pixel
        Strip1.Interval = 1;
        Strip1.Color2 = Strip1.Color(2,rnd,0,rnd-10); //GRBW random red and random white-10
    }
}

void Strip2Complete(){
    Strip2.Reverse();

    if (Strip2.Direction == REVERSE){ // go back down        
        Strip2.Interval = random(5,22); // choose random speed in range
    }
    else{  // pattern ended.  Stop, then trigger re-flicker
        rnd = random(random(45,55),random(80,255)); // see explanation in Strip1Complete().
        Strip2.Pixel = random(0,Strip2.numPixels()); // pick a random Pixel
        Strip2.Interval = 1;
        Strip2.Color2 = Strip2.Color(2,rnd,0,rnd-10); //GRBW random red and random white-10
    }
}

// (pseudo)ASYNC light the candle by starting the animations
void lightCandle(){
    Strip1.Flicker(Strip1.Color1, Strip1.Color2, 20, 5);
    Strip2.Flicker(Strip2.Color1, Strip2.Color2, 20, 5);
}

void blowOutCandle(){   
  cWipe(offColor, 10); // synchronously turn the candle off.

  // We don't want no stinking patterns.
  Strip1.ActivePattern = NONE;
  Strip2.ActivePattern = NONE;
}

// synchronous color wipe
void cWipe(uint32_t c, uint8_t wait) {
  for (uint16_t i = 0; i < Strip1.numPixels(); i++) {
    Strip1.setPixelColor(i, c);
    Strip1.show();
    delay(wait);
  }
  for (uint16_t i = 0; i < Strip2.numPixels(); i++) {
    Strip2.setPixelColor(i, c);
    Strip2.show();
    delay(wait);
  }
}[/mw_shl_code]

[mw_shl_code=applescript,true][Code segment omitted for clarity.  See attached file.]   


    // *****************************************
    // START Custom animation for LED candle
    // *****************************************
   
    // Initialize for a Flicker
    void Flicker(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval, direction dir = FORWARD)
    {
        ActivePattern = FLICKER;
        Interval = interval;
        TotalSteps = steps;
        Color1 = color1;
        Color2 = color2;
        Index = 0;
        Direction = dir;
        Pixel = random(0,numPixels()); // random(min,max) --max is EXCLUSIVE
    }
   
    // Initialize for a Flicker
    void FlickerUpdate()
    {
        // Calculate linear interpolation between Color1 and Color2
        // Optimize order of operations to minimize truncation error
        uint8_t red = ((Red(Color1) * (TotalSteps - Index)) + (Red(Color2) * Index)) / TotalSteps;
        uint8_t green = ((Green(Color1) * (TotalSteps - Index)) + (Green(Color2) * Index)) / TotalSteps;
        uint8_t blue = ((Blue(Color1) * (TotalSteps - Index)) + (Blue(Color2) * Index)) / TotalSteps;
        uint8_t white = ((White(Color1) * (TotalSteps - Index)) + (White(Color2) * Index)) / TotalSteps;
        setPixelColor(Pixel,Color(red, green, blue, white));
        show();
        Increment();
    }

    // *****************************************
    // END Custom animation for LED candle
    // *****************************************

[Code segment omitted for clarity.  See attached file.][/mw_shl_code]
截图201903201355044753.png
[mw_shl_code=applescript,true]// Using technique from here  https://learn.adafruit.com/multi-tasking-the-ardu...
//    see link above for a good tutorial on this multi-task-ish way of doing things.

// Flicker/Smoke Realistic Candle
// Keith Kelly 2019-03-04  www.KeithsTestGarage.com

// Milestone 3 of 3

#ifdef __AVR__
#include
#endif

// NeoPatterns will require the Adafruit NeoPixel library.  Be sure to install that.  
#include "NeoPatterns.h"

#define NEO_PIN 5    // First RGBW Strip Pin
#define NEO2_PIN 9   // Second RGBW Strip Pin
#define NEO_COUNT 3  // First RGBW Strip Count
#define NEO2_COUNT 3 // Second RGBW Strip Count
#define MIC_PIN A1   // Microphone Pin
#define FLAME_PIN A3 // IR Sensor Pin
#define SMOKE_PIN 3  // Smoke Pin
#define SMOKE_TIME_MILLIS 1200 // How long should smoke wire be heated?

#define FLAME_DURATION 2000 // millis- duration of flame before lighting candle
#define FLAME_THRESHOLD 800 // 0...1023 - analog reading of FLAME value to detect
#define MIC_THRESHOLD 950 // 0...1023 - analog reading of MIC value to detect

void Strip1Complete();
void Strip2Complete();

NeoPatterns Strip1(NEO_COUNT, NEO_PIN, NEO_RGBW + NEO_KHZ800, &Strip1Complete);
NeoPatterns Strip2(NEO_COUNT, NEO2_PIN, NEO_RGBW + NEO_KHZ800, &Strip2Complete);

uint32_t baseColor; // What is the ON resting color?
uint32_t offColor;  // What is the OFF resting color?

// Vars to keep track of things
bool smoking = false;
bool flaming = false;

bool lit = false;
int flame_val = 0;
int mic_val = 0;
byte rnd = 0;

// Vars for tracking pseudo-async times
unsigned long previousMillis = 0;        // will store last time LED was updated
unsigned long smokeStartedMillis = 0;    // time smoking started
unsigned long flameStartedMillis = 0;        // will store last time LED was updated

void setup(){

    //Serial.begin(9600); // uncomment this to figure sensor readings.

    // initialize pins
    pinMode(FLAME_PIN, INPUT);
    pinMode(MIC_PIN, INPUT);
    pinMode(SMOKE_PIN, OUTPUT);
    pinMode(LED_BUILTIN, OUTPUT);

    // Make sure the following pins are OFF
    digitalWrite(SMOKE_PIN, LOW);  
    digitalWrite(LED_BUILTIN, LOW);

    // Initialize NeoPixel Strip 1
    Strip1.begin();
    Strip1.show();
    baseColor = Strip1.Color(2, 110, 0, 100);// GRBW
    Strip1.Color1 = baseColor;

    // Initialize NeoPixel Strip 2
    Strip2.begin();
    Strip2.show();
    baseColor = Strip2.Color(2, 110, 0, 100);// GRBW
    Strip2.Color1 = baseColor;
   
    blowOutCandle(false);  // Make sure candle is off (but don't smoke)

}

void loop(){
    smokeCheck(); // Check if we should stop smoking.  
    checkSensors(); // Check for fire and strong winds
    Strip1.Update();
    Strip2.Update();
}

// Checks for fire and strong winds every 50 milliseconds
void checkSensors(){
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= 50) { // only check every 50ms
    flame_val = analogRead( FLAME_PIN );
    mic_val = analogRead( MIC_PIN );
    previousMillis = currentMillis;
   
    //  Uncomment below to check sensor readings.  
    //    Serial.print(mic_val);
    //    Serial.print(" : ");
    //    Serial.println(flame_val);
  }

  if (lit && mic_val > MIC_THRESHOLD){ // MIC REGISTERED SOUND.  BLOW OUT.
    blowOutCandle(true); // Turn off light (and start SMOKING!)
    lit = false;
  }

  if (!lit){ // if candle isn't lit
    if (flame_val > FLAME_THRESHOLD)  { // if flame is detected
        
        // record the starting time (if flame not yet detected)
        if (!flaming){  // if not flaming
          flaming = true;
          flameStartedMillis = millis();  // record time that flaming begins
        }
        else if (checkFlame()){ // has flame been flaming long enough?         
          lightCandle(); // ok finally light it up.
          lit = true;
        }
    }
    else{ // no flame detected
      flaming = false;
    }
   
  }  
}

// Check if flame has been detected long enough.
bool checkFlame(){   
  unsigned long currentMillis = millis(); // get current time
  if (currentMillis - flameStartedMillis >= FLAME_DURATION) {
    return true;  
  }
  else
    return false;
}

//------------------------------------------------------------
//Completion Routines - get called on completion of a pattern
//------------------------------------------------------------

// The below configuration routines are the same except for the strip
// being used.  I kept them separate so the strips can be configured
// with different ranges if desired.

void Strip1Complete(){
    Strip1.Reverse();

    if (Strip1.Direction == REVERSE){ // go back down
        Strip1.Interval = random(5,22); // choose random speed in range
    }
    else{  // pattern ended.  Stop, then trigger re-flicker
        
        /*  This needs an explanation:  
            
              rnd = random(random(45,55),random(80,255));
            You'd think that we could just do random(45,255), right?
            Selecting the low and high randoms first helps make sure that
            the ending random number is *more likely* to fall within a limited range.  
            When observing the flickering of a real candle, the flame generally bounces
            around in a certain range.  But, every once in a while, it spikes high or low.
            This random(random, random) solves that problem!  #proudnerddadmoment
        */
        rnd = random(random(45,55),random(80,255));

        Strip1.Pixel = random(0,Strip1.numPixels()); // pick a random Pixel
        Strip1.Interval = 1;
        Strip1.Color2 = Strip1.Color(2,rnd,0,rnd-10); //GRBW random red and random white-10
    }
}

void Strip2Complete(){
    Strip2.Reverse();

    if (Strip2.Direction == REVERSE){ // go back down        
        Strip2.Interval = random(5,22); // choose random speed in range
    }
    else{  // pattern ended.  Stop, then trigger re-flicker
        rnd = random(random(45,55),random(80,255)); // see explanation in Strip1Complete().
        Strip2.Pixel = random(0,Strip2.numPixels()); // pick a random Pixel
        Strip2.Interval = 1;
        Strip2.Color2 = Strip2.Color(2,rnd,0,rnd-10); //GRBW random red and random white-10
    }
}

// (pseudo)ASYNC light the candle by starting the animations
void lightCandle(){
    Strip1.Flicker(Strip1.Color1, Strip1.Color2, 20, 5);
    Strip2.Flicker(Strip2.Color1, Strip2.Color2, 20, 5);
}

void blowOutCandle(bool shouldSmoke){
  if(shouldSmoke)
    smokeStart();
   
  cWipe(offColor, 10); // synchronously turn the candle off.

  // We don't want no stinking patterns.
  Strip1.ActivePattern = NONE;
  Strip2.ActivePattern = NONE;
}

// SMOKING METHODS
void smokeStart(){
  digitalWrite(SMOKE_PIN, HIGH); // HEAT SMOKE WIRE
  smoking = true;
  smokeStartedMillis = millis(); // record time smoking started
}

// Stop smoking if the time has come.
void smokeCheck(){
  if (!smoking)
    return; // if not smoking, get out of here.
   
  unsigned long currentMillis = millis();
  if (currentMillis - smokeStartedMillis >= SMOKE_TIME_MILLIS) {
    smokeStop();    // smoke break is over
  }
}

// Ok seriously now stop it
void smokeStop(){
  digitalWrite(SMOKE_PIN, LOW); // TURN OFF SMOKE WIRE
  smoking = false;
}

// synchronous color wipe
// To avoid smoke becoming fire, be sure to only
//   use synchronous methods like this SPARINGLY and when you
//   are sure it won't interfere with the smoking.  
//
// In other words, here's something that would be very bad:
//
//  smokeStart();
//  cWipe(offColor, 1000);   // CPU would get caught up in
//                              here for a while and would
//                              not stop the smoking process
//                              
//  At this point, I'm only using it directly after smokeStop();

void cWipe(uint32_t c, uint8_t wait) {
  for (uint16_t i = 0; i < Strip1.numPixels(); i++) {
    Strip1.setPixelColor(i, c);
    Strip1.show();
    delay(wait);
  }
  for (uint16_t i = 0; i < Strip2.numPixels(); i++) {
    Strip2.setPixelColor(i, c);
    Strip2.show();
    delay(wait);
  }
}[/mw_shl_code]
需要详细教程的朋友可以去看原文


gada888  版主

发表于 2019-3-21 13:52:07

挺不错的创意
回复

使用道具 举报

20060606  高级技匠

发表于 2020-8-9 05:33:07

挺不错的创意
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2023 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail