Welcome to Laser Pointer Forums - discuss green laser pointers, blue laser pointers, and all types of lasers

Buy Site Supporter Role (remove some ads) | LPF Donations

Links below open in new window

FrozenGate by Avery

Anyone familiar with Attiny13 programming?

Does it really need to be THAT random? After all you've only got 7 colour choices, which is going to be far more limiting than the actual randomness.

Here's how I'd do it:

In the main loop, use say, the first button press to store a value from millis(), and use that as a seed for the RNG. Run the RNG with that seed, to generate a value from 1-7, and store that in EEPROM. On next startup, simply use that EEPROM value as the first randomized colour choice. By doing this you're using the randomness of the user (there is no way they'll be able to get the button press accurate to the millisecond every time).

The seed is just an arbitrary number that is used as the basis of the RNG, so increasing the seed by 1 does not neccesarily mean the RNG's output will just increase by 1 also, it COULD be, but it's also just as likely it'll be a totally different number to whatever the previous seed was. Even if they press the button within 1 second every time, you've got the chance of 1000 different seeds, which is far more than the possible 7 colour combinations you can even use :)

Here's the problem.

The second, third, fourth, etc time around, there is no button press. The randomness happens immediately upon startup. Remember that this circuit is powering off and starting back up again.

So suppose the previous color was 4, and you increment it by 1 to get 5, which becomes the new seed. If 5 goes into the RNG immediately upon startup, it would be expected to result in the same output any time 5 goes into the RNG immediately upon startup, because nothing is different from one time to the next (remember, no additional button presses come into play).

That means color 4 will always lead to the same color next, because color 4 will always go into the EEPROM, and then increment to 5 on startup, which will go into the RNG at the exact same time.

Does that make sense?

-----

Got the board done - this was a painful one:
attachment.php
 

Attachments

  • board.png
    board.png
    68.5 KB · Views: 94
Last edited:





Not at the time the circuit would need to read it unfortunately.

I think the solution needs to be writing the byte to EEPROM from the previous activation, and feeding that, AND an AnalogRead from one of the pins on a thermister, into the chip as the randomness seed (the way they did in that article I linked a few posts back).

Is that doable?

Ya, that's doable. The analogRead() has a resolution of 0.02V iirc so depending on the coefficient on the thermistor it may produce a strong enough swing. You may not need to use an eeprom byte at all if the thermal characteristics are going to be jumpy enough. This is where a prototype board and testing would shine, and why using a 8DIP > a SOIC.

Btw, awesome board layout. Lots of work in there.
 
Last edited:
Thanks!

I know relatively little about thermisters. Am I right to understand that their resistance value is at room temperature?

So if I place a 10k NTC thermister between +5V and Pin, and then a 10k resistor between Pin and GND, as the heat rises, so too should the voltage on the Pin. That's the idea, basically? Use the thermister and a resistor as a voltage divider?

ALTERNATIVE:
What about giving the IC it's own cap on the input to the regulator, with a diode behind it to prevent discharge back into the main driver circuitry after power off. Then, based on the premise that the chip will stay powered up from the cap for a few cycles after power is cut, just have it detect power down by monitoring the main driver circuit voltage on a pin, and then respond by writing a new random value to EEPROM before it dies.
 
Last edited:
Thanks!

I know relatively little about thermisters. Am I right to understand that their resistance value is at room temperature?

So if I place a 10k NTC thermister between +5V and Pin, and then a 10k resistor between Pin and GND, as the heat rises, so too should the voltage on the Pin. That's the idea, basically? Use the thermister and a resistor as a voltage divider?

That's the idea!

ALTERNATIVE:
What about giving the IC it's own cap on the input to the regulator, with a diode behind it to prevent discharge back into the main driver circuitry after power off. Then, based on the premise that the chip will stay powered up from the cap for a few cycles after power is cut, just have it detect power down by monitoring the main driver circuit voltage on a pin, and then respond by writing a new random value to EEPROM before it dies.

Theoretically possible but very difficult to do in practice. You need to calculate the losses and loads in the system and then work backwards to find a value of C that is large enough to sustain the chip for the entire execution time for the events you want executed and account for the dynamic execution times and loadings. It's a lot more work really. If you wanted to go this kind of route I'd say just add a randomize switch and cycle that instead of cycling the power to the whole thing.

