Attiny85 and Timer1 librairy

Hi,

Here is a interesting tutorial on how to dim 120v light with the arduino. Everything works just fine :

http://wiki.dxarts.washington.edu/groups/general/wiki/4dd69/AC_Dimmer_Circuit.html

Now I want to write this code on an Attiny85 , but I am getting an error. I looked online for solutions and seems that the TImerOne.h isn't compatible with the Attiny85. Does it make sense? This code works fine on my Arduino Uno.

and the code (I changed " int AC_pin = 1" .It is originally "int AC_pin = 11;") :

/*
AC Light Control
 
 Updated by Robert Twomey <rtwomey@u.washington.edu>
 
 Changed zero-crossing detection to look for RISING edge rather
 than falling.  (originally it was only chopping the negative half
 of the AC wave form). 
 
 Also changed the dim_check() to turn on the Triac, leaving it on 
 until the zero_cross_detect() turn's it off.
 
 Adapted from sketch by Ryan McLaughlin <ryanjmclaughlin@gmail.com>
 http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230333861/30
 
 */

#include <TimerOne.h>           // Avaiable from http://www.arduino.cc/playground/Code/Timer1

volatile int i=0;               // Variable to use as a counter
volatile boolean zero_cross=0;  // Boolean to store a "switch" to tell us if we have crossed zero
int AC_pin = 1;                // Output to Opto Triac
int dim = 0;                    // Dimming level (0-128)  0 = on, 128 = 0ff
int inc=1;                      // counting up or down, 1=up, -1=down

int freqStep = 65;    // This is the delay-per-brightness step in microseconds.
// It is calculated based on the frequency of your voltage supply (50Hz or 60Hz)
// and the number of brightness steps you want. 
// 
// The only tricky part is that the chopper circuit chops the AC wave twice per
// cycle, once on the positive half and once at the negative half. This meeans
// the chopping happens at 120Hz for a 60Hz supply or 100Hz for a 50Hz supply. 

// To calculate freqStep you divide the length of one full half-wave of the power
// cycle (in microseconds) by the number of brightness steps. 
//
// (1000000 uS / 120 Hz) / 128 brightness steps = 65 uS / brightness step
//
// 1000000 us / 120 Hz = 8333 uS, length of one half-wave.

void setup() {                                      // Begin setup
  pinMode(AC_pin, OUTPUT);                          // Set the Triac pin as output
  attachInterrupt(0, zero_cross_detect, RISING);   // Attach an Interupt to Pin 2 (interupt 0) for Zero Cross Detection
  Timer1.initialize(freqStep);                      // Initialize TimerOne library for the freq we need
  Timer1.attachInterrupt(dim_check, freqStep);      
  // Use the TimerOne Library to attach an interrupt
  // to the function we use to check to see if it is 
  // the right time to fire the triac.  This function 
  // will now run every freqStep in microseconds.                                            
}

void zero_cross_detect() {    
  zero_cross = true;               // set the boolean to true to tell our dimming function that a zero cross has occured
  i=0;
  digitalWrite(AC_pin, LOW);       // turn off TRIAC (and AC)
}                                 

// Turn on the TRIAC at the appropriate time
void dim_check() {                   
  if(zero_cross == true) {              
    if(i>=dim) {                     
      digitalWrite(AC_pin, HIGH); // turn on light       
      i=0;  // reset time step counter                         
      zero_cross = false; //reset zero cross detection
    } 
    else {
      i++; // increment time step counter                     
    }                                
  }                                  
}                                   

void loop() {                        
  dim+=inc;
  if((dim>=128) || (dim<=0))
    inc*=-1;
  delay(18);
}

error:

acdimmer_sleeping.ino: In function 'void setup()':
acdimmer_sleeping:16: error: expected unqualified-id before '.' token
acdimmer_sleeping:17: error: expected unqualified-id before '.' token

Ok now here the new error message I get: TimerOne doesn't seems to be accepted.

C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp: In member function 'void TimerOne::initialize(long int)':
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:51: error: 'TCCR1A' was not declared in this scope
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:52: error: 'TCCR1B' was not declared in this scope
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:52: error: 'WGM13' was not declared in this scope
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp: In member function 'void TimerOne::setPeriod(long int)':
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:70: error: 'ICR1' was not declared in this scope
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:73: error: 'TCCR1B' was not declared in this scope
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp: In member function 'void TimerOne::pwm(char, int, long int)':
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:96: error: 'TCCR1A' was not declared in this scope
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:100: error: 'TCCR1A' was not declared in this scope
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp: In member function 'void TimerOne::disablePwm(char)':
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:109: error: 'TCCR1A' was not declared in this scope
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:110: error: 'TCCR1A' was not declared in this scope
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp: In member function 'void TimerOne::attachInterrupt(void (*)(), long int)':
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:117: error: 'TIMSK1' was not declared in this scope
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp: In member function 'void TimerOne::detachInterrupt()':
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:125: error: 'TIMSK1' was not declared in this scope
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp: In member function 'void TimerOne::resume()':
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:130: error: 'TCCR1B' was not declared in this scope
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp: In member function 'void TimerOne::start()':
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:142: error: 'TIMSK1' was not declared in this scope
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:143: error: 'PSRSYNC' was not declared in this scope
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp: In member function 'void TimerOne::stop()':
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:163: error: 'TCCR1B' was not declared in this scope
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp: In member function 'long unsigned int TimerOne::read()':
C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:204: error: 'ICR1' was not declared in this scope

