Problem frequency generator and frequency measure

Hi

I'd like to generate a frequency up to 1 Mhz on pin 8 and measure them on pin 3 (timer1).
The problem ist that i need a timer interrupt which runs the function "frequenz" every second.
How can i use the a timer interrupt.

Thanks

Peter

--- Code ---

#define Ausgangspin 8

unsigned int OutFrequenz = 10000; //Hz (Maximum: 65535 Hz)
long InFrequenz = 0;
long Counter = 0;

void setup()
{
Serial.begin(9600);
Serial.print("Ausgangsfrequenz: ");
Serial.print(OutFrequenz,DEC);
Serial.println(" Hz!");
tone(Ausgangspin, OutFrequenz);
attachInterrupt(1, ping, FALLING);
}

void loop()
{
Serial.print("Eingangsfrequenz: ");
InFrequenz = Counter;
Serial.print(InFrequenz);
Serial.println(" Hz!");
delay(5000);
Counter = 0;
delay(1000);
}

void ping()
{
Counter++;
}

void frequenz()
{
InFrequenz = Counter;
Counter = 0;
}

The code mentions a maximum of 65kHz, you mention a maximum of 1MHz - which is it?

The frequenz routine needs to disable interrupts while looking at and clearing the counter, otherwise it will get garbled values occasionally.

The counter variable should be declared volatile since its accessed by an interrupt routine.

If you could use pin 5 for the input then you could count input pulses directly with timer1 which can be configured to count on that pin.

// Use the code tags for including code - checkout the # button.

Hi

I'd like to generate a maximum of 1MHz.
How is the code for pin5 and timer1 ?

Peter

Something like:

void setup ()
{
  TCCR1A = 0x00 ;
  TCCR1B = 0x07 ;
  ICR1  = 0x0001 ;
  OCR1A = 0x0000 ;
  TCNT1 = 0x0000 ;
  
  Serial.begin (57600) ;
}

int prev = 0 ;
int now  = 0 ;

void loop ()
{
  now = TCNT1 ;
  Serial.println (now-prev) ;
  prev = now ;
  delay (1000) ;
}

But tuned for your application (16 bit counter might need to be sampled more often to avoid wrap-arounds being missed.)

I’ve got a little code tht will output to 1Mhz on pin 9 nd pin 10 inverted
you can easily modify it to use only pin 9 or 10, inverted or not
just don’t add COM1B0(pin 10) or COM1A0(pin 9) toTCCR1B
don’t know about timing something coming in but I suspect you will have to use another timer to create your frequency (a little bit less accurate generation), to use timer1s extra option of input capture to directly advance the counter
for generation this will work tho

 //dynamic frequency generator
//for timer1
#include <avr/io.h>
#include <avr/interrupt.h>
unsigned long frequency = 1000000 ;//select frequency
void setup(){
  pinMode(9,1);
  pinMode(10,1);
  DFG(frequency);
  Serial.begin(57600);
  
}


void loop(){
DFG(frequency);//can change anytime

}

void DFG(unsigned long tempfreq){
  cli();//disable interupts
  TCCR1A = 0;//registers for timer 1
  TCCR1B = 0;
  TCNT1=0;
  TCCR1A |= _BV(COM1A0) + _BV(COM1B0);//sets pin 9&10
  TCCR1B |=_BV(WGM12); 
  TCCR1C = _BV(FOC1A);//inverts one pin to have inverted signals
   if(tempfreq > 122 && tempfreq < 1000001){
  OCR1A = (8000000/tempfreq)-1;//#TIMER COUNTS
  TCCR1B |= _BV(CS10);
  }
  else if(tempfreq <= 122 && tempfreq > 15){
    OCR1A = (1000000/tempfreq)-1;
    TCCR1B |= _BV(CS11);
  }
  else if(tempfreq <= 15 && tempfreq > 4){
    OCR1A = (125000/tempfreq)-1;
    TCCR1B |= _BV(CS10) + _BV(CS11);
  }
  
  //TIMSK1 = _BV(OCIE1A);//TIMER1 COMPARE INTERUPT
  sei();//enable interupts
}

