Tone() function messing with LED lights

Hello. I am using an Arduino mega for my project.
I am using analogWrite to write to 6 pins for 2 RGB LEDs. The LEDs should be in sync. However, when I play a tune with the passive speaker, the LEDs are not lit correctly.

So, it appears that there is some subtle interaction between the two?
My sound pin is 4 and I am using 7-12 digital pins for the LEDs.

This reproduces the problem.
bool sound=true; // set this to be false to see the colors are set 100% correctly.
It seems that one of the digital outputs is lagged until the tone is done playing.


typedef enum : char {FORMATION='F', SET='S', REDFLAG = 'R', YELLOWFLAG = 'Y', GREENFLAG = 'G', CHECKERS = 'C' } RaceFlag;


RaceFlag raceFlag=FORMATION;



#define LANENUM 2


// Define an enum to represent different colors
typedef enum  {
  RED,
  GREEN,
  BLUE,
  YELLOW,
  ORANGE,
  PURPLE,
  CYAN,
  WHITE,
  BLACK,
  NUM_COLORS // Keeps track of the number of colors
} Color;


// Define a struct to hold RGB values
struct RGB {
  uint8_t red;
  uint8_t green;
  uint8_t blue;
};



// Array of short 3-letter labels for each color 
const char* colorLabels[NUM_COLORS] = { "RED", "GRN", "BLU", "YLW", "ORG", "PUR", "CYN", "WHT", "BLK" };

// Adjust these values to balance the colors
const uint8_t maxRed = 230;  // Full intensity for red
const uint8_t maxGreen = 60; // Reduced intensity for green to balance brightness
const uint8_t maxBlue = 240;  // Slightly reduced intensity for blue


// Create an array of RGB structs to hold custom color values
const RGB colorTable[NUM_COLORS] = {
  {maxRed, 0, 0},             // RED
  {0, maxGreen, 0},           // GREEN
  {0, 0, maxBlue},            // BLUE
  {maxRed, maxGreen*(int)3/4, 0},      // YELLOW
  {maxRed, maxGreen * (int)1 / 5, 0}, // ORANGE
  {maxRed / 2, 0, maxBlue / 2}, // PURPLE
  {0, maxGreen, maxBlue},     // CYAN
  {maxRed, maxGreen, maxBlue},// WHITE
  {0, 0, 0}                   // BLACK
};

// Static brightness value ranging from 0 to 8
#define MAXBRIGHTNESS 8
static int brightness = 3; // Default to maximum brightness

class Lights {
  public:

  byte redPin,bluePin,greenPin;




  void setup(byte r,byte g,byte b){
    redPin=r;
    greenPin=g;
    bluePin=b;
    // Initialize the RGB LED pins as outputs
    pinMode(redPin, OUTPUT);
    pinMode(greenPin, OUTPUT);
    pinMode(bluePin, OUTPUT);
  }






  void demo() {
    for(int c=0;c<NUM_COLORS;c++){
      Serial.println(colorLabels[c]);
      setColor(colorTable[c]);
      delay(2000);
    }
  }

  void setColor(RGB rgb){
    analogWrite(redPin, rgb.red * brightness / MAXBRIGHTNESS);
    analogWrite(greenPin, rgb.green * brightness / MAXBRIGHTNESS);
    analogWrite(bluePin, rgb.blue * brightness / MAXBRIGHTNESS);
  }
  
  // Function to set the color of the RGB LED with brightness adjustment
  void setColor(Color color) {
    RGB rgb = colorTable[color];
    setColor(rgb);  
  }


  
};


Lights lights[LANENUM];


void setColor(Color c){
  for(int i=0;i<LANENUM;i++){
     lights[i].setColor(c);
  }  
}

void waveFlag(RaceFlag which){
  switch(which){
    case FORMATION:
      setColor(BLACK);
    break;
    case SET:
      setColor(WHITE);
    break;
    case REDFLAG:      
      setColor(RED);
    break;
    case YELLOWFLAG:
      setColor(YELLOW);
    break;
    case GREENFLAG:
      setColor(GREEN);
    break;
    case CHECKERS:
      setColor(PURPLE);
    break;
  }
}


const int speakerPin = 4; // Pin connected to the speaker

bool sound=true; //change to false to notice colors are perfect

void myTone(int pin,unsigned int frequency,unsigned long duration){
   if(sound) tone(pin,frequency,duration);
}

void playTone(int frequency, int duration) {
  myTone(speakerPin, frequency, duration);
  delay(duration);
  noTone(speakerPin);
}

void playF1StartSound1() {
  // Tone sequence for the starting lights
  waveFlag(FORMATION);
  waveFlag(SET);  
  playTone(500, 300);   
  delay(1300);
  waveFlag(REDFLAG);
  playTone(500, 300);   
  delay(1300);
  waveFlag(YELLOWFLAG);
  playTone(500, 300);   
  delay(1300);  
  playTone(1000, 500);  
  delay(1100);
  waveFlag(GREENFLAG);  
}



void setup() {
  pinMode(speakerPin, OUTPUT);
  noTone(speakerPin);
  lights[0].setup(7,8,9);   
  lights[1].setup(10,11,12); 
  playF1StartSound1(); 

}

void loop() {
  // put your main code here, to run repeatedly:

}

Reading this Use of the tone() function interferes with PWM output on pin 9 on Mega 2560 - #5 by DrAzzy

There appears to be a fight between the LEDs PWM and the tone timer:

"Use of the tone() function will interfere with PWM output on pins 3 and 11"

I am using a Mega board that was supposed to be immune but it doesn't seem like it.

I will try to not use 3 or 11 pins.

1 Like

Your myTone() function plays a tome for a given duration. Next you delay for the same duration and switch the tone off (which was already off). Is that the intention?

tone() is non blocking but I need it to be blocking, hence the delay.

Apologies, I forgot about that.

You can use

  tone(4, 500);
  delay(duration);
  noTone(4);

Not sure if it will solve your problem.

1 Like

From what i recall, the tone() function uses timer1, but i am not correct there. It depends a bit on the MCU.
From what i can tell the mega uses timer2

from this reference the Mega also uses it for PWM on pin 10 & 9.
Anyway, experiment a little. Basically the tone() function will set the PWM duty cycle to 50% and just mess with the frequency.

edit: Just realizing that although the normal configuration allows for playing just 1 tone at a time, it isn't all that hard to use all of the timers to generate tones. Using timers for tones is so inaccurate though due to the dependency on clock division, that i will not consider making some instrument like that.

1 Like

THANK YOU!!! :blush:

Indeed, those pins were giving me problems, so I now avoid them.

I recognize that code! : )

I've never seen that color fade code, thanks for the reference. :slight_smile:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.