Help with Timer1

Can some kind soul help me adressing the Timer1 in arduino instead of IDE-Preset functions?
I want higher res on external interrupt. This below needs to be rewritten the hardcore way.
I dont understand and would like it to be rewritten…

Best!
//

int mic1 = 2;// using leonardo for external interrupts on theese pins.
int mic2 = 3;
int mic3 = 7;

volatile unsigned long tid1 = 0; //Var to store time-stamp in micros in.
volatile unsigned long tid2 = 0;
volatile unsigned long tid3 = 0;
volatile int stop1 = 0;//Flags in interrupts to not trigger again.
volatile int stop2 = 0;
volatile int stop3 = 0;

void setup() {

pinMode(mic1, INPUT);
pinMode(mic2, INPUT);
pinMode(mic3, INPUT);
pinMode(11, OUTPUT);//Eg Buzzer to beep when all triggs ar OK!

Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(mic1), trig1, FALLING);//How to write this in the hardcore way removing IDE presets???

attachInterrupt(digitalPinToInterrupt(mic2), trig2, FALLING);
attachInterrupt(digitalPinToInterrupt(mic3), trig3, FALLING);

}

void loop() {

if (stop1 == 1 && stop2 == 1 && stop3 == 1) {

stop1 = 20;//Avoid triggs by changing state to 20 or anything but 0...
stop2 = 20;
stop3 = 20;

// These things write to an external application.
Serial.print(“A”);
Serial.write((byte)0x00);
Serial.print(tid1);
Serial.write((byte)0x00);
Serial.print(“B”);
Serial.write((byte)0x00);
Serial.print(tid2);
Serial.write((byte)0x00);
Serial.print(“C”);
Serial.write((byte)0x00);
Serial.print(tid3);
Serial.write((byte)0x00);
Serial.println();

//End writing to external application…

delay(250); //ECHO-Delay.

//reset states.

tid1 = 0;
tid2 = 0;
tid3 = 0;

stop1 = 0;
stop2 = 0;
stop3 = 0;

}
}

void trig1() {

if (stop1 == 0);
tid1=micros();// How to write this the hardcore way adressing timer1 to get the value based om clockcycles?
tid1=tid1;// Just so it doesent rely on function micros that gives error for me.

stop1 = 1; //Raise flag to avoid more/future interruppts…

}

void trig2() {

if ( stop2 == 0);
tid2=micros();
tid2=tid2;

stop2 = 1;

}

void trig3() {

if ( stop3 == 0);
tid3=micros();
tid3=tid3;

stop3 = 1;

}

// Fast Timer
// Written by John Wasser
//
// Returns the current time in 16ths of a microsecond.
// Overflows every 268.435456 seconds.

// Note: Since this uses Timer1, Pin 9 and Pin 10 can’t be used for
// analogWrite().

void StartFastTimer()
{
noInterrupts (); // protected code
// Reset Timer 1 to WGM 0, no PWM, and no clock
TCCR1A = 0;
TCCR1B = 0;

TCNT1 = 0; // Reset the counter
TIMSK1 = 0; // Turn off all Timer1 interrupts

// Clear the Timer1 Overflow Flag (yes, by writing 1 to it)
// so we don’t get an immediate interrupt when we enable it.
TIFR1 = _BV(TOV1);

TCCR1B = _BV(CS10); // start Timer 1, no prescale
// Note: For longer intervals you could use a prescale of 8
// to get 8 times the duration at 1/8th the resolution (1/2
// microsecond intervals). Set ‘_BV(CS11)’ instead.

TIMSK1 = _BV(TOIE1); // Timer 1 Overflow Interrupt Enable
interrupts ();
}

volatile uint16_t Overflows = 0;

ISR(TIMER1_OVF_vect)
{
Overflows++;
}

unsigned long FastTimer()
{
unsigned long currentTime;
uint16_t overflows;

noInterrupts();
overflows = Overflows; // Make a local copy

// If an overflow happened but has not been handled yet
// and the timer count was close to zero, count the
// overflow as part of this time.
if ((TIFR1 & _BV(TOV1)) && (TCNT1 < 1024))
overflows++;

currentTime = overflows; // Upper 16 bits
currentTime = (currentTime << 16) | TCNT1;
interrupts();

return currentTime;
}

// Demonstration of use
#if 1
void setup()
{
Serial.begin(115200);
while (!Serial);
StartFastTimer();
}

void loop()
{
static unsigned long previousTime = 0;
unsigned long currentTime = FastTimer();

Serial.println(currentTime - previousTime);
previousTime = currentTime;

delay(100);
}
#endif

1 Like

