frequency counter for Atmega2560

Hi , Nick Gammon

first thanks for your tutorial on this link Gammon Forum : Electronics : Microprocessors : Timers and counters it is very useful, tutorial
I want to use the code on "Frequency Counter sketch for Atmega2560" on your tutorial, when I tested the code it is counting either odd numbers or even numbers , I tested using sigal generator,

what I wanted is to count numbers for example:
starting from: 80, 81, 82, 83, 84, 85, and so on
but the code is counting for example. 80, 82, 84, 86, 88, 90 and so on it is jumping over a one number
if I start for example 81, it continued as 83, 85, 87, 89, 91

can you please help me by telling what I have to change in your code to count - like . 60,61,62,63, 64,65,66,67,68,69,70 continued like that not jumping any number?

thanks

Yes, well that was on the Atmega328P. Perhaps if you post the code you used we can see what you did and compare it to the datasheet.

Hi, Nick Gammon

thanks for quick reply

I am using Amega2560 - seeeduino,the code is yours: the code is working perfectly,when I tested, the problem is jumping over one number.
here is the code:

// Timer and Counter example for Mega2560
// Author: Nick Gammon
// Date: 24th April 2012

// input on pin D47 (T5)

// these are checked for in the main program
volatile unsigned long timerCounts;
volatile boolean counterReady;

// internal to counting routine
unsigned long overflowCount;
unsigned int timerTicks;
unsigned int timerPeriod;

void startCounting (unsigned int ms) 
  {

  counterReady = false;         // time not up yet
  timerPeriod = ms;             // how many 1 mS counts to do
  timerTicks = 0;               // reset interrupt counter
  overflowCount = 0;            // no overflows yet

  // reset Timer 2 and Timer 5
  TCCR2A = 0;
  TCCR2B = 0;
  TCCR5A = 0;             
  TCCR5B = 0;  

  // Timer 5 - counts events on pin D47
  TIMSK5 = _BV (TOIE1);   // interrupt on Timer 5 overflow

  // Timer 2 - gives us our 1 mS counting interval
  // 16 MHz clock (62.5 nS per tick) - prescaled by 128
  //  counter increments every 8 uS. 
  // So we count 125 of them, giving exactly 1000 uS (1 mS)
  TCCR2A = _BV (WGM21) ;   // CTC mode
  OCR2A  = 124;            // count up to 125  (zero relative!!!!)

  // Timer 2 - interrupt on match (ie. every 1 mS)
  TIMSK2 = _BV (OCIE2A);   // enable Timer2 Interrupt

  TCNT2 = 0;     
  TCNT5 = 0;      // Both counters to zero

  // Reset prescalers
  GTCCR = _BV (PSRASY);        // reset prescaler now
  // start Timer 2
  TCCR2B =  _BV (CS20) | _BV (CS22) ;  // prescaler of 128
  // start Timer 5
  // External clock source on T4 pin (D47). Clock on rising edge.
  TCCR5B =  _BV (CS50) | _BV (CS51) | _BV (CS52);

}  // end of startCounting

ISR (TIMER5_OVF_vect)
{
  ++overflowCount;               // count number of Counter1 overflows  
}  // end of TIMER5_OVF_vect


//******************************************************************
//  Timer2 Interrupt Service is invoked by hardware Timer 2 every 1ms = 1000 Hz
//  16Mhz / 128 / 125 = 1000 Hz

ISR (TIMER2_COMPA_vect) 
{
  // grab counter value before it changes any more
  unsigned int timer5CounterValue;
  timer5CounterValue = TCNT5;  // see datasheet, (accessing 16-bit registers)

  // see if we have reached timing period
  if (++timerTicks < timerPeriod) 
    return;  // not yet

  // if just missed an overflow
  if (TIFR5 & TOV5)
    overflowCount++;

  // end of gate time, measurement ready

  TCCR5A = 0;    // stop timer 5
  TCCR5B = 0;    

  TCCR2A = 0;    // stop timer 2
  TCCR2B = 0;    

  TIMSK2 = 0;    // disable Timer2 Interrupt
  TIMSK5 = 0;    // disable Timer5 Interrupt

  // calculate total count
  timerCounts = (overflowCount << 16) + timer5CounterValue;  // each overflow is 65536 more
  counterReady = true;              // set global flag for end count period
}  // end of TIMER2_COMPA_vect


void setup () {
  Serial.begin(115200);       
  Serial.println("Frequency Counter");
} // end of setup



void loop () {

  // stop Timer 0 interrupts from throwing the count out
  byte oldTCCR0A = TCCR0A;
  byte oldTCCR0B = TCCR0B;
  TCCR0A = 0;    // stop timer 0
  TCCR0B = 0;    
  
  startCounting (500);  // how many mS to count for

  while (!counterReady) 
     { }  // loop until count over

  // adjust counts by counting interval to give frequency in Hz
  float frq = (timerCounts *  1000.0) / timerPeriod;

  // restart timer 0
  TCCR0A = oldTCCR0A;
  TCCR0B = oldTCCR0B;

  Serial.print ("Frequency: ");
  Serial.println ((unsigned long) frq);
  
  // let serial stuff finish
  delay(200);

}   // end of loop

