How to create an ISR to analogRead and change a variable during a function call

I’m working on developing a beat machine for a project.

I have created a library with functions that are called dependent on an analogPin reading.

What I would like to happen is that the pitch input and speed input are changed “Real time” rather than being called after a series of function called from the library.

After some research I believe that creating a time based ISR is a the way to complete this but I’m unsure as to how exactly to proceed. I’ve tried using millis() but it didn’t seem to work so most likely it doesn’t work or I was implementing it incorrectly.

I’ve attached all files below.

Still a novice and would appreciate some help.

beets.ino (225 Bytes)

Beets_machine.cpp (7.34 KB)

Beets_machine.h (1.04 KB)

Volume.cpp (3.43 KB)

Volume.h (651 Bytes)

When looking for help, you really need to ask a specific question, not state some concepts and attach five files that so far, no one has downloaded. I’ll never see them because I’m using a tablet and downloading is more of a pain than it’s worth.

You can easily create a time based interrupt using one of the many timer libraries out there but I don’t know what you’re trying to do. Please describe the goal of your program, not the bits and pieces of the program itself.

Apologies, I've yet to get all conventions of the forum.

But to answer your quesiton. The code in the main tab is as follows:

#include "Beets_machine.h"
#include "Volume.h"

Volume vol;
Beets Beets;

void setup() {
Serial.begin(9600);
}

void loop() {

 uint8_t playSpeed = Beets.SpeedPot(A1);
  int inputSpeed = map(playSpeed,0,255,200,1000);
  Beets.Speed(inputSpeed);



  uint8_t pitch = Beets.PitchPot(A0);
  int inputPitch = map(pitch,0,255,100,1000);
  Beets.Pitch(inputPitch);

  
  

  
  uint8_t sound = Beets.SoundPot(A5);
     
  Beets.beets(vol, sound,2);
  
  sound = Beets.SoundPot(A4);

  Beets.beets(vol, sound,8);

  sound = Beets.SoundPot(A3);
 
  Beets.beets(vol, sound,9);

  sound = Beets.SoundPot(A2);
  
  Beets.beets(vol, sound,10);
  



}

The four Beets.beets(vol,sound,ledPin) function creates a predefined rhythm from the library.

The problem is that the Beets.Pitch(inputPitch) and Beets.Speed(inputSpeed) aren't called until the four beets functions are called.

The solution is a timer that momentarily and very very quickly interrupts the Beets.beets() performs an analog read on the speedPot and pitchPot and changes the variable for inputPitch and inputSpeed dependent on changes to the analog pins.

Joshua_M_K:
What I would like to happen is that the pitch input and speed input are changed “Real time” rather than being called after a series of function called from the library.

The first thing to consider is why the calls to analogRead() are not happening often enough without the need for an ISR. I suspect that some part of your program is blocking the Arduino from calling the ADC as often as needed. If so, that is what needs to be fixed.

Have a loot at the demo Several Things at a Time. Note how each function runs very briefly and returns to loop() so the next one can be called. And there may be dozens of calls to a function before it is actually time for it to do anything.

…R

The reason I believe that it is happening is how I've written the beat functions within the library, for example

void Beets:: ninth(Volume &vol) {
  digitalWrite(_pin,HIGH);
   vol.tone(_pitch, 255);
  vol.fadeOut(10 / delayTime);
  vol.delay(delayTime / 9);

  vol.tone(_pitch, 127);
  vol.fadeOut(10 / delayTime);
  vol.delay(delayTime / 9);

  vol.tone(_pitch, 127);
  vol.fadeOut(10 / delayTime);
  vol.delay(delayTime / 9);

  vol.tone(_pitch, 127);
  vol.fadeOut(10 / delayTime);
  vol.delay(delayTime / 9);

  vol.tone(_pitch, 127);
  vol.fadeOut(10 / delayTime);
  vol.delay(delayTime / 9);

  vol.tone(_pitch, 127);
  vol.fadeOut(10 / delayTime);
  vol.delay(delayTime / 9);

  vol.tone(_pitch, 255);
  vol.fadeOut(10 / delayTime);
  vol.delay(delayTime / 9);

  vol.tone(_pitch, 127);
  vol.fadeOut(10 / delayTime);
  vol.delay(delayTime / 9);

  vol.tone(_pitch, 127);
  vol.fadeOut(10 / delayTime);
  vol.delay(delayTime / 9);
  digitalWrite(_pin,LOW);

}

This is how a beat with a subdivision of nine is called. I understand that delay is being called multiple times but the I'd like that analogRead changes in delayTime and _pitch real time.

