Flashing & Fading using Attiny85

Hi,

Don’t come on here much as I use my Uno to write simple programmes for LED lighting kits for models, usually simple enough to load onto an Attiny85 as this has more than enough I/O for the lighting kits.

I’m building a bespoke kit for a Sci-Fi kit where I want to flash an LED for 2 seconds on then 2 seconds off and also have 2 LEDs that the first fades up stays on for 20 seconds, fades down, the second fades up, on for 20 seconds and then fades down and just keeps repeating this cycle.

Had a play around with a couple of solutions neither of which worked successfully, mainly to the use of the “delay” instruction, it stopped the LedFlash.h library from working.

The last programme I developed used a state change for the fading cycle and works exactly as I want it to on the Uno, LED flashes for 2 seconds and then out for 2 and the 2 LEDs fade in and out in sequence, happy days!

I have then loaded it into the Attiny85 but it won’t run the same, the fading works though is a bit jerky and the flash rate is inconsistent.

This is the programme code I am using, is there something I have missed to stop it working in the Attiny85 or is there a better, simpler way to do what I am after.

Have I missed something to make it work with the Attiny85 or is there a simpler way to do what I am trying to achieve with the 85. (Code is for 85 using pins 0 & 1 for PWM)

Thanks in anticipation.

#include <LedFlasher.h>

// pin assignments
const byte Strobes1Pin = 4;
const int RestgreenPin = 0;   // PWM
const int BattleyellowPin = 1;    // PWM


// Flashers                pin          off-time  on-time       on?
LedFlasher strobes1    (Strobes1Pin,        2000,       2000,     false);


// states for the state machine
typedef enum
  {
  initialState,
  wantStrobes1,              // ALWAYS ON  
  wantRestgreenstartup,      // Startup mode
  wantRestgreenoff,          // Battle mode
  wantBattleyellowon,        // Battle mode
  wantBattleyellowoff,       // Rest mode
  wantRestgreenon,           // Rest mode
 
    
  } states;

// state machine variables
states state = initialState;
unsigned long lastStateChange = 0;
unsigned long timeInThisState = 1000;

void setup ()
  {
  pinMode (Strobes1Pin, OUTPUT);
  
  
  // set up faders, flashers  
 
  strobes1.begin ();
  
  }  // end of setup
        
void doStateChange ()
  {
  lastStateChange = millis ();    // when we last changed states
  timeInThisState = 1000;         // default one second between states

  switch (state)
   {
    case initialState:
         state = wantStrobes1;
         break;
         
    case wantStrobes1:
         strobes1.on();
         state = wantRestgreenoff;
         timeInThisState = 1000;
         break;
         
            
//battle mode
    case wantRestgreenoff:
         {
  float in, out;

   // falling
  for (in = 1.570; in < 4.712; in = in + 0.001)
  {
    out = sin(in) * 127.5 + 127.5;
    analogWrite(RestgreenPin,out);
    delay(1);
  }
         state = wantBattleyellowon;
         break;
         
    case wantBattleyellowon:
 // rising2
  for (in = 4.712; in < 7.854; in = in + 0.001)
  {
    out = sin(in) * 127.5 + 127.5;
    analogWrite(BattleyellowPin,out);
    delay(1);
  }}
         state = wantBattleyellowoff;
         timeInThisState = 20000;
         break;
         
   
         
//rest mode         
   case wantBattleyellowoff:
                {
  float in, out;

   // falling
  for (in = 1.570; in < 4.712; in = in + 0.001)
  {
    out = sin(in) * 127.5 + 127.5;
    analogWrite(BattleyellowPin,out);
    delay(1);
  }
        state = wantRestgreenon;
        break;
        
   case wantRestgreenon:
        // rising2
  for (in = 4.712; in < 7.854; in = in + 0.001)
  {
    out = sin(in) * 127.5 + 127.5;
    analogWrite(RestgreenPin,out);
    delay(1);
  }}
        state = wantRestgreenoff;
        timeInThisState = 20000;
        break;
        
  
         
    }  // end of switch on state
  }  // end of doStateChange


void loop ()
  {
   if (millis () - lastStateChange >= timeInThisState)
     doStateChange ();
   // update faders, flashers
 
   strobes1.update ();
   
    }  // end of loop[/[code]

Cheers,

Warren

[/code]

Hi, what clock speed are you running the tiny85? It may be defaulting to 1MHz. Those thousands of calculations using float and sin() may be taking much longer as a result.

You can get tiny85 to run at 8MHz, even 16MHz, without an external crystal, I think.

I assume linear fading does not give a good enough effect, hence the sin() function? There are ways to achieve the same thing with integers, which will run much more quickly.

Paul

Hi Paul,

Yes it is running at 1MHz. Will try it at 8 or 16 this evening.

The programme seems large for what I want to do but with my limited knowledge this was the only way I could get it to work on the Uno.

Will have a look into integers and see if I can get something simpler.

Thanks,

Warren

You mean “large” in terms of the compiled code size in bytes? Again, that will be the float calculations and the sin() function. The compiler will have had to add in some large libraries to support those.

8-bit micros like the tiny85 and the mega328 in the Uno don’t have built-in hardware for floating point maths, so lots of complex and relatively slow library code has to be included by the compiler to support their use. (Modern 32-bit micros like those used the the Due or Teensy 3 have built-in floating maths hardware.)

Parts of your sketch like this:

  for (in = 1.570; in < 4.712; in = in + 0.001)
  {
    out = sin(in) * 127.5 + 127.5;
    analogWrite(RestgreenPin,out);
    delay(1);
  }

Are repeating almost the same calculation, giving the exact same result, multiple times over.

Try this:

  for (in = 1.570; in < 4.712; in = in + 0.008)
  {
    out = sin(in) * 127.5 + 127.5;
    analogWrite(RestgreenPin,out);
    delay(8);
  }

This will reduce the calculations by a factor of 8 and should not make a noticeable difference to the eye.

Paul

Hi Paul,

Thanks for that I will alter the code and see what that does.

I have also found some integer coding and will try that (halved the code size).

for(int fadeValue = 255 ; fadeValue >=0; fadeValue -=5)
  {
    
    analogWrite(RestgreenPin, fadeValue);
    delay(30);

Thanks,

Warren

Hi Warren,

That code will give a linear fade, compared to your original code which uses a sine-curve shaped fade. It may look quite different, because the human eye is not linear. The eye can detect the difference between analogWrite values of 1, 2, 3 etc. easilly, but values of 250, 251, 252 etc. are indistinguishable to the eye. You may not like the way it fades. It may seem a less even fade to the eye, with nothing much happening at first, then fading to nothing very quickly at the end.

Sine-curve shapes can be achieved with integers too, something like this (untested):

unsigned int pos = 65535;
int speed = -2;
while(speed != 0)
  {
    analogWrite(RestgreenPin,highByte(pos));
    delay(8);
    if (pos > 32768) {
      speed -= 2;
    }
    else {
      speed += 2;
    }
    pos += speed;
  }

Paul,

Thanks for the help, the linear integer fade works with the 85 and gives me what I want.

Will play around with the code you suggested to see if I can get a sin fade.

Thanks again,

Warren