user6709: I have some really simple code and tested on an 8 MHz ATtiny85 and ATtiny2313. It's basically a blocking blink:
int relayPin = 7;

long offPeriod = 1 * 60 * 1000;
long onPeriod = 1 * 60 * 1000;

void setup()
{
  pinMode(relayPin, OUTPUT);
}

void loop()
{
  digitalWrite(relayPin, LOW);
  delay(onPeriod);
  digitalWrite(relayPin, HIGH);
  delay(offPeriod);
}

When I assign onPeriod and offPeriod to be 1 * 1000 (1 second), the LED will blink as expected. When I add the 60 second multiplier in, it seems to fail.
For the ATtiny85 I use Arduino Pin 4 (physical pin 3) and for the ATtiny2313, I use Arduino pin 7 (physical pin 9).
I program through the Arduino IDE using boards manager to install the ATTinyCore library for the ATtiny2313 and this for the ATtiny85.
Am I doing something wrong here?
It looks like if I throw the delay in a function, and then invoke it with however many seconds I want, it will work. This is not good as it remains blocking. So perhaps the correct way to do this is to grab timestamps.
Here's the somewhat working code:
int relayPin = 4;
unsigned long offPeriod = 60;
unsigned long onPeriod = 60;

void setup()
{
  pinMode(relayPin, OUTPUT);
}

void loop()
{
  digitalWrite(relayPin, LOW);
  delaySeconds(onPeriod);
  digitalWrite(relayPin, HIGH);
  delaySeconds(offPeriod);
}

void delaySeconds(int s) {
  for (int i = 0; i < s; i++) {
    delay(1000);
  }
}


user368: These are the problem lines:
long offPeriod = 1 * 60 * 1000;
long onPeriod = 1 * 60 * 1000;

Even though long should hold the result, integer operations in C++ are still done in int by default. And on AVR int is 16 bits. The fix is to tell the compiler what size the intermediate result should be:
long offPeriod = 1 * 60L * 1000;
long onPeriod = 1 * 60L * 1000;


user10794: This is absolutely nothing to do with "why can't the atmel attiny family delay over a minute?". It is all to do with the way that C++ works.
See my page about Integer arithmetic and overflow.
To excerpt from that:

On the Arduino (Uno) platform, what do you think will be printed here?
void setup ()
  {
  Serial.begin (115200);
  Serial.println ();

  Serial.println (30000 + 30000); // twice 30000
  Serial.println (60 * 60 * 24);  // seconds in a day
  Serial.println (50 / 100 * 1000); // half of 1000
  }  // end of setup

void loop () { }

Did you guess:
60000
86400
500

Nope!
It prints:
-5536
20864
0

This is because of integer arithmetic. If the compiler can, it treats an numeric literal (like 60) as an int type, which means it has the range -32768 to +32767.
And, arithmetic is done using the type of the largest argument, which means the arithmetic in each case is done as 16-bit arithmetic, and thus it overflows once it reaches 32767.
For example, 30000 + 30000 = 60000 which is 0xEA60 in hex. Unfortunately, 0xEA60 is exactly how -5536 is stored in an int type, which is why it prints -5536.
Meanwhile, 60 * 60 * 24 = 86400 which is 0x15180 in hex. As that doesn't fit in 16 bits, it is truncated to 0x5180 which is 20864 in decimal (as printed).
Finally, in integer arithmetic 50/100 is zero, multiply zero by 1000 and you still get zero, which is why the final result is zero.

Solution
First, you can add a suffix to numeric literals (eg. L for long, or UL for unsigned long), and add a decimal place to floats, like this:
void setup ()
  {
  Serial.begin (115200);
  Serial.println ();

  Serial.println (30000L + 30000); // twice 30000
  Serial.println (60L * 60 * 24);  // seconds in a day
  Serial.println (50.0 / 100 * 1000); // half of 1000
  }  // end of setup

void loop () { }

Now we get:
60000
86400
500.00

You only need to help out with the first literal, once the compiler knows we are using longs (or floats) it sticks with them for the expression.*

* It's actually somewhat more complex than that as this link explains: Understand integer conversion rules.
The compiler "promotes" a value in an expression to match another "higher-ranked" type, under certain circumstances. For example, adding an int and a long will result in the int being promoted to a long (regardless of whether it appears first in the expression or not). However if an int is being added to another int, it will not promote them to a long, even though the result may not fit into an int.

6709: <p>I have some really simple code and tested on an 8&nbsp;MHz <a href="http://www.atmel.com/devices/ATTINY85.aspx" rel="nofollow noreferrer">ATtiny85</a> and <a href="http://www.atmel.com/devices/ATTINY2313.aspx" rel="nofollow noreferrer">ATtiny2313</a>. It's basically a blocking blink:</p>

<pre><code>int relayPin = 7;

long offPeriod = 1 * 60 * 1000;
long onPeriod = 1 * 60 * 1000;

void setup()
{
  pinMode(relayPin, OUTPUT);
}

void loop()
{
  digitalWrite(relayPin, LOW);
  delay(onPeriod);
  digitalWrite(relayPin, HIGH);
  delay(offPeriod);
}
</code></pre>

