Playing a Tone stops IR receiver from decoding

Hi all,

Working on a robot project with my kids. We can make it do all the things we want, except... after it plays a tone, the IR receiver no longer recognizes the signal.

arduino nano board (but the same problem occurs with the uno)

we tried building the code again starting with the tone and then adding the IR receiver content and it still happens. Here is the simplified (re-built) code:

#include "Notes.h" 
#include "PinDefinitionsAndMore.h"
#include <IRremote.hpp>


const int speakerPin = 13;

const int flagpole[] = {27,                                               // Array for Flag pole sound effect & song
  NOTE_G2, 10, NOTE_C3, 10, NOTE_E3, 10, NOTE_G3, 10, NOTE_C4, 10, NOTE_E4, 10, NOTE_G4, 3, NOTE_E4, 3, NOTE_GS2, 10, NOTE_C3, 10, 
  NOTE_DS3, 10, NOTE_GS3, 10, NOTE_C4, 10, NOTE_DS4, 10, NOTE_GS4, 3, NOTE_DS4, 3, NOTE_AS2, 10, NOTE_D3, 10, NOTE_F3, 10, 
  NOTE_AS3, 10, NOTE_D4, 10, NOTE_F4, 10, NOTE_AS4, 3, NOTE_AS4, 10, NOTE_AS4, 10, NOTE_AS4, 10, NOTE_C5, 2};


void setup() {
  Serial.begin(115200);

  Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE));

    // Start the receiver and if not 3. parameter specified, take LED_BUILTIN pin from the internal boards definition as default feedback LED
    IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);

    Serial.print(F("Ready to receive IR signals of protocols: "));
    printActiveIRProtocols(&Serial);
    Serial.println(F("at pin " STR(IR_RECEIVE_PIN)));
}

void loop() {

    if (IrReceiver.decode()) {

        /*
         * Print a summary of received data
         */
        if (IrReceiver.decodedIRData.protocol == UNKNOWN) {
            Serial.println(F("Received noise or an unknown (or not yet enabled) protocol"));
            // We have an unknown protocol here, print extended info
            IrReceiver.printIRResultRawFormatted(&Serial, true);
            IrReceiver.resume(); // Do it here, to preserve raw data for printing with printIRResultRawFormatted()
        } else {
            IrReceiver.resume(); // Early enable receiving of the next IR frame
            IrReceiver.printIRResultShort(&Serial);
            IrReceiver.printIRSendUsage(&Serial);
        }
        Serial.println();

        /*
         * Finally, check the received data and perform actions according to the received command
         */
        if (IrReceiver.decodedIRData.command == 0x86) {
              FlagSong();
              delay(500); // do something
        } else if (IrReceiver.decodedIRData.command == 0x85) {
              Stop();// do something else
        }
    }
}

void FlagSong(){
          Serial.println("Begin playing Flag pole sound effect & song");                        // Print begin of melody
            for (int thisNote = 1; thisNote < (flagpole[0] * 2 + 1); thisNote = thisNote + 2) { // Run through the notes one at a time
              tone(speakerPin, flagpole[thisNote], (1000/flagpole[thisNote + 1]));              // Play the single note
              delay((1000/flagpole[thisNote + 1]) * 1.30);                                      // Delay for the specified time
              noTone(speakerPin);                                                               // Silence the note that was playing
            }
          Serial.println("Flag pole sound effect & song complete");                             // Print that the song is complete
}

void Stop() {
          Serial.println("stop");
          delay(500);
}

And here is a sample of the Serial Monitor:


Protocol=NEC2 Address=0x5583 Command=0x85 Repeat gap=40400us Raw-Data=0x7A855583 32 bits LSB first
!Use the NEC2 protocol for sending!

stop
Protocol=NEC Address=0x5583 Command=0x86 Raw-Data=0x79865583 32 bits LSB first
Send with: IrSender.sendNEC(0x5583, 0x86, );

Begin playing Flag pole sound effect & song
Flag pole sound effect & song complete
Protocol=RC5 Address=0x0 Command=0x40 Raw-Data=0x0 0 bits MSB first
Send with: IrSender.sendRC5(0x0, 0x40, );