I'm still not 100% clear on how/why the application requires repetitive power cycling to cycle random states.
 
I'm still not 100% clear on how/why the application requires repetitive power cycling to cycle random states.

Because the driver is on a momentary driver, and I want the the color to cycle per activation (when set to random).

EDIT:

I think I have a more elegant solution that addresses all of the above.

Instead of writing the current color to the EEPROM as the new seed, lets instead write (current color + previous EEPROM value) to the EEPROM as the new seed, with a provision for it to subtract 255 if the new value is greater than 255. This means that GREEN (for example) won't always result in the same seed being stored to EEPROM, so there's no risk of a discernible patter whereby green always leads to some other color.

Plus, this is simpler, requires no analogread or external components.
 
Last edited:
Double-posting intentionally.

I think I have final working code. Would love any feedback as to whether there are problems with this approach to randomness.

By the way... and perhaps I should have asked this before starting to tinker with the code... what language am I writing in here?

Code:
// RHD's TTL Color Selector
// Programming by Matt "Sigurthr" Giordano 08/13/2014
// www.SigurthrEnterprises.com
// Sigurthr@SigurthrEnterprises.com

// ATTiny85 Physical Pinout - innermost designation is code addressable
//                   _______
// Reset           _|  |_|  |_   Vcc
// ADC3 Pin3   3   _|       |_ 2 Pin2 ADC1
// ADC2 Pin4  A2   _| ATT85 |_ 1 Pin1 Digital-1
// Gnd             _|       |_ 0 Pin0 Digital-0
//                  |_______|
  

#include <EEPROM.h> // include the EEPROM Memory library
boolean pinOptions[7][3] = { // Array of pin combinations (1 = on, 0 = off)
  {1,1,1},
  {1,0,0},
  {1,1,0},
  {0,1,0},
  {0,1,1},
  {0,0,1},
  {1,0,1}
};

byte PressDetects = 0;
byte ButtonPin = 3; // see pinout
byte ColorOnePin = 0; // see pinout
byte ColorTwoPin = 1; // see pinout
byte ColorThreePin = 2; // see pinout
byte MemVar;
byte ButtonPinState;
byte ColorChoice;
byte MemoryLocation = 1;
byte TriggerCount = 10; // threshold for debounce
byte RandomVar;
byte RandomVarNew;

void setup (){ // this subroutine runs once upon startup
  MemVar = EEPROM.read(MemoryLocation); // read EEPROM on power on
  pinMode (0, OUTPUT); // set pin 0 to output
  pinMode (1, OUTPUT); // set pin 1 to output
  pinMode (2, OUTPUT); // set pin 2 to output
  pinMode (3, INPUT); // set pin 3 to input
  if (MemVar == 8){
    RandomVar = EEPROM.read(RandomVar);
    randomSeed(RandomVar);
    ColorChoice = random(1, 7);
    RandomVar = RandomVar + ColorChoice;
    if (RandomVar > 255) {
      RandomVar = RandomVar - 255
    }
    EEPROM.write(RandomVar, RandomVarNew); 
  }
}

void loop(){ // this subroutine runs continuously after setup finishes
  ButtonPinState = digitalRead(ButtonPin);  // read ButtonPin to ButtonPinState  
  if (MemVar == 0 || 255){  // first time an EEPROM is read it reads as 255
    MemVar = 1;
  }
  if (ButtonPinState == HIGH){ // when ButtonPinState is HIGH...
    ++ PressDetects; // increment detection variable
  }
  if (PressDetects >= TriggerCount) { // when threshold is exceeded...
    ++ MemVar; // increment memory variable
    PressDetects = 0; // reset button detector
    if (MemVar >= 9){ // on 9th button press...
      MemVar = 1; // reset color
    }  
    if (MemVar == 8){ // on 8th button press...
      randomSeed(millis());
      ColorChoice = random(1, 7);
      RandomVarNew = random(1, 255);
      EEPROM.write(RandomVar, RandomVarNew); 
    }  
    EEPROM.write(MemoryLocation, MemVar); // write color to memory       
  }
    if (MemVar != 8){ // prevents ColorChoice from being set to 8 (invalid)
    ColorChoice = MemVar;
  }  
  digitalWrite(ColorOnePin, pinOptions[ColorChoice-1][0]);
  digitalWrite(ColorTwoPin, pinOptions[ColorChoice-1][1]);
  digitalWrite(ColorThreePin, pinOptions[ColorChoice-1][2]);
}
 
