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?

My intention for the randomness mode is that it is randomized on powerup. For some context, this build is going to be triggered by a momentary switch (by virtue of a mosfet that controls power to everything, the ATTiny, the buck drivers, etc). So the concept of a random mode is essentially the idea that each "shot" (each triggering of the circuit) would be a different color.

So I'll need to move the random generation into the chip's startup. Does the ATTiny have any kind of temperature sensor, or some sort of input of some sort that we can just hash and get a random number from? Is there anything equivalent to the "randomize timer" function in VB?
 





Have updated the previous code.

I also changed the pinOptions array to boolean .. though for whatever stupid reason they still occupy 1 byte in Arduino, even though they can only be 0 or 1, 1 bit. The code probably would fit on the tiny13 if that was the case :(

Ah, much more transparent now. I follow. Thanks!

My intention for the randomness mode is that it is randomized on powerup. For some context, this build is going to be triggered by a momentary switch (by virtue of a mosfet that controls power to everything, the ATTiny, the buck drivers, etc). So the concept of a random mode is essentially the idea that each "shot" (each triggering of the circuit) would be a different color.

So I'll need to move the random generation into the chip's startup. Does the ATTiny have any kind of temperature sensor, or some sort of input of some sort that we can just hash and get a random number from? Is there anything equivalent to the "randomize timer" function in VB?

Ahh, I see. Yes and no. There's no external sensor but you can fudge one using an ADC input. Problem is... in all my experiments and tests I've never been able to get this to work. The ATTiny/Arduino references all say to analogRead() an unused input pin and use that resultant 0-255 value for the randomSeed() seeding function. This all hinges on the assumption that a floating input will have a random voltage on it. My floating inputs all read 0 or 255 every time. Additionally, there is a bug in the standard library for att/arduino that low values entered into randomSeed() result in random()s that are all evenly divisible by 7. So, you need a large enough seed number to get a better pseudorandom output and there's no real way to get it.

I was planning on polling micros() and using that as the seed for a new PRNG, but this requires that the chip be powered on for a while (at least 100uS or so before you get decent values) and you can't put it in void setup() as that function would have been completed well before 100uS.

You could add a voltage divider biased to 1/2 the input voltage and capacitively couple the output from a thermistor to that and then read that with an ADC. Or, you could make a discrete NPN BJT noise generator and amplify it to 0.7-1.25Vp-p and capacitively couple that to the 2.5V reference and read that by the ADC. Doing that gives you true random, but you need +8V or so to make the noise source and it requires tweaking to get the output level just right. I've done it a few times, it isn't something I can walk you through really (especially if you don't have a good fast (40MHz or better) scope and assortment of resistors or trimmer pots).

Again, if it wasn't on startup you could just use micros() or even do some math on micros() to get true random.

What about using the last input as a TTL line, then you toggle that pin's state to get a new random?
 
What if during startup, if it's in random mode (8), the program just sleeps for say 500 uS and then polls micros() ?

That's 1/2000 th of a second (if my knowledge of units is correct), so I don't think the delay would feel like a hit to responsiveness of the power-up button press.

EDIT: I'm having a hell of a time fitting this circuit into 0.96 square inches.... one of my toughest PCB layouts so far.
 
Last edited:
Only problem with a set delay is you'll run into the same non-random issue. If you delay 500uS for example then micros() will return roughly 700uS (for example, wild guess) each time. The idea behind polling micros is that each start up the amount of time since start to the point of calling micros not-in-setup would be different because of user delay, if there's no user delay there's no randomization to when micros is polled.

Any suggestions here, Things? You're way more knowledgeable with ATTiny/Arduino than I am.

Edit: you could try

RandTime = random(200,500);
randomSeed (RandTime);
ColorChoice = random (1,7);

Might work. Never tried it.
 
Last edited:
I've got a solution.

Poll micros() at the time of button press leading to random mode - we'll be at least a second in at that point. Write a long random string of digits to eeprom.

At startup, when in random mode, use that string (some algorithm that turns it into a number from 1 to 7). Then also do something to that long string to pick a new long string (doesn't have to be truly random, just different). Write that new long string to eeprom for next time.

Downside is it's an eeprom write per power up. But that's only when in random mode, and it's still only one per power up.

EDIT:

So at time of selecting random mode, write a 6 digit truly pseudo random number to EEPROM. Then take its MOD 8 to pick a random color and output that color.

At next power up, grab that number from EEPROM, multiply it by 9999 and then drop the leftmost and rightmost digits until it's down to 6 digits or less. Write that number to EEPROM. Take it's MOD 8 to pick a random color and display that color.

Repeat.

Not actually random after the first color, because it's technically predetermined from that point on, but it will be indistinguishable from random.
 
Last edited:
Any suggestions here, Things? You're way more knowledgeable with ATTiny/Arduino than I am.

I'd consider using another EEPROM value as the seed - basically just set the EEPROM value to something random in the main loop, possibly seeded by millis(), then use the EEPROM value as a seed on the next startup (and subsequently re-set it to something else in the loop).

You don't even have to re-randomize on startup, just use the EEPROM value from last time it was randomized :)
 
Last edited:
I'd consider using another EEPROM value as the seed - basically just set the EEPROM value to something random in the main loop, possibly seeded by millis(), then use the EEPROM value as a seed on the next startup (and subsequently re-set it to something else in the loop).

You don't even have to re-randomize on startup, just use the EEPROM value from last time it was randomized :)

That's more or less what I was thinking above. True per-instance pseudo randomization isn't necessary, as long as the first instance is randomized, and the colors that follow aren't in an obvious pattern.

I tried to take a stab at what I was suggesting in my previous post. I'm sure that some of this will be wrong, but I've used a bunch of
===========================
======start of new stuff========
===========================
lines like that ^ to indicate where I've made change's to the most recent code version. I'm completely out on a limb with my use of left/right string functions.

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
================================
======start of new stuff========
================================
int RandomVar;
int RandomVarNew;
int GenerateRandom;
===============================
=======end of new stuff========
===============================

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

================================
======start of new stuff========
================================
  if (MemVar == 8){
    RandomVar = EEPROM.read(MemoryLocation);
    RandomVar = 9999 * RandomVar
    // does this language allow use of string functions on an int?
    // the following fuction is surely incorrect syntax
    RandomVarNew = int( left(RandomVar, 3) & right(RandomVar, 3) )
    EEPROM.write(RandomVar, RandomVarNew); // Write new number
    ColorChoice = (RandomVarNew % 7) + 1;
  }
===============================
=======end of new stuff========
===============================
}

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...
        ================================
        ======start of new stuff========
        ================================
	GenerateRandom = random(100000, 999999);
	ColorChoice = (GenerateRandom % 7) + 1; // I think this is how you do modulus?
        EEPROM.write(RandomVar, GenerateRandom); // Write initial psuedu random number
        ===============================
        =======end of new stuff========
        ===============================
    }  
    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:
I think you have to convert the int to binary and then do bitwise math on it in order to select the center bits you want. Likewise the EEPROM can only store a single byte (0-255) of data in a single location, so you'd have to break down the seed into bytes and then store them individually, then recall them and put them back together. That's above my level of expertise unfortunately. My C++ background is CLI level engineering and scientific programs.

I'm not 100% clear on this next section:

Code:
    RandomVarNew = int( left(RandomVar, 3) & right(RandomVar, 3) )
    EEPROM.write(RandomVar, RandomVarNew); // Write new number
    ColorChoice = (GenerateRandom % 7) + 1;

The first line I assume you're trying to do bitwise math on RandomVar. The second line is clear. The third line I'm not sure of since you didn't initialize the GenerateRandom value prior to this line of code, and thus its value is zero. Zero modulo 7 = 0, +1 = 1. This would set color choice to 1 each time. Was GenerateRandom supposed to be a function and not a variable?
 
Last edited:
I think you have to convert the int to binary and then do bitwise math on it in order to select the center bits you want. Likewise the EEPROM can only store a single byte (0-255) of data in a single location, so you'd have to break down the seed into bytes and then store them individually, then recall them and put them back together. That's above my level of expertise unfortunately. My C++ background is CLI level engineering and scientific programs.

I'm lost on this, unfortunately. Maybe someone else has some thoughts on how to accomplish randomness at startup?

I'm not 100% clear on this next section:

Code:
    RandomVarNew = int( left(RandomVar, 3) & right(RandomVar, 3) )
    EEPROM.write(RandomVar, RandomVarNew); // Write new number
    ColorChoice = (GenerateRandom % 7) + 1;

The first line I assume you're trying to do bitwise math on RandomVar. The second line is clear. The third line I'm not sure of since you didn't initialize the GenerateRandom value prior to this line of code, and thus its value is zero. Zero modulo 7 = 0, +1 = 1. This would set color choice to 1 each time. Was GenerateRandom supposed to be a function and not a variable?

First line:
What I'm trying to do is throw away some information. So for example if the new number was 38593660394, we'd take the left 3 and the right 3 and create 385394 as the new number. It's just a way of tossing out data.

Third line:
That was a mistake on my part. I've just edited the post to fix it, but it should have referred to RandomVarNew instead of GenerateRandom (which is a variable name I was using as I drafted the code, but changed to RandomVarNew - I just missed the change in that line)

Code:
    RandomVar = EEPROM.read(MemoryLocation);
    RandomVar = 9999 * RandomVar
    RandomVarNew = int( left(RandomVar, 3) & right(RandomVar, 3) )
    EEPROM.write(RandomVar, RandomVarNew); // Write new number
    ColorChoice = (RandomVarNew % 7) + 1;
 
Last edited:
Ahh ok, I follow now.

I don't think you can use those string functions on integers, but I'm not an expert here. I think you need to convert to binary and then use bitwise math and bit shifting to do what you want. I've got no experience in those algorithms unfortunately.

I do remember reading something about being able to pull integer/long data out of a string, but I don't know if you can convert the other direction, and more so I don't know if the ATTiny can do it, or even if the arduino can do it. I read it in reference to C++ on windows systems.

The more likely solution is probably as Things stated; run a pseudorandom function in the main loop, do a modulo 7 + 1 to get it into range, write it to eeprom, and then use it for a seed. Read eeprom on start up as normal for MemVar, if it is 8 then read the eeprom seed byte and use it in the PRNG to get the new random colorchoice.
 
Last edited:
The more likely solution is probably as Things stated; run a pseudorandom function in the main loop, do a modulo 7 + 1 to get it into range, write it to eeprom, and then use it for a seed. Read eeprom on start up as normal for MemVar, if it is 8 then read the eeprom seed byte and use it in the PRNG to get the new random colorchoice.

I don't think that will work. A number from 1 to 7 surely isn't a seed that can be used for randomness. Plus, more to the point, if the seed is 4 (the color was 4), that will always lead to the same color next. So it will produce a consistent pattern (that may even miss colors).

EDIT: what about this approach?
http://m.instructables.com/id/ATtin...imple-and-CHEAP/step3/Program-the-ATtiny-MCU/

EDIT 2: If you think the fact that the input is regulated will make this approach not work, what about adding a thermister on the pin input? This board's temperature will be changing after each activation. It's a sub 1 square inch board containing three switching regulators capable of 4A each - it will be a heat factory.
 
Last edited:
Your edit#1 link doesn't work (the link works, the idea doesn't). I've tried it on regulated and unregulated supplies, the "floating" pins just don't float for me.

I mentioned adding a thermistor and resistor for temperature sensing as a random seed earlier, figured you didn't like it when you didn't mention it since size is an issue. Can easily do that. Just size the resistor to bias the output to ~2.5V at room temp and send that in to the unused ADC line (A2). analogRead it and use as randomSeed, then random(1,7) for ColoChoice. Put all of that in the void setup() inside of an if(){} conditional for MemVar==8.

(I type most of this out for my own reference because tomorrow I will have forgotten the steps to implement otherwise and will have to redo it in my head!)
 
Last edited:
Your edit#1 link doesn't work (the link works, the idea doesn't). I've tried it on regulated and unregulated supplies, the "floating" pins just don't float for me.

I mentioned adding a thermistor and resistor for temperature sensing as a random seed earlier, figured you didn't like it when you didn't mention it since size is an issue. Can easily do that. Just size the resistor to bias the output to ~2.5V at room temp and send that in to the unused ADC line (A2). analogRead it and use as randomSeed, then random(1,7) for ColoChoice. Put all of that in the void setup() inside of an if(){} conditional for MemVar==8.

(I type most of this out for my own reference because tomorrow I will have forgotten the steps to implement otherwise and will have to redo it in my head!)

I just read up on AnalogRead, and it's only a 10 bit output. I doubt there will be enough voltage change on the pin to result in this approach working :(

Back to the drawing board....

Based on this thread, and understanding a bit better how the seed function works, I think the best idea is still to generate a fairly random seed at time of button press when the random mode is selected, and save that to EEPROM. Then, on startup, use that value as a seed, and generate a new see to save to EEPROM.

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=88724
 
Last edited:
Re: Thermistor; you could add amplification via BJTs but you'd be eating up space again.

Will there be any optical splash near the circuit? Or exposed room lighting? Could do a photocell.
 
Re: Thermistor; you could add amplification via BJTs but you'd be eating up space again.

Will there be any optical splash near the circuit? Or exposed room lighting? Could do a photocell.

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?
 
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 :)
 


Back
Top