Received noise or an unknown (or not yet enabled) protocol
rawData[56]:
-384000

  • 400,- 350
  • 50,- 50 + 100,- 50 + 50,- 200 + 50,- 50
  • 100,- 50 + 50,- 200 + 50,- 50 + 100,- 50
  • 50,- 300 + 100,- 50 + 50,- 300 + 50,- 50
  • 50,- 50 + 50,-2150 + 450,- 200 + 50,- 200
  • 50,- 50 + 200,- 50 + 50,- 250 + 100,- 100
  • 50,- 300 + 50,- 50 + 100,- 300 + 50,- 50
  • 100,- 300 + 50,- 50 + 100
    Sum: 8550

Every time it executes the FlagSong function, it can no longer interpret the IR signal.

We've tried using different pins, and using different buttons on the IR controller to call the functions.

I'm thinking it might be something about the "for()" loop of the tone, but I'm not sure what or how to break out of it.

The longer code works for IR signals to drive an H-Bridge, and a stepper motor, but the tone seems to break it!

Thanks for any advice!

Notes.h (1.9 KB)
PinDefinitionsAndMore.h (15.2 KB)

See GitHub - Arduino-IRremote/Arduino-IRremote: Infrared remote library for Arduino: send and receive infrared signals with multiple protocols

Receiving does not run if analogWrite() or tone() is used.

The receiver sample interval of 50 µs is generated by a timer. On many boards this must be a hardware timer. On some boards where a software timer is available, the software timer is used.
Be aware that the hardware timer used for receiving should not be used for analogWrite().
On the Uno and other AVR boards the receiver timer ist the same as the tone timer, so receiving will stop after a tone() command. See ReceiveDemo example how to deal with it.

1 Like

You likely have a timer usage conflict.

Thanks @J-M-L and @jremington

The timer issue seems to make sense. I'll read up on it and adjust the code, and reply again to let you all know.

Thanks again!

@jremington and @J-M-L

That was it! Thank you all, "Buzz" is great now!

Great! Please post the revised code (using code tags), in case other people have the same problem.

@jremington Thanks for the direction.

The important part of the code for the timer issue is to start and end the tone function with

IrReceiver.stopTimer();
//Tone Code Here
IrReceiver.restartTimer(8000);

