Go Down

Topic: Hardware-Interrupt-Counter via Register (TCCRx) (Read 377 times) previous topic - next topic



I'm working with Interrupts for counting signals for about one year now - and things worked very fine with AttachInterrupt and incrementing variables in an ISR  (https://www.arduino.cc/en/Reference/AttachInterrupt). Using an Arduino Uno I counted signals on Digital Pin 2 and Digital Pin 3.

At the moment I do have troubles with my code (problems in timing and communication), that's why I wanted to outsource the counting-task to one of the registers of the ATMega328P (see chapter 15.4 in the Atmel-datasheet at http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf).

Unfortunately I do find plenty of general informations (Timer 0 is 8 bit and used for delay() and millis(), Timer 1 is 16 bit and used by the Servo library, Timer 2 is 8 bit and used for the tone library) about timers (for example http://www.instructables.com/id/Arduino-Timer-Interrupts/), preloaders and prescalers - but almost nothing about a simple counter!

Since I do use millis() from time to time I would prefer Timer 1 or Timer 2, and since I do not see a reason for using 16 bits I would prefer the timer 2 with 8 bit incrimenting a variable after every overflow (255 counts) or after a specific number of counts (timer compare interrupt?) without prescaler or preloader.

I tried the following setup
Code: [Select]
  cli();//stop interrupts
  TCCR2A=0; // set entire TCCR2A register to 0
  TCNT2  = 0;//initialize counter value to 0
  TCCR2A |= (1 << WGM21); // turn on CTC mode
  TIMSK2 |= (1 << OCIE2A); // enable timer compare interrupt
  sei();//allow interrupts

and the following ISRs:
Code: [Select]
ISR(TIMER2_COMPA_vect) { // timer compare interrupt service routine
  zaehler_compare_match++; //

ISR(TIMER2_OVF_vect) { // timer für Überlauf
  zaehler_ueberlauf++; //

Nothing is working now, and I do not know how to declare a specific pin for my signal and how to get the data (255*zaehler_ueberlauf+counter) and reset the counter after a specific time (every second: millis()%1000==0). And I do not know, if I could count 2 pins in parallel?
Could anyone please help me with this problem?

Thanks a lot!


Aug 13, 2017, 02:05 pm Last Edit: Aug 13, 2017, 02:05 pm by MarkT
Each timer has a specific pin it counts. timer0 uses Arduino pin 4, timer1 uses Arduino pin 5.  timer2
does not support counting.

In the datasheet pins are named Tx if they are the count input to timer x
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]



thank you for your input, so Timer2 is a bad idea.. Timer0 is a taboo if I do want to use millis() -> I do have to use Timer1 and Digital Pin 5 (and there is no possibility to do 2 measurements in parallel)

Do you have an idea of an usable code?
Code: [Select]
  TCCR1A=0; // set entire TCCR1A register to 0
  TCCR1B=0; // set entire TCCR1B register to 0 (16 bit)
  TCNT1  = 0;//initialize counter value to 0
  TIMSK1 |= (1 << TOIE1); // enables overflow interrupt

Code: [Select]
ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{  overflow_counter++;}

seem to be a good start - however I have no idea how to get out the counted numbers?

Thank you!


Aug 13, 2017, 06:16 pm Last Edit: Aug 13, 2017, 06:16 pm by cattledog
Do you have an idea of an usable code?
Here is an example of a simple frequency counter. It uses blocking code and the counting period is for high speed counts, but this will give you the set up for the external clock source. The external clock source can be set for rising or falling edge. You read the counts with TCNT1. If the counts go over the 16 bit limit, you will need to deal with rollover counting.

Code: [Select]

//frequency counter using Timer1 counter without overflow count
//TCNT1 16 bit max value = 65,534
//20ms sample period gives frequency counter to a bit over 3.2 mhz

unsigned int dwell = 20000; // dwell in microseconds for counter
unsigned long final_counts;
unsigned long start_time;
unsigned long measured_time;

void setup()
  TCCR1A = 0; //initialize Timer1
  TCCR1B = 0;
  TCNT1 = 0;

  pinMode( 5, INPUT_PULLUP); //external source pin for timer1

void loop()
    start_time = micros();
    TCNT1 = 0;//initialize counter
    // External clock source on Timer1, pin (D5). Clock on rising edge.
    // Setting bits starts timer
    TCCR1B =  bit (CS10) | bit (CS11) | bit (CS12); //external clock source pin D5 rising edge

    while (micros() - start_time < dwell) {} // do nothing but wait and count during dwell time

    TCCR1B = 0; //stop counter
    final_counts = TCNT1; //frequency limited by unsigned int TCNT1 without rollover counts

    measured_time = micros() - start_time;

    Serial.print(measured_time); // report resulting counts
    Serial.println(50 * final_counts); //20ms sample in Hz

Go Up