Hi

thanks for the generator code, but i also need the code to measure the incoming frequenz every second.
What ist the best solution ? An overflow interrupt or timer interrupt ?

Peter

The variable counter should be made volatile, otherwise when you read it outside of the IRQ it may be in the process of being changed by the IRQ. It should be an unsigned long. Long because you can count past 1,000,000 and unsigned because you can still know elapsed count past rollover -- then you won't need to zero or synchronize count the same way you don't with millis() and micros(). Count becomes a clock and your IRQ is minimal.

In loop() you need to be able to know the value of counter at a start time and then as close as you can to 1 second later. Subtract counter value at end of 1 second from counter at start and you have your frequency. At no point is counter needed to be made 0, you only need to know when 1 second has passed, which you must do in any case. Again, the minimum. I would use micros() to watch for 1 second, that's as close as I can get without adding external hardware.

With rollover-safe code you can check frequency again and again for a very long time if desired.

My question is why stop at 1 second? 10 seconds will give more accuracy and 100, even more. There is always a small time between one value being set and another instruction reading that due to the sequential nature of the machine, longer intervals will reduce the effect of that.

Hi.
What is the limit for the command attachInterrupt for the arduino Mega 2560 ?
If i measure lower frequencies like 50kHz it works perfectly.
If i count a higher frequency like 350kHz the Serial.print do nothing till i remove pin21 (timer2).
Then the program print a very high number and it works normally.

Peter


//Timer2 Inputpin 21
volatile long InFrequenz = 0;
volatile long counter = 0;

void setup()
{
Serial.begin(9600);
attachInterrupt(3, ping, FALLING);

// initialize timer1
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 62500; // compare match register 16MHz/256/1Hz
TCCR1B |= (1 << WGM12); // CTC mode
TCCR1B |= (1 << CS12); // 256 prescaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
interrupts(); // enable all interrupts
}

void loop()
{
Serial.print(“Eingangsfrequenz: “);
Serial.print(InFrequenz);
Serial.println(” Hz!”);
delay(5000);
}

void ping()
{
counter++;
}

ISR(TIMER1_COMPA_vect) // timer compare interrupt service routine
{
InFrequenz = counter;
counter = 0;
}

Maybe get rid of ISR() and the associated timer code (comment them out, you can un-comment later) then just print the value of counter or counter/5 in loop() and see what that will let you do.

Try increasing serial.begin(9600) to 115600
@9600 its quite slow, and serial being interupt driven probably screws it up

Hi

i tried the options, but it is still the same problem !
If the pin is connected the serial.print do nothing.
If i disconnect the pin 20 it will print the text ??

What is the max. frequency which an Port can handle ?

Peter

Code:
//Timer3 Inputpin 20
volatile long InFrequenz = 0;
volatile long counter = 0;

void setup()
{
Serial.begin(115200);
attachInterrupt(3, ping, FALLING);
}

void loop()
{
Serial.print("Eingangsfrequenz: ");
Serial.print(InFrequenz);
Serial.println(" Hz!");
delay(5000);
}

void ping()
{
// counter++;
}

I think that your main code should clear count, run 5 seconds (or however long) then detach the pin 3 interrupt before printing anything.

attachInterrupt( interrupt #, function, mode ) -- not pin #
http://arduino.cc/en/Reference/AttachInterrupt

Connect your frequency input to pin 3, yes?

edit: this code compiled and tested without frequency source, always says 0 Hz!

volatile unsigned long counter = 0;

void setup()
{
  Serial.begin(115200);
  attachInterrupt(1, ping, FALLING); // pin 3 on UNO and MEGA is interrupt 1
}

void loop()
{
  delay(5000);
  detachInterrupt(1);
  Serial.print("Eingangsfrequenz: ");
  Serial.print(counter/5UL); // for 5 seconds collection, will round down though
  Serial.println(" Hz!");
  attachInterrupt(1, ping, FALLING); 
}

void ping()
{
  counter++;
}

Some day we talk about not using delay but for this it seems perfect.