So for my function:

  void FlagSong(){
          IrReceiver.stopTimer(); // ESP32 uses another timer for tone(), maybe other platforms (not tested yet) too.
            for (int thisNote = 1; thisNote < (flagpole[0] * 2 + 1); thisNote = thisNote + 2) { // Run through the notes one at a time
            tone(speakerPin, flagpole[thisNote], (1000/flagpole[thisNote + 1]));// Play the single note
            delay((1000/flagpole[thisNote + 1]) * 1.30);                        // Delay for the specified time
            noTone(speakerPin);                                                 // Silence the note that was playing
            } 
            IrReceiver.restartTimer(8000); // Restart IR timer. 8000 to compensate for 8 ms stop of receiver. This enables a correct gap measurement.
            Serial.println("Done");

The whole code is below:

#include <Arduino.h> //This include defines the actual pin number for pins like IR_RECEIVE_PIN, IR_SEND_PIN for many different boards and architectures
#include "PinDefinitionsAndMore.h" //This is edited so Pin 12 is IR receive pin
#include <IRremote.hpp> // include the library
#include "Notes.h"
#include <Stepper.h>
// -------------- Constant Integers -------------------
  const int stepsPerRevolution = 985; //Change this to match the stepper
  const int motor1pin1 = 10;          //Pins to control L298N H-Bridge to drive the wheel motors
  const int motor1pin2 = 9;
  const int motor2pin1 = 8;
  const int motor2pin2 = 7;
  /* Arduino cannot analogWrite while reading IR code
  *const int motor1SC = 11; //Speed Controllers for the L298N H-Bridge
  *const int motor2SC = 6; 
  */
  const int flagpole[] = {27,                                               // AVMute Button -- Array for Flag pole sound effect & song
  NOTE_G2, 10, NOTE_C3, 10, NOTE_E3, 10, NOTE_G3, 10, NOTE_C4, 10, NOTE_E4, 10, NOTE_G4, 3, NOTE_E4, 3, NOTE_GS2, 10, NOTE_C3, 10, 
  NOTE_DS3, 10, NOTE_GS3, 10, NOTE_C4, 10, NOTE_DS4, 10, NOTE_GS4, 3, NOTE_DS4, 3, NOTE_AS2, 10, NOTE_D3, 10, NOTE_F3, 10, 
  NOTE_AS3, 10, NOTE_D4, 10, NOTE_F4, 10, NOTE_AS4, 3, NOTE_AS4, 10, NOTE_AS4, 10, NOTE_AS4, 10, NOTE_C5, 2};

  const int death[] = {17,                                                  // Array for Death sound effect & song
  NOTE_C4, 32, NOTE_CS4, 32, NOTE_D4, 16, NOTE_H, 4, NOTE_H, 2, NOTE_B3, 8, NOTE_F4, 8, NOTE_H, 8, NOTE_F4, 8, NOTE_F4, 6, 
  NOTE_E4, 6, NOTE_D4, 6, NOTE_C4, 8, NOTE_E3, 8, NOTE_H, 8, NOTE_E3, 8, NOTE_C3, 8};

  const int gameover[] = {15,                                               // Help Button -- Array for Game over song
  NOTE_C4, 8, NOTE_H, 8, NOTE_H, 8, NOTE_G3, 8, NOTE_H, 4, NOTE_E3, 4, NOTE_A3, 6, NOTE_B3, 6, NOTE_A3, 6, NOTE_GS3, 6, NOTE_AS3, 6, 
  NOTE_GS3, 6, NOTE_G3, 8, NOTE_F3, 8, NOTE_G3, 4};

  const int BDay[] = {25,                                                   // Freeze Button -- Array for Happy Birthday song
  NOTE_C4,8, NOTE_C4,8, NOTE_D4, 4, NOTE_C4, 4, NOTE_F4, 4, NOTE_E4, 2, 
  NOTE_C4,8, NOTE_C4, 8, NOTE_D4, 4, NOTE_C4, 4, NOTE_G4, 4, NOTE_F4, 2, 
  NOTE_C4,8, NOTE_C4,8, NOTE_C5, 4, NOTE_A4, 4, NOTE_F4, 4, NOTE_E4, 4, NOTE_D4, 2, 
  NOTE_AS4, 8, NOTE_AS4, 8, NOTE_A4, 4, NOTE_F4, 4, NOTE_G4, 4, NOTE_F4, 3}; 

// -------------- Variable Integers -------------------
  int sensorvalue = 0;                // Used to describe state changes for Motor Control
  int speed1 = 255;                   // Used to control Motor Speeds independently
  int speed2 = 255;
  int speakerPin = 11;                // Used to send frequency and tone signal to peizo speaker
// -------------- Variable Strings --------------------
  String Forwardnote = "Forward";
  String Reversenote = "Beeeep, Beeeep";
  String Rightnote = "Right Turn";
  String Leftnote = "Left Turn";
  String Stopnote = "Stop";
  String Raisenote = "Raising";
  String Dropnote = "Lowering";
// -------------- Library Assignments -----------------
  Stepper myStepper(stepsPerRevolution, 2, 3, 4, 5);
// -------------- Functions ---------------------------
  void Forward(){           
              digitalWrite(motor1pin1, HIGH);
              digitalWrite(motor1pin2, LOW);

              digitalWrite(motor2pin1, HIGH);
              digitalWrite(motor2pin2, LOW);
  } 
  void Stop(){
              digitalWrite(motor1pin1, LOW);
              digitalWrite(motor1pin2, LOW);

              digitalWrite(motor2pin1, LOW);
              digitalWrite(motor2pin2, LOW);

              digitalWrite(2, LOW);
              digitalWrite(3, LOW);
              digitalWrite(4, LOW);
              digitalWrite(5, LOW);
  }
  void Reverse(){
              digitalWrite(motor1pin1, LOW);
              digitalWrite(motor1pin2, HIGH);

              digitalWrite(motor2pin1, LOW);
              digitalWrite(motor2pin2, HIGH);
  }
  void Right(){
            digitalWrite(motor1pin1, HIGH);
            digitalWrite(motor1pin2, LOW);

            digitalWrite(motor2pin1, LOW);
            digitalWrite(motor2pin2, LOW);
  }
  void Left(){
            digitalWrite(motor1pin1, LOW);
            digitalWrite(motor1pin2, LOW);

            digitalWrite(motor2pin1, HIGH);
            digitalWrite(motor2pin2, LOW);  
  }
  void Raise(){
            Serial.println("Raising");
            myStepper.step(stepsPerRevolution);
            delay(500);
            Stop();
  }
  void Lower(){
            Serial.println("Lowering");
            myStepper.step(-stepsPerRevolution);
            delay(500);
            Stop();
  }
  void FlagSong(){
          IrReceiver.stopTimer(); // ESP32 uses another timer for tone(), maybe other platforms (not tested yet) too.
            for (int thisNote = 1; thisNote < (flagpole[0] * 2 + 1); thisNote = thisNote + 2) { // Run through the notes one at a time
            tone(speakerPin, flagpole[thisNote], (1000/flagpole[thisNote + 1]));// Play the single note
            delay((1000/flagpole[thisNote + 1]) * 1.30);                        // Delay for the specified time
            noTone(speakerPin);                                                 // Silence the note that was playing
            } 
            IrReceiver.restartTimer(8000); // Restart IR timer. 8000 to compensate for 8 ms stop of receiver. This enables a correct gap measurement.
            Serial.println("Done");

  }
  void deathsong(){
          IrReceiver.stopTimer(); // ESP32 uses another timer for tone(), maybe other platforms (not tested yet) too.
            for (int thisNote = 1; thisNote < (death[0] * 2 + 1); thisNote = thisNote + 2) { // Run through the notes one at a time
            tone(speakerPin, death[thisNote], (1000/death[thisNote + 1]));// Play the single note
            delay((1000/death[thisNote + 1]) * 1.30);                        // Delay for the specified time
            noTone(speakerPin);                                                 // Silence the note that was playing
            } 
          IrReceiver.restartTimer(8000); // Restart IR timer. 8000 to compensate for 8 ms stop of receiver. This enables a correct gap measurement.
          Serial.println("Done");
  }
  void gameoversong(){
          IrReceiver.stopTimer(); // ESP32 uses another timer for tone(), maybe other platforms (not tested yet) too.
            for (int thisNote = 1; thisNote < (gameover[0] * 2 + 1); thisNote = thisNote + 2) { // Run through the notes one at a time
            tone(speakerPin, gameover[thisNote], (1000/gameover[thisNote + 1]));// Play the single note
            delay((1000/gameover[thisNote + 1]) * 1.30);                        // Delay for the specified time
            noTone(speakerPin);                                                 // Silence the note that was playing
            } 
            IrReceiver.restartTimer(8000); // Restart IR timer. 8000 to compensate for 8 ms stop of receiver. This enables a correct gap measurement.
            Serial.println("Done");
  }
  void BDaysong(){
          IrReceiver.stopTimer(); // ESP32 uses another timer for tone(), maybe other platforms (not tested yet) too.
            for (int thisNote = 1; thisNote < (BDay[0] * 2 + 1); thisNote = thisNote + 2) { // Run through the notes one at a time
            tone(speakerPin, BDay[thisNote], (1000/BDay[thisNote + 1]));// Play the single note
            delay((1000/BDay[thisNote + 1]) * 1.30);                        // Delay for the specified time
            noTone(speakerPin);                                                 // Silence the note that was playing
            } 
            IrReceiver.restartTimer(8000); // Restart IR timer. 8000 to compensate for 8 ms stop of receiver. This enables a correct gap measurement.
            Serial.println("Done");
  }

void setup() {

  pinMode(motor1pin1, OUTPUT);
  pinMode(motor1pin2, OUTPUT);
  pinMode(motor2pin1, OUTPUT);
  pinMode(motor2pin2, OUTPUT);

  //pinMode(motor1SC, OUTPUT);
  //pinMode(motor2SC, OUTPUT);

  pinMode(speakerPin, OUTPUT);
  //analogWrite(motor1SC, speed1);
  //analogWrite(motor2SC, speed2);

  myStepper.setSpeed(10);
  //Stepper motor pinouts initialized as output in Stepper.h
  //IR recieve pin initialized as input in IRremote.hpp

    Serial.begin(115200);
    // Just to know which program is running on my Arduino
    Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE));

    // Start the receiver and if not 3. parameter specified, take LED_BUILTIN pin from the internal boards definition as default feedback LED
    IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);

    Serial.print(F("Ready to receive IR signals of protocols: "));
    printActiveIRProtocols(&Serial);
    Serial.println(F("at pin " STR(IR_RECEIVE_PIN)));
  
}

