LED throwie project : Random blinking usign PWM

Hi all,

I would like to do a LED throwie project using the ATtiny45 or 85. There will be 25 throwies with a LED lighting up at random intervals. My inspiration and starting point is this:

https://github.com/thogo/light-sensity-morse-throwie/blob/master/FireFly-V0.5

The attached swf file is a demonstration/simulation in flash.
Also viewable here: fastSWF - Free Flash and Unity Hosting

I started working on the code and below you can see how far I got. At this moment I have two challenges:

  1. Generating a random number from 1 to 10 (1,2,3,4,5,6,7,8,9 or 10)
  2. Making the led blink using PWM (0% to 100% to 0% in one second)

For clarity: a short explanation of what the code should do:

- Generate random number from 1 to 10 (1,2,3,4,5,6,7,8,9 or 10) Let's say 6
- watchdog will timeout every 4 seconds
- count how many times a timeout has occurred
So after 6 timeouts (6x4 = 24 seconds)
- timeout count == random number (6) --> light up LED
- set timeout count to zero
- generate new random, say 3
So after 3 timeouts (3x4 = 12 seconds)
- timeout count == random number (3) --> light up LED
- set timeout count to zero
- generate new random....

There will be 25 throwies running this code

1. Random number

I need this random number to make the LED blink at random intervals. The watchdog will timeout every 4 seconds, after a random number of timeouts the LED blinks. After a blink a new random number will be generated to make the blinking pattern random.

The rand() function is however not so random (explained here). So what I’d like to do is this:

  • Use the sensDarkness function in the code
  • Say this returns 22816
  • Take the last digit, “6” in this case
  • This will be my random number

Possible last digits: 0,1,2,3,4,5,6,7,8 or 9
add 1
Result is: 1,2,3,4,5,6,7,8,9 or 10
This is exactly the random range I need

I assume that the sensDarkness function is not that accurate and the last digit will vary

But how does this translate into code ? I’m pretty new to programming in C and would appreciate some hints :slight_smile:

2. Make LED blink

I would like to use the PWM on the ATtiny. In about 1 second the LED should go from 0% > 100% > 0%
Does anyone have a link to a usable example of this ?

Thanks for reading !

// for sleep Mode / Powersave we need some additional stuff. Its alredy there,
// if you installed the Attiny extension for Arduino IDE, no additional
// installing needed.
#include <avr/sleep.h>
#include <avr/wdt.h>

// ===========================================================================
// Some definitions for powersave depending of ATTiny type.
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif


// ---------------------------------------------------------------------------
// LED Pin definitions, 
#define LED1_N_SIDE 3
#define LED1_P_SIDE 4

// ===========================================================================
// Variables

// Define light trigger threshold. best way to set it on dusk / dawn level
// diffuse red ones are less sensitive than clear green ones...
int darknessThreshold = 17000;

// Interrupt Flag, should be volatile, means: read from RAM, not register
// because registers are used for interrupt handling, it have to be volatile.
volatile boolean f_wdt = 1;


//Blink interval, holds the number of times a timeout must occur before the LED is blinked
int intBlinkInterval = 5; //??? generate a random number from 1-10 ??? ;

//intTimeOutCount holds the number of occurred timeouts
int intTimeOutCount = 0;

// ===========================================================================
// Setup watchdog
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms, 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
// ===========================================================================
void setup()
{
  setup_watchdog(8);
}

// ===========================================================================
// Main
// ===========================================================================

void loop(){

  if (f_wdt==1 && sensDarkness(LED1_N_SIDE, LED1_P_SIDE) > darknessThreshold) {    // if watchdog timed out AND if it is dark enough
                  
    f_wdt=0;       // reset watchdog flag  
  
    intTimeOutCount++; // increment counter
  
    if (intTimeOutCount == intBlinkInterval){ 
        
      // reset timeoutcount
      intTimeOutCount = 0;
      
      // interval should get a new random value of 1-10
      intBlinkInterval = 4; //??? generate a random number from 1-10 ??? 
      
      // Make LED glow
      blink(); 
      
    }
  
  } //end if wdt and dark
  
  // If no watchdog timout or not dark enough: 
  // set all used port to intput to save power
  pinMode(LED1_N_SIDE,INPUT);
  pinMode(LED1_P_SIDE,INPUT);
  system_sleep();
  
} //end loop main


// ===========================================================================
// Subroutines for Sleeping
// ===========================================================================
// set system into the sleep state 
// system wakes up when watchdog is timed out
void system_sleep() {
  cbi(ADCSRA,ADEN);                    // switch Analog to Digital converter OFF

  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
  sleep_enable();

  sleep_mode();                        // System sleeps here

  sleep_disable();                     // System continues execution here when watchdog timed out 
  sbi(ADCSRA,ADEN);                    // switch Analog to Digitalconverter ON
}

// ----------------------------------------------------------------------------
// Setup for watchdog. Parameter ii for sleeping time:
//      0 =  16ms, 1 =  32ms, 2 =  64ms, 3 = 128ms, 4 = 250ms, 5 = 500ms
//      6 = 1 sec, 7 = 2 sec, 8 = 4 sec,9 = 8 sec
// ----------------------------------------------------------------------------