I looked at that tutorial and tried to implement what it said but I was unable to get it to work. I can get it to work in a processual way but I'm at a loss on how to do it while using a library.

Does this come close to what you want?

It uses a timer compare interrupt that interrupts at 1kHz. I moved your checks of pots A0 and A1 and the associated calls to methods speed and pitch etc there. There may be room for optimizations if you find the interrupts are not working well.

Give it a shot. (BTW, I did not try to compile this but it grew out of an LED blinky thing I had lying around so the bones should be good...)

#include "Beets_machine.h"
#include "Volume.h"

Volume vol;
Beets Beets;

void setup() 
{
    //setup a T0 compare interrupt that will happen each millisecond (or close to it...)
    OCR0A = 0xA0;
    TIMSK0 |= _BV( OCIE0A );
    Serial.begin(9600);
  
}//setup

void loop() 
{
    uint8_t sound;
    
    sound = Beets.SoundPot(A5);    
    Beets.beets(vol, sound,2);
    //
    sound = Beets.SoundPot(A4);
    Beets.beets(vol, sound,8);
    //
    sound = Beets.SoundPot(A3);
    Beets.beets(vol, sound,9);
    //
    sound = Beets.SoundPot(A2);
    Beets.beets(vol, sound,10);

}//loop


//Timer Compare interrupt handler
SIGNAL(TIMER0_COMPA_vect) 
{
    uint8_t 
        pitch,
        playSpeed;
    int
        inputSpeed,
        inputPitch;
        
    playSpeed = Beets.SpeedPot(A1);
    inputSpeed = map(playSpeed,0,255,200,1000);
    Beets.Speed(inputSpeed);

    pitch = Beets.PitchPot(A0);
    inputPitch = map(pitch,0,255,100,1000);
    Beets.Pitch(inputPitch);
      
}//timer compare int

Thanks for the reply and the sample code.

The problem is that timer0 is used by the millis() and delay() and all internal timekeeping in the Arduino libraries. Changing it’s time constant impacts these operations.

The notes are created by using the delay function. Example:

void Beets:: triplet(Volume &vol ) {
  digitalWrite(_pin,HIGH); 
  vol.tone(_pitch, 255);
  vol.fadeOut(10 / delayTime);
  vol.delay(delayTime / 3);

  vol.tone(_pitch, 127);
  vol.fadeOut(10 / delayTime);
  vol.delay(delayTime / 3);
 
  vol.tone(_pitch, 127);
  vol.fadeOut(10 / delayTime);
  vol.delay(delayTime / 3);
  digitalWrite(_pin,LOW);
 
}

I also can’t use timer2 because that is related to the tone function.

I’ve also tried the timer1 library but that seems to cause a meltdown,

#include <TimerOne.h>
#include "Beets_machine.h"
#include "Volume.h"

Volume vol;
Beets Beets;

void setup() {
Serial.begin(9600);
Timer1.initialize(500000);         // initialize timer1, and set a 1/2 second period
  //Timer1.pwm(9, 512);                // setup pwm on pin 9, 50% duty cycle
  Timer1.attachInterrupt(callback);  // attaches callback() as a timer overflow interrupt
}

void loop() {

    
  uint8_t sound = Beets.SoundPot(A5);
     
  Beets.beets(vol, sound,2);
  
  sound = Beets.SoundPot(A4);

  Beets.beets(vol, sound,8);

  sound = Beets.SoundPot(A3);
 
  Beets.beets(vol, sound,9);

  sound = Beets.SoundPot(A2);
  
  Beets.beets(vol, sound,10);
  
}

void callback()
{
    uint8_t 
        pitch,
        playSpeed;
    int
        inputSpeed,
        inputPitch;
        
    playSpeed = Beets.SpeedPot(A1);
    inputSpeed = map(playSpeed,0,255,200,1000);
    Serial.println(inputSpeed);
    Beets.Speed(inputSpeed);

    pitch = Beets.PitchPot(A0);
    inputPitch = map(pitch,0,255,100,1000);
    Beets.Pitch(inputPitch);
      
}

Joshua_M_K:
Thanks for the reply and the sample code.

The problem is that timer0 is used by the millis() and delay() and all internal timekeeping in the Arduino libraries. Changing it's time constant impacts these operations.

Crap, right. Well, I would consider re-writing the code so it doesn't occupy all of the machine resources through delay() ¯_(ツ)_/¯.

BTW, if you did that you wouldn't need any interrupt as the mainline would be executing all the time; you could do the updates there.

It may be worth remembering that each analogRead wastes around a hundred microseconds.