void loop() {
    /*
     * Check if received data is available and if yes, try to decode it.
     * Decoded result is in the IrReceiver.decodedIRData structure.
     *
     * E.g. command is in IrReceiver.decodedIRData.command
     * address is in command is in IrReceiver.decodedIRData.address
     * and up to 32 bit raw data in IrReceiver.decodedIRData.decodedRawData
     */
    if (IrReceiver.decode()) {

        /*
         * Print a summary of received data
         */
        if (IrReceiver.decodedIRData.protocol == UNKNOWN) {
            Serial.println(F("Received noise or an unknown (or not yet enabled) protocol"));
            // We have an unknown protocol here, print extended info
            IrReceiver.printIRResultRawFormatted(&Serial, true);
            IrReceiver.resume(); // Do it here, to preserve raw data for printing with printIRResultRawFormatted()

        } else {
            IrReceiver.resume(); // Early enable receiving of the next IR frame
            IrReceiver.printIRResultShort(&Serial);
            IrReceiver.printIRSendUsage(&Serial);
        }
        Serial.println();
        /*
         * Finally, check the received data and perform actions according to the received command
         */
        if (IrReceiver.decodedIRData.command == 0xB0) {
          Serial.println(Forwardnote);
          sensorvalue = 1;// do something

        } else if (IrReceiver.decodedIRData.command == 0xB2) {
          Serial.println(Reversenote);
          sensorvalue = 2;// do something

        } else if (IrReceiver.decodedIRData.command == 0xB1) {         
          Serial.println(Rightnote);
          sensorvalue = 3;

        } else if (IrReceiver.decodedIRData.command == 0xB3) {          
          Serial.println(Leftnote);
          sensorvalue = 4;

        } else if (IrReceiver.decodedIRData.command == 0x85) {
          Serial.println(Stopnote);
          sensorvalue = 0;

        } else if (IrReceiver.decodedIRData.command == 0x86) {
          Serial.println(Raisenote);
          Raise();
          FlagSong();

        } else if (IrReceiver.decodedIRData.command == 0x87) {
          Serial.println(Dropnote);
          Lower();

        } else if (IrReceiver.decodedIRData.command == 0x93) {
          Serial.println("Flagsong");
          FlagSong();
        
        } else if (IrReceiver.decodedIRData.command == 0x95) {
          Serial.println("gameover");
          gameoversong();

        } else if (IrReceiver.decodedIRData.command == 0x92) {
          Serial.println("Happy Birthday");
          BDaysong();

        //} else if (IrReceiver.decodedIRData.command == 0X98) {
          // Serial.println("themesong");
          // themesong();

        }
          //else if (IrReceiver.decodedIRData.command == 0x98) {
          //for (int j = 0; speed1 <= 205; speed1 = j+50);
          //Serial.print("motor 1 faster: ");
          //Serial.println(speed1);
        //} //else if (IrReceiver.decodedIRData.command == 0x99) {
          //for (int j = 0; speed1 >= 50; speed1 = j=50);
          //Serial.print("motor 1 slower: ");
          //Serial.println(speed1);
        //}
    
                
      if (sensorvalue == 0) {
        Stop ();
    
      } else if (sensorvalue == 1) {
        Forward ();
    
      } else if (sensorvalue == 2) {
        Reverse ();
    
      } else if (sensorvalue == 3) {
        Right ();
    
      } else if (sensorvalue == 4) {
        Left ();
        
      }
    }
} //void loop close

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