Using timer1 of an ATtiny84

Hi,
finally I want to generate a variable delay and then a pulse of about 1 ms to be used in a phase control for motor control. Timer1 and the output compare interrupts A and B of an ATtiny84 shall be used for that purpose.
To understand timer1 I wanted to test it without interrupts in following sketch:

#include <SoftwareSerial.h>

#define CLCK_SEL_BITS   (5)   // ./. 1024, 64 usec steps

SoftwareSerial mySerial(5, 6);  // RX, TX

uint32_t baudrt, t0, t1;
uint16_t lcnt = 0;

void setup() {
  // put your setup code here, to run once:
  baudrt = 38400;
  mySerial.begin(baudrt);
  delay(100);
  mySerial.println();
  mySerial.print("Baudrate=");
  mySerial.println(baudrt);

  // Timer1 konfigurieren
  TCCR1A = 0; // OC1A/OC1B disconnected, normal mode
  TCCR1B = 0; // normal mode, no clock
  TCCR1C = 0; // no force output compare
  TCNT1 = 0;  // clear counter
  TIFR1 = 0;  // clear interrupt flags
  TIMSK1 = 0; // OCIE1A und OCIE1B Interrupts disable

  while (1) {
    OCR1B = 0x6000;  // output compare B match is early
    OCR1A = 0xC300;  // output compare A match is later
    TCNT1 = 0;   // clear counter register
    TIFR1 = 0;  // clear all interrupt flags
    TCCR1B = (1<<CS12) | (1<<CS10); // Timer start, ./. 1024
    while (TIFR1 & 4 == 0); // wait for output compare B match flag
    TCCR1B = 0;  // timer stop, time for print()
    mySerial.print(TIFR1); 
    mySerial.print(" ");
    mySerial.print(TCNT1H,HEX); mySerial.print(TCNT1L,HEX);
    mySerial.print(" ");
    TCCR1B =  (1<<CS12) | (1<<CS10); // Timer continue
    while (TIFR1 & 2 == 0); // wait for output compare A match flag
    TCCR1B = 0;  // timer stop
    mySerial.print(TIFR1); 
    mySerial.print(" ");
    mySerial.print(TCNT1H,HEX); mySerial.println(TCNT1L,HEX);
    delay(5000);
  }
}

void loop() {
  // put your main code here, to run repeatedly:

}
The code is edited according to first answer!

After configuring timer1 the while loop is the intended test.
My understanding of timer1 is that timer1 provides two output compare registers A and B. When the counter equals register B and A the corresponding flags are set and if interrupts are enabled, corresponding interrupt routines will be fired.

With this understanding my intention is to generate a delay corresponding to the value of OCR1B. When the counter matches OCR1B an output bit is set (to trigger a triac) and when the counter matches OCR1A (OCR1A > OCR1B) the bit is reset and the counter resets automatically (Clear Timer on Compare with OCR1A). The time between OCR1B and OCR1A is the pulse length.

The while loop in the sketch simulates the sequence of processing and the prints shall show the states of flags and content of counter.
What I expected on the Serial Monitor is:

4  600  6 C30        (a hex value of 0 is printed as a single "0")

meaning OCF1B=1 and counter value 0x6000 then OCF1B=1,OCF1A=1 and counter 0xC300.
After compare match with OCR1A the counter is stopped. Therefore an overflow never should occur.

What I get is:

7 00  7 00

7 means that OCF1B=OCF1A=TOV1=1, i.e. both output compare flags and overflow flag are set and the counter always is 0.

I don't understand how timer1 really works. Can somebody explain it to me, please.

In order to understand the timer, you first need to know what each individual bit in each register does. It does not help at all that your code hides that information.

For example, what is the point of writing
TCCR1B = CLCK_SEL_BITS; // Timer start, ./. 1024

when this makes so much more sense (with the data sheet close at hand, of course)?
TCCR1B = (1 << CS12) | (1 <<CS10); //prescaler CLKIO/1024

Also, the compiler knows how to correctly read and write 16 bit values from/to the 16 bit timer registers, so you don't need to worry about the individual bytes. Drop the code addressing the high and low bytes. Read and print TCNT1 directly.

    TCNT1H = 0;   // clear counter register
    TCNT1 = 0;

I studied the data sheet and derived the register settings from that. Well, the code is somewhat better readable using e.g. (1<<CS12) but even so it is necessary to have the data sheet at hand to understand what effect (1<<C12) has.

My problem is not understanding the meaning of the bits in the registers. I don't understand why e.g. the counter reading immediately after an output compare match with OCR1B=0x6000 is zero and not 0x6000, or why all flags in the TIFR1 register a set to 1 when during counting only the first compare match at 0x6000 occurred and 0xC300 is far away, where the second match should occur, and the counter can run up to 0xFFFF where an overflow occurs.

I found the solution. There were several errors.

  1. clearing the interrupt flags is
TIFR1=7; // instead of TIFR1=0;
  1. waiting for the interrupt flags being set is
if ((TIFR1&4) == 0);  // instead of if (TIFR1&4 == 0); 
...
if ((TIFR1&2) == 0);  // instead of if (TIFR1&2 == 0); 

now it works as expected :slight_smile:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.