Re: MyTimer library. (no overflows)

int8_t daysCounter = 0;

After 254 days, 23 hours, 59 minute, and 59 seconds, a tick happens. Then what?

How does this timer provide microsecond resolution?

That's just an example, if you need more days, just change to unsigned long. ;-)

I'm still working out the details for another timer lib...

Wk

I'm still working out the details for another timer lib...

You might be interested in this link for your project.

Korman

Yup, that’s me, I like to reinvent stuff. :sunglasses: But heck, at least I’m learning something on the way. :wink: :smiley:

Wk

I'm trying to learn how to reduce from 128 to 8 prescale but it just won't work correctly, not even 64 prescale... Could it be the inline call slowing down the process? (removing makes it worse)

Wk

Also, if I could learn how to deal with the 16 bit timer, and if its not taking already by something else, I could just do the whole PPQ counter for my midi project with that, instead of counting and counting. Each overflow would be the actual PPQ time. But with the 8 bit timer it won't be precise enough... :-(

Wk

Here we go, I removed the other posts as they had old codes and there’s no Modify option for the first post. (why?)

The new code is up, and its a complete Timer solution, as now it actually uses the Timer frequency for the Timer.

http://arduino.wusik.com

http://www.wusik.com/arduino/Libraries/MyTimer/MyTimer.zip

I also create 2 nice examples. One is a great Midi Clock running at 960 PPQ and doesn’t miss a pulse! :sunglasses:

MyTimer.h

/*

      Original code from the Tone Library by Brett Hagman

      Adapted and Optimized by WilliamK @ Wusik Dot Com (c) 2010
      http://arduino.wusik.com

      Compact 8 Bit Timer (uses Timer2)

      Min frequency for Start() = 62 hz at 16 Mhz clock or 32 hz at 8 Mhz clock
      Max frequency for Start() = 16 Mhz at 16 Mhz clock or 8 Mhz at 8 Mhz clock

      Just add to your Arduino code the following:
            
            ISR(TIMER2_COMPA_vect)
            { 
                  // Add here the code you want to execute, just be sure its short so the next call doesn't overlap the previous one //
            } 

*/

#ifndef MYTIMER_h
#define MYTIMER_h

#include <inttypes.h>
#include "HardwareSerial.h"

// ------------------------------------------------------------------------------------------- //
class MyTimer
{
public:
      MyTimer();
      
      void stop(void);
      void start(float frequency);
};

#endif

MyTimer.cpp

/*

      Original code from the Tone Library by Brett Hagman

      Adapted and Optimized by WilliamK @ Wusik Dot Com (c) 2010
      http://arduino.wusik.com

      Compact 8 Bit Timer (uses Timer2)

      See MyTimer.h for instructions

*/

#include "WConstants.h"
#include "MyTimer.h"

// ------------------------------------------------------------------------------------------- //
MyTimer::MyTimer() 
{
      //
}

// ------------------------------------------------------------------------------------------- //
void MyTimer::start(float frequency)
{
      stop();

    TCCR2A = 0;
    TCCR2B = 0;
    bitWrite(TCCR2A, WGM21, 1);
    bitWrite(TCCR2B, CS20, 1);

      uint32_t ocr = F_CPU / frequency - 1;
      uint8_t prescalarbits = 0b001;

      if (ocr > 255)
      {
            ocr = F_CPU / frequency / 8 - 1;
            prescalarbits = 0b010;

            if (ocr > 255)
            {
                  ocr = F_CPU / frequency / 32 - 1;
                  prescalarbits = 0b011;
            }

            if (ocr > 255)
            {
                  ocr = F_CPU / frequency / 64 - 1;
                  prescalarbits = 0b100;

                  if (ocr > 255)
                  {
                        ocr = F_CPU / frequency / 128 - 1;
                        prescalarbits = 0b101;
                  }

                  if (ocr > 255)
                  {
                        ocr = F_CPU / frequency / 256 - 1;
                        prescalarbits = 0b110;
                        
                        if (ocr > 255)
                        {
                              ocr = F_CPU / frequency / 1024 - 1;
                              prescalarbits = 0b111;

                              if (ocr > 255)
                              {
                                    stop();
                                    Serial.println("MyTimer Error!");
                                    return;
                              }
                        }
                  }
            }
      }

      TCCR2B = prescalarbits;
      OCR2A = ocr;
      bitWrite(TIMSK2, OCIE2A, 1);
}

// ------------------------------------------------------------------------------------------- //
void MyTimer::stop(void)
{
      bitWrite(TIMSK2, OCIE2A, 0);
      TCCR2A = (1 << WGM20);
      TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22);
      OCR2A = 0;
}