Johnwasser.
U r definitly Going to be on my creditlist for ever.

Thank U extremely much. Karma!

One more q?
Am i totally off here doing like this combining my interrupts with your Fast timer?
Hence the prescaler is none and i want the answer in micros, what shall i then divide with to get the current micros? ( See bold text in trigs)…I cannot change the reading in the external apllication therefore it has to be this way…

65535-16000/1024 ? or something like that?

// Fast Timer
// Written by John Wasser
//
// Returns the current time in 16ths of a microsecond.
// Overflows every 268.435456 seconds.

// Note: Since this uses Timer1, Pin 9 and Pin 10 can’t be used for
// analogWrite().

void StartFastTimer()
{
noInterrupts (); // protected code
// Reset Timer 1 to WGM 0, no PWM, and no clock
TCCR1A = 0;
TCCR1B = 0;

TCNT1 = 0; // Reset the counter
TIMSK1 = 0; // Turn off all Timer1 interrupts

// Clear the Timer1 Overflow Flag (yes, by writing 1 to it)
// so we don’t get an immediate interrupt when we enable it.
TIFR1 = _BV(TOV1);

TCCR1B = _BV(CS10); // start Timer 1, no prescale
// Note: For longer intervals you could use a prescale of 8
// to get 8 times the duration at 1/8th the resolution (1/2
// microsecond intervals). Set ‘_BV(CS11)’ instead.

TIMSK1 = _BV(TOIE1); // Timer 1 Overflow Interrupt Enable
interrupts ();
}

volatile uint16_t Overflows = 0;

ISR(TIMER1_OVF_vect)
{
Overflows++;
}

unsigned long FastTimer()
{
unsigned long currentTime;
uint16_t overflows;

noInterrupts();
overflows = Overflows; // Make a local copy

// If an overflow happened but has not been handled yet
// and the timer count was close to zero, count the
// overflow as part of this time.
if ((TIFR1 & _BV(TOV1)) && (TCNT1 < 1024))
overflows++;

currentTime = overflows; // Upper 16 bits
currentTime = (currentTime << 16) | TCNT1;
interrupts();

return currentTime;
}

// Demonstration of use
//#if 1
//void setup()
//{
// Serial.begin(115200);
// while (!Serial);
// StartFastTimer();
//}

//void loop()
//{
// static unsigned long previousTime = 0;
// unsigned long currentTime = FastTimer();

// Serial.println(currentTime - previousTime);
// previousTime = currentTime;

//delay(100);
//}
//#endif

//____________________________________________________________________________________________________

int mic1 = 2;// using leonardo for external interrupts on theese pins.
int mic2 = 3;
int mic3 = 7;

volatile unsigned long tid1 = 0; //Var to store time-stamp in micros in.
volatile unsigned long tid2 = 0;
volatile unsigned long tid3 = 0;
volatile int stop1 = 0;//Flags in interrupts to not trigger again.
volatile int stop2 = 0;
volatile int stop3 = 0;

void setup() {
StartFastTimer();

pinMode(mic1, INPUT);
pinMode(mic2, INPUT);
pinMode(mic3, INPUT);
pinMode(11, OUTPUT);//Eg Buzzer to beep when all triggs ar OK!

Serial.begin(115200);
attachInterrupt(digitalPinToInterrupt(mic1), trig1, RISING);//How to write this in the hardcore way removing IDE presets???

attachInterrupt(digitalPinToInterrupt(mic2), trig2, RISING);

attachInterrupt(digitalPinToInterrupt(mic3), trig3, RISING);

}

void loop() {

if (stop1 == 1 && stop2 == 1 && stop3 == 1) {

stop1 = 20;
stop2 = 20;
stop3 = 20;

Serial.print("A");
Serial.write((byte)0x00);
Serial.print(tid1);
Serial.write((byte)0x00);
Serial.print("B");
Serial.write((byte)0x00);
Serial.print(tid2);
Serial.write((byte)0x00);
Serial.print("C");
Serial.write((byte)0x00);
Serial.print(tid3);
Serial.write((byte)0x00);
Serial.println();



delay(250);

tid1 = 0;
tid2 = 0;
tid3 = 0;

stop1 = 0;
stop2 = 0;
stop3 = 0;

}
}

void trig1() {

if (stop1 == 0);
tid1 = FastTimer();
stop1 = 1;
tid1 = tid1/62.5;

stop1 = 1;

}

void trig2() {

if ( stop2 == 0);
tid2 = FastTimer();
stop2 = 1;
tid2 = tid2/62.5;

stop2 = 1;

}

