help with pulse counter program

Hi!

I'm making a pulsecounter program to my Atmega 328 Duemilanova. It counts the number of pulses the arduino can receive during a time of 0.05s. I actualy havent decided yet how fast the pulses from my encorder should be coming to my arduino, but i want my program to be as fast and reliable as possible. (I would like it to work with at least Something like from 400Hz up to 5kHz). Could this program code do that for me, or do i need to modify anything?

Would be great if someone friendly could have a look at my code and give me some advises.

#include "TimerOne.h"

int lastpulse=0;
int pulse=0;
unsigned long counter=0;

void setup()
{
  Serial.begin(9600);
  pinMode(2, INPUT);
  Timer1.initialize(1000000);
  Timer1.attachInterrupt(callback);
  attachInterrupt(0, change, FALLING);
}

void loop()
{
}

void change()
{
  counter++;
}

void callback()
{
  Serial.println(counter);
  counter=0;
}

I've been looking at the frequencyCounter lirary but i think it is to hard for me to understand and work with.

Thanks!!!

Any variable used in an ISR should be declared volatile.

Changing the value of counter, which is non-byte sized, will require disabling interrupts, changing the value, and re-enabling interrupts. You would not want another interrupt to fire while you were in the middle of updating a 4 byte value.

I've never used TimerOne, but that does not look like a 0.05 second initialization.

Serial printing in an ISR is not recommended. Set a flag to tell loop that it needs to print the (copied) value. After printing, clear the flag.

Wow, really fast answers! Thank you very much!

ok, ill change to a volatile! Why do you think it doesnt look like a 0.05 second initialization? Do I have to use something else?

Serial printing in an ISR is not recommended. Set a flag to tell loop that it needs to print the (copied) value. After printing, clear the flag.

yes, i hade a thought that this should be mentioned, and i think your right. How do i set a flag then?

How do i set a flag then?

flag = 1;

Why do you think it doesnt look like a 0.05 second initialization?

I looked at the library. The value in the initialize() call defines how often the interrupt handler gets invoked, in microseconds.

  Timer1.initialize(1000000);

That looks like a lot of microseconds for 0.05 seconds. Could just be me, though.

yes, it should be a value of 5000micros istead of 1000000micros, but i havent changed that yet. Could I get the program to set a flag that it is time to print every "callback" instead of doing the interrupt handling? Or do i just simply set flag = 1; in the interrupt and then reading the flag-value in my loop? What would be the fastest and most reliable option here? I really need to print every 0.05s, not every 0.051s or 0.049s.

Transmitting at 9600bps, it will take approximately 0.001s to transmit each serial character.

Increase the serial port speed to 57600 and you'll be able to get that counter printed out in less time. You will have to live with the fact that for the time it takes to print out the counter, you will not be counting pulses for the next cycle.

One option is to use an external counter and latch. The incoming pulses are counted by the counter, the Timer1 interrupt simply sets a flag telling the loop to print the value, latches the value, copies the value from the latch to memory, unlocks the latch and leaves the counter to run.

In the loop, use the previous value of the "latched count" to determine how many more events have occurred. Print that number out at your leisure.

If it is important that your serial output begin as close as possible to the timer interrupt, you can print during the interrupt handler. Since the counter is external to the micro controller it will keep counting even while interrupts are disabled (which they will be inside the interrupt handler).

Allright, ill set the program for a higher port speed!

One option is to use an external counter and latch.

So you think i should use a timer2 to count pulses, or do i get you wrong?

If it is important that your serial output begin as close as possible to the timer interrupt, you can print during the interrupt handler. Since the counter is external to the micro controller it will keep counting even while interrupts are disabled (which they will be inside the interrupt handler).

This sounds like the thing i need, but it is quite difficult programming, isnt it?

Thanks for the help!

This sounds like the thing i need, but it is quite difficult programming, isnt it?

It seems to me that if this really was the case, you'd start by trying to optimize the data being sent. Sending the count as a string is neither fast nor efficient.

Sending the count as a string is neither fast nor efficient

So you suggest me to sent it in binary or hexa instead?

So you suggest me to sent it in binary or hexa instead?

Yes, I do.

Yes, I do

Ok, that could i do.

But is there any library to use to set the external counter?

Allright, I made this new code based on the frequency library. But i cant have it to work. First of all I want to get the string "test" serial.printed from the ISR to see so that it is working, because right now it isnt, and i cant understand why. If anyone could have a look and help me i would be very happy! Here is the code:

unsigned int volatile flag = 0;
unsigned long volatile pulses = 0;

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))    //means a 0
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))       //means a 1

void setup(){
  
pinMode(5, INPUT);
Serial.begin(57600);

  
//Settings timer1

TCCR1A=0;          //Reset counter1 controlregister A
TCCR1B=0;          //------------------II---------- B?
TCNT1=0;           //Resest counter1

sbi (TCCR1B ,CS10);    //External clock source, pin 5.
sbi (TCCR1B ,CS11);
sbi (TCCR1B ,CS12);

//settings for timer2, that will generate the gate time

sbi (TCCR2B ,CS20);    //prescaler sets to 1024
sbi (TCCR2B ,CS21); 
sbi (TCCR2B ,CS22);

cbi (TCCR2A ,WGM20);   //enable CTC mode, "Clear timer on compare"
sbi (TCCR2A ,WGM21);   
cbi (TCCR2A ,WGM22);
OCR2A=254;             //The value for the CTC mode to compare to.

TCNT2=0;               //resets timer2 
sbi (TCCR2A ,OCIE2A);  //enable Timer2 interrupt.

//some other settings

cbi (TIMSK0 ,TOIE0);   //Disables timer0
sbi (GTCCR,PSRASY);    //Reset prescaler counter
TCCR1B = TCCR1B | 7;    //sets counter clock source to T1.
}


void loop(){
  if(flag==1){
    Serial.println(pulses,HEX);
    flag=0;
  }
}

  
//Interrupt from timer2
ISR(TIMER2_COMPA_vect){
  Serial.print("test");
  flag=1;
  pulses=TCNT1;
  sbi(TIFR1 ,TOV1);    //reseting counter1 and the overflow flags.
}

Thank you VERY much so far for the help!

I made this pulse counter. May it helps you.. Check it out,,

int count = 0;
int previousValue = 0;
int currentValue = 0;
void setup()
{
   pinMode(10, INPUT);
   digitalWrite(10, HIGH);
   Serial.begin(9600);
}
void loop()
{
   currentValue = digitalRead(10);
   if (previousValue != currentValue)
   {
      if(currentValue == HIGH)
        {Serial.println("HIGH");
         ++count;
         Serial.println(count);}
       if (currentValue == LOW)
         Serial.println("LOW");
    } 
previousValue = currentValue; 
}