what I have to modify this code so it can count .. 1,2, 3, 4, 5, 6, 7, 8, instead of 1 , 3, 5, 7, 9 or 2, 4, 6, 8, 10 using signal generator.

thanks

startCounting (500);  // how many mS to count for

Would this have anything to do with your trouble?

Change the gate time.

hi dhenry
thanks for helping.
I am not in the lab, I don't have signal generator my selv, I will test after 1 hour, so instead of this startCounting (500);  // how many mS to count for shall I increase or decrease the counting number , I will test soon, but my problem is the code is counting either odd numbers or even numbers, and I want to count both, like this way. 90, 91, 92, 93, 94,95,96 ....... and so on

My telling you what to do doesn't help you, if you don't understand why you are observing what you are observing.

The original code isn't well documented but the following may help you understand what is happening:

unsigned int timerPeriod;

void startCounting (unsigned int ms) 
...
  timerPeriod = ms;             // how many 1 mS counts to do
...
  startCounting (500);  // how many mS to count for
...
  float frq = (timerCounts *  1000.0) / timerPeriod;

Once you figure out the problem, the solution is right there.

Ducaqabe:
I am not in the lab, I don't have signal generator my selv, I will test after 1 hour, so instead of this startCounting (500);  // how many mS to count for shall I increase or decrease the counting number , I will test soon, but my problem is the code is counting either odd numbers or even numbers, and I want to count both, like this way. 90, 91, 92, 93, 94,95,96 ....... and so on

Why are you expecting the count to go up anyway? What frequency are you putting into it?

Putting in 1 KHz square wave I get this:

Frequency: 1000
Frequency: 1000
Frequency: 1000
Frequency: 1000
Frequency: 1000
Frequency: 1000
Frequency: 1000
Frequency: 1000
Frequency: 1000
Frequency: 1000
Frequency: 1000
Frequency: 1000
Frequency: 1000
Frequency: 1000
Frequency: 1000
Frequency: 1000
Frequency: 1000

I don't see why it would increase by odd or even numbers. It is supposed to be giving you the frequency of counts per second, with the gate time (that dhenry mentioned) being the sample period.

Change the gate time.

Which way, dhenry? Provide reasons for your answer.

dhenry:
The original code isn't well documented but the following may help you understand what is happening:

I have repeatedly asked you to post code to demonstrate some of the things you claim you have done, dhenry. If you were to do so, we could see how properly-written and documented code looks like.

Hello Nick and thanks much for your posting on this link Gammon Forum : Electronics : Microprocessors : Timers and counters . It is very useful, in helping me get started with an Arduino 2560 that Im using to collect 2 frequency signals and 7 analog signals... My frequency signals range from 1 - 15 Khz on one channel and 4 khz on the second channel.

I have your code running fine for the input on pin 47 but having problems getting the second frequency recognized. The second input reads only 0's ...

My modifications to your original code to include a second input include the following additions...Im wondering if you can glance at this and see the error of my ways..

// Reset timers 2, 4, and 5

TCCR4A = 0
TCCR4B = 0
TCCR5A = 0
TCCR5B = 0

// Count the events on D43 & D47

TIMSK4 = bit (TOIE4);
TIMSK5 = bit (TOIE5);

after Timer 2 stuff ... set all timers to zero

TCNT2 = 0
TCNT4 = 0
TCNT5 = 0

// Start timer 4 and 5

TCCR4B = bit (CS40) | bit (CS41) | bit (CS42)
TCCR5B = bit (CS50) | bit (CS51) | bit (CS52)

//Run the ISR

timer4CounterValue = TCNT4
timer5CounterValue = TCNT5

// If just missed an overflow

if (TIFR5 & TOV5 || TIFR4 &TOV4)

// stop timers 2, 4 and 5

// disable timers 2, 4 and 5

// calculate the total counts

timerCountsSpeed = (overflowCount << 16) + timer4CounterValue;
timerCountsTorque = (overflowCount << 16) + timer5CounterValue;

I have your code running fine for the input on pin 47 but having problems getting the second frequency recognized. The second input reads only 0's ...

My modifications to your original code to include a second input include the following additions...Im wondering if you can glance at this and see the error of my ways..

You are trying to adapt a sketch which uses the external clock source as input for the timer. That input for Timer5 is broken out on the mega digital pin 47.

Unfortunately, there is no breakout for the equivalent pin on Timer 4. You need to spend some time looking at the Arduino pin out diagrams along with the processor pin diagrams. Where did you get the idea that you should be reading the second frequency on pin 43?

You need to go back to Nick's website, and look at the frequency counters near the bottom of the pages in replys #12 and #13. They use the input capture pins and not the external clock source. You should be able to modify one of the for your two frequencies on the Mega. For the Mega ICP5 = digital pin 48 and ICP4 is digital 49.

thanks cattledog .... Ill take a look .. not sure where I found the mapping to pin 43 and T4 but tried several combinations without successful combination. At a glance it looks like T4 is available on processor pin 27 but thats not mapped to a terminal on Mega.... Ill take a look at Nicks other freq measurement posting...

thank again