Check the ZIP file for examples:
http://www.wusik.com/arduino/Libraries/MyTimer/MyTimer.zip

But here’s the Midi Example:

/*
  
  Created by WilliamK @ Wusik Dot Com
  http://arduino.wusik.com
  
  Serial @ 115200 bauds
  
  Simple Midi Clock Test
  It will count all beats in one minute and time to check if its near 60 seconds
  Min BPM = 40
  
*/

#include <WProgram.h>
#include <MyTimer.h>

unsigned long startTime;
unsigned long ppqtime;
unsigned int BPM = 120;
unsigned int PPQ = 960;
unsigned int beats = 0;
unsigned int ppqcounter = 0;
byte notesCounterTest = 12;
boolean notesCounterTestGoUp = true;
#define NoteOn 0x90
#define MSerial Serial3 // Rename to test on other Arduino Boards, you may need to change the main Serial calls too //

MyTimer timer = MyTimer();

ISR(TIMER2_COMPA_vect) 
{ 
  if (beats == 0 && ppqcounter == 0) startTime = millis();
  
  ppqcounter++;
  
  if (ppqcounter == PPQ)
  {
    ppqcounter = 0;
    beats++;
    if (beats == BPM)
    {
      timer.stop();
      Serial.println("All BPM Done!");
      Serial.print("Processed Time MS: ");        
      Serial.println(millis() - startTime);
      BPM += 25;
      if (BPM <= 300) updateTime();
      return;
    }
  }
  
  // Send several midi notes at the first beat //
  if (ppqcounter == 0) 
  { 
    sendCmd(NoteOn, 0x3C-48, 0x7F); sendCmd(NoteOn, 0x3C-24, 0x7F); sendCmd(NoteOn, 0x3C-36, 0x7F);  sendCmd(NoteOn, 0x3C-12, 0x7F); 
    sendCmd(NoteOn, 0x3C, 0x7F); sendCmd(NoteOn, 0x3C+12, 0x7F); sendCmd(NoteOn, 0x3C+36, 0x7F); sendCmd(NoteOn, 0x3C+24, 0x7F); sendCmd(NoteOn, 0x3C+48, 0x7F);
  }
  
  for (int xp=0; xp<32; xp++)
  {
    if (ppqcounter == ((PPQ/32)*xp))
    {
      sendCmd(NoteOn, notesCounterTest, 0x7F); 
      if (notesCounterTestGoUp)
      {
        notesCounterTest++;
        if (notesCounterTest > 112) notesCounterTestGoUp = false;
      }
      else
      {
        notesCounterTest--;
        if (notesCounterTest < 24) notesCounterTestGoUp = true;
      }
    }
  }
}

void setup() 
{
  Serial.begin(115200);
  MSerial.begin(31250);
  updateTime();
}

void updateTime()
{
  ppqtime = (float(BPM)*float(PPQ))/60.0f;
  Serial.println("");
  Serial.print("BPM: ");
  Serial.println(BPM);
  Serial.print("PPQ: ");
  Serial.println(PPQ);
  Serial.print("PPQ HZ: ");    
  Serial.println(ppqtime);
  beats = 0;
  ppqcounter = 0;
  timer.start(ppqtime);
}

void sendCmd(char cmd, char data1, char data2)
{
  MSerial.print(cmd, BYTE);
  MSerial.print(data1, BYTE);
  MSerial.print(data2, BYTE);
}

void loop() 
{
  //
}

Now, if you need lower HZ than 62, its actually easy, just set to 62 and put a counter inside it.

62 * 10 = 6.2 hz 62 * 100 = 0.62 hz

Just see the other example I included in the ZIP file, for a Seconds (1000ms) counter.

Wk

I’m really loving Timers, as it helps my Midi project a lot. I did another test here with some of my main midi project files, and it works great.

I setup 120 BPM and 960 PPQ and had the Timer send a midi note on every beat (ppqCounter == 0) and while in the Loop I had all sort of things going on. LCD Update, reading, writing and reading again from the SD Card I’m using, checking if the data is correct, Encoder check, 16 buttons and leds check. It doesn’t interfere with the Timer interrupts, which is great. Is like having 2 Threads now! :sunglasses: During my initial tests I couldn’t get more than 48 PPQ using regular micros() calls, now, I can go up to 960 PPQ and it runs great!

Thanks to everybody who helped me out so far.

Best Regards, WilliamK

I renamed to Timer2 as it uses timer2, makes more sense. New files with complete examples ready for download.

http://arduino.wusik.com

Wk