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
- N = 2048, OCR1C = 243
- N = 4096, OCR1C = 122
- N = 8192, OCR1C = 61
- 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:
}
1 Answer 1
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?
-
Ahh thank you so much! I'll try this code out and get back to you.Souvik Saha– Souvik Saha2019年11月12日 10:31:46 +00:00Commented 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!Souvik Saha– Souvik Saha2019年11月17日 04:49:28 +00:00Commented Nov 17, 2019 at 4:49
Explore related questions
See similar questions with these tags.
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?