void setup_watchdog(int ii) {

  byte bb;
  int ww;
  if (ii > 9 ) ii=9;
  bb=ii & 7;
  if (ii > 7) bb|= (1<<5);
  bb|= (1<<WDCE);
  ww=bb;

  MCUSR &= ~(1<<WDRF);
  
  WDTCR |= (1<<WDCE) | (1<<WDE);       // start timed sequence

  WDTCR = bb;                          // set new watchdog timeout value
  WDTCR |= _BV(WDIE);
}
// -----------------------------------------------------------------------------
// Watchdog Interrupt Service / is executed when watchdog timed out
ISR(WDT_vect) {
  f_wdt=1;                             // set global flag
}

// =============================================================================
// Subroutines for light sensor
// =============================================================================
// Function sensDarkness
// Usage: sensDarkness(Pin-No. N-Side of LED, Pin-No. P-Side of LED):
// will result "darkness-level" - the higher the darker:
//      30000 = pitch black
//      0     = sunshine
int sensDarkness(int LED_N, int LED_P){

  unsigned int i;                        //Parameter bleed-out LED capacitor

  // charge the capacitor of LED  
  pinMode(LED_N,OUTPUT);
  pinMode(LED_P,OUTPUT);
  digitalWrite(LED_N,HIGH);
  digitalWrite(LED_P,LOW);

  // Isolate the N end of the diode and turn off internal pull-up resistor
  pinMode(LED_N,INPUT);
  digitalWrite(LED_N,LOW);

  // Count how long it takes the diode to bleed back down to a logic zero
  for ( i = 0; i < 30000; i++) {
    if ( digitalRead(LED_N)==0) break;
  }
  // thats it, return result
  return i;
}

// =============================================================================
// Make LED glow
// LED should glow from 0 to 100% in 0.5 seconds and back from 100 to 0% in 0.5 seconds

void blink(){
  
  
  
}

Ledfield_Complete.zip (2.4 KB)

I assume that the sensDarkness function is not that accurate and the last digit will vary

It might be better to use the return value from the function as input to randomSeed(). Then, just call random() to get (more) random numbers.

I seriously doubt that anyone will be able to tell that your throwie is using a psuedo-random number generator.

I would like to use the PWM on the ATtiny. In about 1 second the LED should go from 0% > 100% > 0%

Where does random blinking come into play in that scenario?

  1. I Have never heart of the sensDarkness() function… What is is suppose to do? Easiest way for random is to use the ADC as a seed for the random function and you’re all set.

  2. I would do something like:

// 1s = 1000ms, 1000ms/62 ~= 16 steps in a second
// 16 * 16 ~= 255
const byte LedFadeInterval = 62;
const byte LedFadeStepSize = 16;

bool rampLed(int step){
  static unsigned int lastTime = millis();
  static int level = 0;
  unsigned int nowTime = millis();
  
  if(nowTime - lastTime >= LedFadeInterval){
    lastTime = nowTime;
    level += step;
    
    if(level > 255){
      level = 255;
    }
    else if(level < 0){
      level = 0;
    }
    
    analogWrite(LedPin, level);
  }
  return (level == 255) || (level == 0);
}

bool rampLedUp(){
  return rampLed(LedFadeStepSize);
}

bool rampLedDown(){
  return rampLed(-(LedFadeStepSize));
}

bool updateLed(){
  static byte state = 0;
  switch(state){
    case 0:
      if(randomWait()){
        state++;
      }
    break;
    case 1:
      if(rampLedUp()){
        state++;
      }
    break;
    case 2:
      if(wait()){
        state++;
      }
    break;
    case 3:
      if(rampLedDown()){
        state = 0;
      }
    break;
  }
}

It might be better to use the return value from the function as input to randomSeed(). Then, just call random() to get (more) random numbers.
...
I seriously doubt that anyone will be able to tell that your throwie is using a psuedo-random number generator.

Yes, that would be easier I guess. Using randomSeed(analogRead(0)) looks like an option too. Probably no one is going to notice but I want to prevent repetition in the blinking pattern.

Note for clarity: The 25 throwies will be spread in the grass and the total of them will make up a "LED-field". Please view the demo in the openingpost to get the idea

Where does random blinking come into play in that scenario?

Please see note above, all 25 throwies will light up randomly. One "blink" is one LED glowing for a second

I Have never heart of the sensDarkness() function...

This is a function in the code used to determine if it is dark

Please see note above, all 25 throwies will light up randomly. One "blink" is one LED glowing for a second

There is nothing random about a LED fading up and then down in a one second rhythm.

The only randomness that you get get with that cycle is starting the cycle at a different (random delay?) on each device.

PaulS:
There is nothing random about a LED fading up and then down in a one second rhythm.

The only randomness that you get get with that cycle is starting the cycle at a different (random delay?) on each device.

Yes, and that is exactly what I’m trying to do :slight_smile: I need this random number in combination with the watchdog to have a random delay between the LED’s glowing

For random generation of number from 1 to 10 I will use in void setup():
randomSeed(analogRead(Loose_Pin));
or:
randomSeed(sensDarkness(LED1_N_SIDE, LED1_P_SIDE));

And then:
// interval should get a new random value of 1-10
intBlinkInterval = random(1,11);

for the fading:

void blink(){
  
  for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
    // sets the value (range from 0 to 255):
    analogWrite(LED1_P_SIDE, fadeValue);
    // wait for 30 milliseconds to see the dimming effect
    delay(30);
  }

  // fade out from max to min in increments of 5 points:
  for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
    // sets the value (range from 0 to 255):
    analogWrite(LED1_P_SIDE, fadeValue);
    // wait for 30 milliseconds to see the dimming effect
    delay(30);
  }
  
}

Where does the blink interval come into play?