Last edited:
Looks good minus a few syntax errors. That's where a good IDE program shines, it really helps prevent syntax problems. This is C++ btw. I'll run the code through a compiler to remove errors and post it here (in an edit). Oh, I can't verify the pinOptions part, I've never used it, but Things knows his stuff.

edit1: added a new variable RandomVarLocation. You can't use the same variable for the eeprom location that you use for the data in that location.

edit2: in void setup() you were writing RandomVarNew without having assigned any data to that variable. Changed to RandomVar.

Code:
// RHD's TTL Color Selector
// Programming by Matt "Sigurthr" Giordano 08/18/2014
// Website: www.SigurthrEnterprises.com
// Email: Sigurthr@SigurthrEnterprises.com
// and by Things of LaserPointerForums.com 08/15/2014

// ATTiny85 Physical Pinout - innermost designation is code addressable
//                   _______
// Reset           _|  |_|  |_   Vcc
// ADC3 Pin3   3   _|       |_ 2 Pin2 ADC1
// ADC2 Pin4  A2   _| ATT85 |_ 1 Pin1 Digital-1
// Gnd             _|       |_ 0 Pin0 Digital-0
//                  |_______|
  

#include <EEPROM.h> // include the EEPROM Memory library
boolean pinOptions[7][3] = { // Array of pin combinations (1 = on, 0 = off)
  {1,1,1},
  {1,0,0},
  {1,1,0},
  {0,1,0},
  {0,1,1},
  {0,0,1},
  {1,0,1}
};

byte PressDetects = 0;
byte ButtonPin = 3; // see pinout
byte ColorOnePin = 0; // see pinout
byte ColorTwoPin = 1; // see pinout
byte ColorThreePin = 2; // see pinout
byte MemVar;
byte ButtonPinState;
byte ColorChoice;
byte MemoryLocation = 1;
byte TriggerCount = 10; // threshold for debounce
byte RandomVarLocation = 2;
byte RandomVar;
byte RandomVarNew;

void setup (){ // this subroutine runs once upon startup
  MemVar = EEPROM.read(MemoryLocation); // read EEPROM on power on
  pinMode (0, OUTPUT); // set pin 0 to output
  pinMode (1, OUTPUT); // set pin 1 to output
  pinMode (2, OUTPUT); // set pin 2 to output
  pinMode (3, INPUT); // set pin 3 to input
  if (MemVar == 8){
    RandomVar = EEPROM.read(RandomVarLocation);
    randomSeed(RandomVar);
    ColorChoice = random(1, 7);
    RandomVar = RandomVar + ColorChoice;
    if (RandomVar > 255) {
      RandomVar = RandomVar - 255;
    }
    EEPROM.write(RandomVarLocation, RandomVar); 
  }
}

void loop(){ // this subroutine runs continuously after setup finishes
  ButtonPinState = digitalRead(ButtonPin);  // read ButtonPin to ButtonPinState  
  if (MemVar == 0 || 255){  // first time an EEPROM is read it reads as 255
    MemVar = 1;
  }
  if (ButtonPinState == HIGH){ // when ButtonPinState is HIGH...
    ++ PressDetects; // increment detection variable
  }
  if (PressDetects >= TriggerCount) { // when threshold is exceeded...
    ++ MemVar; // increment memory variable
    PressDetects = 0; // reset button detector
    if (MemVar >= 9){ // on 9th button press...
      MemVar = 1; // reset color
    }  
    if (MemVar == 8){ // on 8th button press...
      randomSeed(millis());
      ColorChoice = random(1, 7);
      RandomVarNew = random(1, 255);
      EEPROM.write(RandomVarLocation, RandomVarNew); 
    }  
    EEPROM.write(MemoryLocation, MemVar); // write color to memory       
  }
  if (MemVar != 8){ // prevents ColorChoice from being set to 8 (invalid)
    ColorChoice = MemVar;
  }  
  digitalWrite(ColorOnePin, pinOptions[ColorChoice-1][0]);
  digitalWrite(ColorTwoPin, pinOptions[ColorChoice-1][1]);
  digitalWrite(ColorThreePin, pinOptions[ColorChoice-1][2]);
}
 