Tiny85 timers aren't compatible with Mega328 timers.

Ok Thank you !!! So any way of changing the code so it would work? Just wondering before digging in to it.

or I will just buy an atmega 328 chip.

fungus:
Tiny85 timers aren't compatible with Mega328 timers.

Correction: t85 timer 1 is not compatible with m328 timer 1. Timer 0 on the two processors is identical (and appears to be for all AVR processors).

playagood:
or I will just buy an atmega 328 chip.

The ATtiny84 is a reasonable alternative. Timer 0 and timer 1 are identical for both processors.

That is just great!!! I will try that tomorrow when I pick up an Attiny84 at my local store.

Thank you

I hadn't noticed that. It's worth knowing...

playagood:
or I will just buy an atmega 328 chip.

Not a bad idea...

Using ATtinys doesn't make much practical sense when you factor in the time spent programming, getting libraries to work, etc. You can easily get Mega328 boards for $6 plus change. eg. http://www.ebay.com/itm/310562519074

If you use ATtinys it's because you enjoy using them. :slight_smile:

Time spent on programming is a good point. Atmega328 might be a good choice.

I'm just back from the store and I tried to load the code on the Attiny84. The error message is not as heavy as with the Attiny85:

C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:148: error: 'PSRSYNC' was not declared in this scope

Note that Timer/Counter1 and Timer/Counter0 share the same prescaler and a reset of this prescaler will affect both timers.

Given the fact that millis is on timer 0 resetting the prescaler is really a bad idea. I wonder why the TimerOne author does that?

I'm just back from the store and I tried to load the code on the Attiny84. The error message is not as heavy as with the Attiny85:

Do you want help with that or are you committed to using an ATmega328?

Not true. Timer0's prescaler is in TCCR0B and Timer1's prescaler is in TCCR1.

That's a quote from the ATmega328 datasheet.

Oh, I was looking at the Tiny85 datasheet.

(which is silly, because he's got a Tiny84...)

PS: I wish there were shops around here that you could just pop in and buy an ATtiny84.

fungus:
PS: I wish there were shops around here that you could just pop in and buy an ATtiny84.

One of the advantages of living where I do ... mouser.com is close enough that, no matter what I choose for shipping, the package arrives the next day. :smiley:

I wouldn't mind give it a try. I just bought 2 of these , so why not!!

and thank you for your time.

#include <TimerOne.h>           // Avaiable from http://www.arduino.cc/playground/Code/Timer1

Is that correct? Are you using the TimerOne library available from that link?

Yep. That's the one.

First, the "what"...

C:\arduino-1.0.3-windows\arduino-1.0.3\libraries\Timer1\TimerOne.cpp:148: error: 'PSRSYNC' was not declared in this scope

Searching the ATmega328 datasheet we find that PSRSYNC is used when resetting the prescaler. There are only 36 Google hits of PSRSYNC on this forum. ("pig latin" has two hits.) And, it looks like most of the 36 hits are posts from users like you who want TimerOne to work on other processors. Clearly, resetting the prescaler is not done very often in the Arduino world.

The next quest is "why". Is it necessary to reset the prescaler for TimerOne to function correctly? The method of interest...

void TimerOne::start()  // AR addition, renamed by Lex to reflect it's actual role  
{
    unsigned int tcnt1;
    TIMSK1 &= ~_BV(TOIE1);        // AR added
    GTCCR |= _BV(PSRSYNC);                // AR added - reset prescaler (NB: shared with all 16 bit timers);
    oldSREG = SREG;                               // AR - save status register
    cli();                                                // AR - Disable interrupts
    TCNT1 = 0;
    SREG = oldSREG;                       // AR - Restore status register

    do {  // Nothing -- wait until timer moved on from zero - otherwise get a phantom interrupt
          oldSREG = SREG;
          cli();
          tcnt1 = TCNT1;
          SREG = oldSREG;
    } while (tcnt1==0);

    //  TIFR1 = 0xff;                       // AR - Clear interrupt flags
    //  TIMSK1 = _BV(TOIE1);              // sets the timer overflow interrupt enable bit  
}

I cannot find any documentation for the start method. In addition, this comment is at the top of the header file...

    • start() amended to enable interrupts

Clearly that is no longer true. We cannot rely on the comments being correct.

As far as I can tell, start is only called by restart which is never called from the library. There is no calling context for start. We're left with no answer as to why the author felt it was necessary to reset the prescaler (or even when or why we would call start or restart).

So, do you call start or restart?