void trig3() {

if ( stop3 == 0);
tid3 = FastTimer();
stop3 = 1;
tid3 = tid3/62.5;

stop3 = 1;

}

With the prescale set to 1, the clock runs at 16,000,000 counts per second or 16 counts per microsecond. Divide by 16 to get microseconds.

:slight_smile:
Heh…Of course.

But… Now these interrupts are as modified in the Leonardo. Lest say i want to move the code to an UNO then pin interrupts are just active on pin 0 and 2, therfore fighting with serial.print. Is there a way to rewrite it so that it compiles as PinChange interrupt for say A0 to A5?

Sure. Use a Pin Change Interrupt library. Then just return if the CHANGE was not the edge you wanted.

The External Interrupts on the UNO are on Pin 2 and Pin 3 so they do not interfere with Serial on Pin 0 and Pin 1.

John!! U seem like u know stuff bout timers others dont.
I have a q here, that if solved can give the angle to the soundsource Quite easy if solved, avoiding arrays and other phase related complicated stuff.

U think one Can use timers and interrupts to figure out the sine wawe length therby the frequency of the sound?

Yes. I’d use Timer1 and the Input Capture Register. It can save the TCNT1 register and initiate an interrupt when it sees a RISING or FALLING edge on Pin 8 of an UNO. Subtract the previous ICR from the current ICR to measure the wavelength in clock ticks (16ths of a microsecond). Divide into 16000000 to get frequency in Hz.

1 Like

//Interrupt-test by fast timer Johnwasser.
//Modified by Nils Bruhner.
//
// Still not fast enough, well maybe fast, but not stable enough.
//Is there a way to enhance the reading of the interrupts?
//It shall basically read the speed of sound, with the help of trigging mics. Analog or digital.
//Any Ideas?

void StartSnabbTimer()
{
noInterrupts ();
// Reset Timer 1
TCCR1A = 0;
TCCR1B = 0;

TCNT1 = 0;
TIMSK1 = 0;

TIFR1 = _BV(TOV1);

TCCR1B = _BV(CS10);

TIMSK1 = _BV(TOIE1);
interrupts ();
}

volatile uint16_t Overflows = 0;

ISR(TIMER1_OVF_vect)
{
Overflows++;
}

unsigned long SnabbTimer()
{
unsigned long currentTime;
uint16_t overflows;

noInterrupts();
overflows = Overflows; // Lokal kopia

if ((TIFR1 & _BV(TOV1)) && (TCNT1 < 1024))
overflows++;

currentTime = overflows; // övre 16 bitar
currentTime = (currentTime << 16) | TCNT1;
interrupts();

return currentTime;
}

//____________________________________________________________________________________________________

int mic1 = 2;// Leonardo
int mic2 = 3;
int mic3 = 7;

volatile unsigned long tid1 = 0;
volatile unsigned long tid2 = 0;
volatile unsigned long tid3 = 0;
volatile int stop1 = 0;
volatile int stop2 = 0;
volatile int stop3 = 0;

void setup() {
StartSnabbTimer();

pinMode(mic1, INPUT);
pinMode(mic2, INPUT);
pinMode(mic3, INPUT);
pinMode(11, OUTPUT);//Eg Buzzer

Serial.begin(115200);
attachInterrupt(digitalPinToInterrupt(mic1), trig1, RISING);
attachInterrupt(digitalPinToInterrupt(mic2), trig2, RISING);
attachInterrupt(digitalPinToInterrupt(mic3), trig3, RISING);
}

void loop() {

if (stop1 == 1 && stop2 == 1 && stop3 == 1) {

stop1 = 20;
stop2 = 20;
stop3 = 20;

Serial.print("A");
Serial.write((byte)0x00);
Serial.print(tid1);
Serial.write((byte)0x00);
Serial.print("B");
Serial.write((byte)0x00);
Serial.print(tid2);
Serial.write((byte)0x00);
Serial.print("C");
Serial.write((byte)0x00);
Serial.print(tid3);
Serial.write((byte)0x00);
Serial.println();


delay(250);

tid1 = 0;
tid2 = 0;
tid3 = 0;

stop1 = 0;
stop2 = 0;
stop3 = 0;

}
}

void trig1() {

if (stop1 == 1);
tid1 = SnabbTimer();
stop1 = 1;
tid1 = tid1 / 16;
stop1 = 1;

}

void trig2() {

if ( stop2 == 0);
tid2 = SnabbTimer();
stop2 = 1;
tid2 = tid2 / 16;
stop2 = 1;

}

void trig3() {

if ( stop3 == 0);
tid3 = SnabbTimer();
stop3 = 1;
tid3 = tid3 / 16;
stop3 = 1;

}