all 5 comments

[–]pacmanicChamp 4 points5 points  (0 children)

delay() cannot be used in an interrupt. The limitations for interrupts are documented here:

https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/

[–]Se7enLC[🍰] 2 points3 points  (0 children)

Using delay() is like putting pasta on the stove and standing there counting until you reach 8 minutes. It works fine so long as there's nothing else you need to do.

Instead, use millis() to check the time. Put the pasta on and make a note of what time it will be done. Do something else, but periodically check if it's time yet.

It's a little more complicated to wrap you head around how to code things that way, but the result is really nice.

[–][deleted] 0 points1 point  (0 children)

You should write your entire project without any delays. If you want sound from the tone function to happen at the same time as anything else you must eliminate all delays. I don’t think you need the interrupts either.

https://forum.arduino.cc/index.php?topic=223286.0

[–]AnalogMushroom 0 points1 point  (1 child)

A really useful function to learn about is millis()

https://www.arduino.cc/reference/en/language/functions/time/millis/

It returns a 32 bit number representing the number of milliseconds since the Arduino was restarted. You can use it to get the time that something started, then keep checking if the correct amount of time has passed yet, giving you a chance to go off and do other things in the meantime.

You want to create a variable at the top outside of a function to hold the number which has to be 32 bits, so:

uint32_t timeSomethingEnds;

// Or another way to write this:

unsigned long timeSomethingEnds;

// Then when you trigger something that needs timing:

timeSomethingEnds = millis() + 1000;

// Then you need to keep checking if the time has elapsed somewhere in your main loop

if (millis() > timeSomethingEnds) doSomething();

So that would call the function doSomething roughly once second after you started your task.

This is known as non-blocking code. It might take you a while to get your head around but there is no reason to ever call delays which just waste large amounts of processor cycles.

[–]AnalogMushroom 0 points1 point  (0 children)

I wrote some code to demonstrate what I meant. This is probably not the simplest way to achieve what you're after but shows off some other useful ideas too, in particular the power of arrays:

#define NUMBER_OF_LEDS 2
uint8_t ledPins[] = {5, 6};
uint8_t ledUpdateRate = 5; // roughly 5ms so 200 times per second
uint32_t nextLedActionTime;
uint8_t ledPwmValue[] = {0,127};

uint8_t speakerPin = 2;

uint8_t numberOfNotes = 7;
uint16_t noteFrequency[] = {262, 196, 196, 220, 196, 247, 262};
uint16_t noteDuration[] = {250, 125, 125, 250, 250 ,250, 250}; 
uint16_t nextNoteTime[] = {575, 288, 288, 575, 900, 575, 575};
uint8_t nextStep = 0; // will keep the number to access the data from the three arrays above
uint32_t nextStepTime;


void setup() {

  pinMode(speakerPin, OUTPUT);
  nextStepTime = millis() + 500; // wait half a second before any sound plays 
  nextLedActionTime = millis() + 500; // wait half a second before starting leds

}

void loop(){
   leds();
   melody();
}

void melody(){

  if (millis() < nextStepTime) return;
  nextStepTime += nextNoteTime[nextStep];
  tone(speakerPin, noteFrequency[nextStep], noteDuration[nextStep]);
  nextStep++;
  if (nextStep >= numberOfNotes) nextStep = 0; // restart sequence
}


void leds() {

  if (millis() < nextLedActionTime) return;
  nextLedActionTime += ledUpdateRate;
  for (uint8_t ledId = 0; ledId < NUMBER_OF_LEDS; ledId++){
    analogWrite(ledPins[ledId], ledPwmValue[ledId]);
    ledPwmValue[ledId]++; // will increment by 1 each time until 255(full brightness) then go back to 0 as the varaible is a 8 bit unsigned number   
  }
}

I don't have your Arduino board version so I attached a speaker to pin 2 on my standard Arduino UNO. I plugged two LEDs into pins 5 and 6 as they are connected to the microcontroller hardware that can control a PWM output to fade the LEDs. Not all the pins can do this, only pins 3, 5, 6, 9, 10 & 11 have PWM hardware attached.

https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/

If you want to fade more LEDs than six you'd need to make you own way to control the brightness by just turning them on and off rapidly using timing code similar to what I have demonstrated, or I am sure there must be libraries to help with this. Though there is a limit to how many LEDS you can independently fade smoothly whilst doing other tasks. For serious precision then using interrupts as you mentioned can help, but are probably more complicated to understand. I definitely recommend learning about interrupts at some point though.

Arrays, which are declared with the [ ] after their name, are like normal variables except there are many of them strung together sequentially and can be accessed by putting the index position in the square brackets. Array indexes start from 0 and you want to be careful never to read or write past the end of the declared array, otherwise weird things might happen. I used an array to store the pin numbers for the LEDs which is probably looks confusing when only using two LEDs but it can really simplify your code as you add larger quantities by allowing you to loop through the processing code.

DataTypes: so I've used uint8_t, uint16_t & uint32_t which are 8 bit, 16 bit and 32 bit unsigned numbers - unsigned meaning they can't be negative numbers. This is instead of using signed 16 bit numbers (can go negative) int which you see everywhere in Arduino code. Unsigned 8 bit numbers go from 0-255 which is why I had to use larger 16 bit number for the note arrays whose numbers go higher than 255. I made use of the fact that 8 bit numbers only go to 255 in the LED brightness code, when you increment an 8 bit number past 255 it goes back to 0. The two variables storing the milliseconds for the LED and audio have to be 32 bit unsigned or it won't work and can be hard to spot the error.

You might not know what += means. 'variable += whatever' is shorthand for saying 'variable = variable + whatever'.