Last edited:
You know how an array works, yeah? Remember arrays are always 0 indexed in Arduino.

Code:
boolean arrayName [3] = {1,0,1}; // Creates a boolean array containing [3] values
digitalWrite(Pin, arrayName[0]); // This would turn the pin on (array index 0 is = 1)
digitalWrite(pin, arrayName[1]); // This would turn it off (array index 1 = 0)
digitalWrite(pin, arrayName[2]); // This would again turn it on (index 2 = 1)

So as you can see, instead of creating a new variable for each output state, you can put them all in an array, and just refer to them by their index.

In the case of your code, you have a variable, ColorChoice, that is a number between 1 and 7. Each one of these numbers refers to a set of pins you either want on or off. So what you can do is add another "dimension" to this array, so instead of just having 1 set of numbers, you can have 2 sets. The array is defined as:

Code:
boolean arrayName [rows] [columns]

So in the case of pinOptions, you have 7 rows, and 3 columns. The 7 rows being your 7 possible pin combinations, and the 3 columns being the actual combinations.

So now, you can use your existing ColorChoice variable to pick which column in the array to use. Since your code gives it a value between 1 and 7, and the array is 0 indexed, I added a -1 so it uses the correct row (as when ColorChoice == 7, it would try access row 8, which doesn't exist). The number following is which number in the column to apply to that pin, so [0] [1] and [2]. Assuming you ordered them RGB and using the pinOptions array, if ColorChoice is == 3, then you'd get the array row {1,1,0}, It would write 1 (or HIGH) to the R pin, 1 to the G pin, and 0 to the B pin, and you'd get yellow :) Of course the array can also be any datatype - even strings.

For example if you were using PWM pins for the colour mixing and wanted orange, you could set the row to {255,127,0} :)
 
Last edited:
Aha, why thank you very much Things! What threw me off was the zero indexing and what the argument after arrayName in digitalWrite function was for. I hadn't seen it like that before so while I was able to get the gist of what was happening, I didn't know the mechanics of it.
 
Many thanks to you guys for your help with this.This particular build is one of my most ambitious, and the programming nature of the driver was one of the parts I was most concerned with. It turns out that this has been the first piece to come together.
 
It was my pleasure to help.

Sharing knowledge, gaining understanding, and advancement of the mind are some of the noblest endeavors we can pursue.
 
It was my pleasure to help.

Sharing knowledge, gaining understanding, and advancement of the mind are some of the noblest endeavors we can pursue.

Well this one sure pushed me out of my usual box.

In addition to the added element of using an ATTiny in my driver design, the host is also rather unorthodox. It's intended to be a 5W White (RGB) portable, with a momentary "phaser" type activation, and a total host volume that is just slightly under that of a deck of cards (and roughly the same shape).

I've never made a proper RGB before, so jumping in with something this tiny, with this power output, is really pushing me.
 
Wow that sounds interesting! I've always wanted a RGB but the expense of mirror/dichro/module mounts has kept it just a dream.
 
Wow that sounds interesting! I've always wanted a RGB but the expense of mirror/dichro/module mounts has kept it just a dream.

Adjustable dichro mounts small enough for this build don't exist (or I couldn't find them), so I had to design those from scratch too.

I have some adjustable dichro mounts I'll send you. I can't remember where I got them, but they're about 20mm in size, so they were way too big for this project. These are them:

attachment.php
 

Attachments

  • IMG_20140819_210607.jpg
    IMG_20140819_210607.jpg
    55.7 KB · Views: 80
Oh wow that's awesome! Thank you tremendously! I may have to start saving for a DIY RGB set up! Know of any mounts of standard aixis modules?
 
Last edited:
Oh wow that's awesome! Thank you tremendously! I may have to start saving for a DIY RGB set up! Know of any mounts of standard aixis modules?

Honestly - since you're in the US and shipping is cheap, I'd probably just ask one of the forum's machinist to take a block of aluminum, and drill a 12mm hole at exactly the perfect height for the dichros. I'm sure that would be really really inexpensive. I've had people do that kind of stuff in the past, and the costs were tiny (single digit).
 





Back
Top