<p>When I assign <code>onPeriod</code> and <code>offPeriod</code> to be <code>1 * 1000</code> (1 second), the LED will blink as expected. When I add the 60 second multiplier in, it seems to fail.</p>

<p>For the ATtiny85 I use Arduino Pin 4 (physical pin 3) and for the ATtiny2313, I use Arduino pin 7 (physical pin 9).</p>

<p>I program through the Arduino IDE using boards manager to install the ATTinyCore library for the ATtiny2313 and <a href="https://github.com/damellis/attiny" rel="nofollow noreferrer">this</a> for the ATtiny85.</p>

<p>Am I doing something wrong here?</p>

<p>It looks like if I throw the delay in a function, and then invoke it with however many seconds I want, it will work. This is not good as it remains blocking. So perhaps the correct way to do this is to grab timestamps.
Here's the somewhat working code:</p>

<pre><code>int relayPin = 4;
unsigned long offPeriod = 60;
unsigned long onPeriod = 60;

void setup()
{
  pinMode(relayPin, OUTPUT);
}

void loop()
{
  digitalWrite(relayPin, LOW);
  delaySeconds(onPeriod);
  digitalWrite(relayPin, HIGH);
  delaySeconds(offPeriod);
}

void delaySeconds(int s) {
  for (int i = 0; i &lt; s; i++) {
    delay(1000);
  }
}
</code></pre>
 368: <p>These are the problem lines:</p>

<pre><code>long offPeriod = 1 * 60 * 1000;
long onPeriod = 1 * 60 * 1000;
</code></pre>

<p>Even though <code>long</code> should hold the result, integer operations in C++ are still done in <code>int</code> by default. And on AVR <code>int</code> is 16 bits. The fix is to tell the compiler what size the intermediate result should be:</p>

<pre><code>long offPeriod = 1 * 60L * 1000;
long onPeriod = 1 * 60L * 1000;
</code></pre>
 10794: <p>This is absolutely nothing to do with "why can't the atmel attiny family delay over a minute?". It is all to do with the way that C++ works.</p>

<p>See <a href="http://www.gammon.com.au/forum/?id=12146">my page about Integer arithmetic and overflow</a>.</p>

<p>To excerpt from that:</p>

<hr>

<p>On the Arduino (Uno) platform, what do you think will be printed here?</p>

<pre class="lang-c++ prettyprint-override"><code>void setup ()
  {
  Serial.begin (115200);
  Serial.println ();

  Serial.println (30000 + 30000); // twice 30000
  Serial.println (60 * 60 * 24);  // seconds in a day
  Serial.println (50 / 100 * 1000); // half of 1000
  }  // end of setup

void loop () { }
</code></pre>

<p>Did you guess:</p>

<pre><code>60000
86400
500
</code></pre>

<p>Nope!</p>

<p>It prints:</p>

<pre><code>-5536
20864
0
</code></pre>

<p>This is because of <strong>integer arithmetic</strong>. If the compiler can, it treats an numeric literal (like 60) as an int type, which means it has the range -32768 to +32767.</p>

<p>And, arithmetic is done using the type of the largest argument, which means the arithmetic in each case is done as 16-bit arithmetic, and thus it overflows once it reaches 32767.</p>

<p>For example, 30000 + 30000 = 60000 which is 0xEA60 in hex. Unfortunately, 0xEA60 is exactly how -5536 is stored in an int type, which is why it prints -5536.</p>

<p>Meanwhile, 60 * 60 * 24 = 86400 which is 0x15180 in hex. As that doesn't fit in 16 bits, it is truncated to 0x5180 which is 20864 in decimal (as printed).</p>

<p>Finally, in integer arithmetic 50/100 is zero, multiply zero by 1000 and you still get zero, which is why the final result is zero.</p>

<hr>

<h2>Solution</h2>

<p>First, you can add a suffix to numeric literals (eg. L for long, or UL for unsigned long), and add a decimal place to floats, like this:</p>

<pre class="lang-c++ prettyprint-override"><code>void setup ()
  {
  Serial.begin (115200);
  Serial.println ();

  Serial.println (30000L + 30000); // twice 30000
  Serial.println (60L * 60 * 24);  // seconds in a day
  Serial.println (50.0 / 100 * 1000); // half of 1000
  }  // end of setup

void loop () { }
</code></pre>

<p>Now we get:</p>

<pre><code>60000
86400
500.00
</code></pre>

<p>You only need to help out with the first literal, once the compiler knows we are using longs (or floats) it sticks with them for the expression.*</p>

<hr>

<p>* It's actually somewhat more complex than that as this link explains: <a href="https://www.securecoding.cert.org/confluence/display/cplusplus/INT02-CPP.+Understand+integer+conversion+rules">Understand integer conversion rules</a>.</p>

<p>The compiler "promotes" a value in an expression to match another "higher-ranked" type, under certain circumstances. For example, adding an <strong>int</strong> and a <strong>long</strong> will result in the <strong>int</strong> being promoted to a <strong>long</strong> (regardless of whether it appears first in the expression or not). However if an <strong>int</strong> is being added to another <strong>int</strong>, it will not promote them to a <strong>long</strong>, even though the result may not fit into an <strong>int</strong>.</p>
