1

I'm using Timer1 on the Attiny85 clocked at 1MHz to toggle an LED every 1 second. However, I'm having some issues regarding prescaler and OSC value selection.

I'm using this formula, which I found in the datasheet for the Attiny.

fOCnx = fclk/(2*N*(1+OCRnx))

N = Prescaler
I'm taking fOCnx = 0.5Hz as I want a square wave
So based on the above formula, I tried the following cases

  1. N = 2048, OCR1C = 243
  2. N = 4096, OCR1C = 122
  3. N = 8192, OCR1C = 61
  4. N = 16384, OCR1C = 30

The LED toggles after an interval of 1s for cases 3 and 4. However, for cases 1 and, it seems to toggle after 2 seconds. Can anyone tell me why this is happening? Eventually, I want to use this to time data acquisition from a sensor I have so I need to be accurate.

Here's my code

#include <SoftwareSerial.h>

int ledPin = 1;
int state = 0;

SoftwareSerial ser(3, 4);
void setup() {
  // put your setup code here, to run once:
  TCCR1 |= 0x8F;
  OCR1C = 30;
  TIMSK = (1 << OCIE1A);
  pinMode(ledPin, OUTPUT);
  ser.begin(9600);
}


ISR(TIMER1_COMPA_vect)
{
  state = !state;
  digitalWrite(ledPin, state);
  ser.println(state);
}

void loop() {
  // put your main code here, to run repeatedly:
}
12
  • Have you double checked your settings for each case. I don't want to say you made a mistake. But what happens is hard to explain otherwise. My values would be (TCCR1, OCR1C) -> (0x8f,30), (0x8e,61), (0x8d,122), (0x8c,244). I only see one of them in the code, so I can not say if you used the others. If you by accident use (0x8c,122) and then made just subtract 1 and double for the next text (0x8b,244) the observation could be explained. I also have a problem with the 2 in the formula. Where does it come from? Commented Nov 9, 2019 at 16:50
  • Ah, I see why you used 2 in the formula. You don't want 0,5 Hz, you want 2 Hz to toggle 2 times in a period of 1 second (0.5 sec from toggle to toggle. 0.5 Hz would be 2 sec from toggle to toggle). Commented Nov 9, 2019 at 16:57
  • I wrote 0.5Hz because the period of the cycle (On+Off) = 1+1 = 2s so 0.5Hz. I hope I could clarify. Commented Nov 9, 2019 at 17:52
  • yes, then I misunderstood. But then I have no glue why there is the 2 in the formula. fOCnx = fclk/(2*N*(1+OCRnx)) I mean I have no glue why it is in the nominator of the fraction. If I I insert one of the value pairs above I get 1 Hz. If I multiply both sides with 2. I get 2 Herz but not 0.5 Hz. Do you see my problem? Commented Nov 9, 2019 at 17:59
  • Well, unless there is some serious problem with my understanding, all the values calculated satisfy the formula, which I found from the datasheet on page 72. What is the formula you're using? Commented Nov 9, 2019 at 18:09

1 Answer 1

2

The only explanation I have is, that the Software serial switch off the interrupts globally when it operates (print). If interrupts are locked when the timer completes, you loose a tick. It does not explain the different behavior of the four value pairs, but there are some issues reported in a german forum. They did not find an answer, but the assumed it depends on the 'delay()' function, that is used for the software serial and the fact that the interrupts are locked to make the delay function more exact.

If you want to be sure, you can try this by completely removing the Software Serial from your program. If you make the values switchable by e.g. a button press you can change it without having to reload the program. Then it's easier to see different blinking intervals.

int ledPin = 1;
int state = 0;

int regValues[] = { 0x8f, 0x8e, 0x8d, 0x8c };
int cntValues[] = { 30, 61, 122, 243 };

const int buttonPin = 2;
int buttonState = LOW;

long lastDebounceTime = 0;
long debounceDelay = 80; 
int lastButtonState = LOW; 

int pairIndex = 0;

void setup() 
{
  TCCR1 = regValues[ pairIndex ];
  OCR1C = cntValues[ pairIndex ];

  TIMSK = (1 << OCIE1A);

  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
}


ISR(TIMER1_COMPA_vect)
{
  state = !state;
  digitalWrite(ledPin, state);
}

void loop() 
{ 
  int reading = digitalRead(buttonPin);

  if (reading != lastButtonState) 
  {
    lastDebounceTime = millis();
  }

  if ( (millis() - lastDebounceTime) > debounceDelay) 
  {
   if (reading != buttonState) 
   {
      buttonState = reading;

      if (buttonState == HIGH) 
      {
        if ( ++pairIndex > 3 )
        {
          pairIndex = 0;
        }

        TCCR1 = regValues[ pairIndex ];
        OCR1C = cntValues[ pairIndex ];
      }

    }

  }

}

I wrote this code without having a attiny to testing it. So hopefully all is correct. If you would try it, can you please report any errors, so I can correct them?

2
  • Ahh thank you so much! I'll try this code out and get back to you. Commented Nov 12, 2019 at 10:31
  • I tried out your suggestions. Looks like it started worked once I changed the assignment to = instead of |= as I was doing earlier. I guess some other bit was influencing the timer value. Thanks for your help! Commented Nov 17, 2019 at 4:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.