Speaker buzz when writing to LCD.

So I’ve got an SNES controller (basically a bunch of buttons and a pair of 4021 shit registers) hooked up to the Arduino, going out into a pair of 74HC595 shift registers, which output to both an 8ohm speaker via a 1kohm resistor and a standard 2x16 backlit LCD.

Everything works as it should, but the tone coming out of the speaker is very buzzy unless I comment out the code that writes to the LCD. I’ve tried putting a cap in after the resistor, but that didn’t help. I thought it was a power issue, but I’ve got the Arduino going on a 12v/1A power supply. There’s about a 0.25V across the speaker when the lcd.print code is active and 0.33 when it’s commented out.

Any ideas? The main loop code and an photo of the wiring are below.

void loop() {
       lcd.home();
     controllerRead();
      byte dpad = 0;
      byte dpad2 = 0;
      for (int j = 0; j < 8; j++) {
          dpad = dpad << 1;
          dpad = dpad + keypress[j];          
          dpad2 = dpad2 << 1;
          dpad2 = dpad2 + keypress[j+8];
      //    lcd.setCursor(j,0);
       //   lcd.print(keypress[j]);
        //  lcd.setCursor(j,1);
         // lcd.print(keypress[j+8]);          
     }

     digitalWrite(latchIC,LOW);
     shiftOut(dataIC, clockIC, MSBFIRST, dpad);
    if ((dpad != 255) || (dpad2 != 255)) { tone(12, dpad+dpad2, 5); }
     digitalWrite(latchIC,HIGH);

}

Click for Hi-Res

which output to both an 8ohm speaker via a 1kohm resistor and a standard 2x16 backlit LCD.

Why are you doing this? You are using the same wire for the speaker and the LCD? I would expect buzzing in that case.

Each button sends a different tone to the speaker, so it's sort of like a keyboard. The LCD displays the tone/button being pressed. The speaker has 1 pin of output, and the LCD has 3. They don't share any wiring.

Can you post the whole sketch? This is just guesswork about what pins do what. And state what LCD library you are using please.

Using NewLiquidCrystal

#include <FastIO.h>
#include <I2CIO.h>
#include <LCD.h>
#include <LiquidCrystal_SR3W.h>
#include <Wire.h>



int latchGREEN = 4; // set the latch pin
int clock = 5; // set the clock pin
int datin = 6;// set the data in pin
int controller_data = 0;
int keypress[16];
int latchIC = 8;
int clockIC = 9;
int dataIC = 7;
LiquidCrystal_SR lcd(2,13,3);





/* SETUP */
void setup() {
  Serial.begin(57600);
  pinMode(latchGREEN,OUTPUT);
  pinMode(clock,OUTPUT);
  pinMode(datin,INPUT);
  pinMode(latchIC,OUTPUT);
  pinMode(clockIC,OUTPUT);
  pinMode(dataIC,OUTPUT);
  pinMode(OE,OUTPUT);
  pinMode(MR,OUTPUT);
  digitalWrite(latchGREEN,HIGH);
  digitalWrite(clock,HIGH);
  digitalWrite(MR, LOW);
  digitalWrite(MR, HIGH);
  digitalWrite(latchIC,LOW);
  digitalWrite(clockIC,LOW);
  digitalWrite(dataIC,LOW);  
  lcd.begin(16,2);
  lcd.home();

}



/* CONTROLLER READ */
void controllerRead() {
  controller_data = 0;
  digitalWrite(latchGREEN,LOW);
  digitalWrite(clock,LOW);
  digitalWrite(latchGREEN,HIGH);
  delayMicroseconds(2);
  digitalWrite(latchGREEN,LOW);


  controller_data = digitalRead(datin);

  for (int i = 0; i < 16; i++) {
    keypress[i] = digitalRead(datin);
    digitalWrite(clock,HIGH);
    controller_data = controller_data << 1;
    controller_data = controller_data + digitalRead(datin);
    delayMicroseconds(4);
    digitalWrite(clock,LOW);
  }  
  
}

/* PROGRAM */
void loop() {
       lcd.home();
     controllerRead();
      byte dpad = 0;
      byte dpad2 = 0;
      for (int j = 0; j < 8; j++) {
          dpad = dpad << 1;
          dpad = dpad + keypress[j];          
          dpad2 = dpad2 << 1;
          dpad2 = dpad2 + keypress[j+8];
      //    lcd.setCursor(j,0);
       //   lcd.print(keypress[j]);
        //  lcd.setCursor(j,1);
         // lcd.print(keypress[j+8]);          
     }

     digitalWrite(latchIC,LOW);
     shiftOut(dataIC, clockIC, MSBFIRST, dpad);
    if ((dpad != 255) || (dpad2 != 255)) { tone(12, dpad+dpad2, 5); }
     digitalWrite(latchIC,HIGH);

}

Well a buzz is alternating current so, as the data is constantly being shifted all the binary data(or rapidly alternating current) gets passed the speaker on its way out, when its a pure tone the speaker gets an exact frequency, the lcd data isn't so exact and causes the sounds you hear, your actually hearing the arduino "talk" to the lcd id suggest dedicate the pin to the speaker or find another way to drive it, perhaps a 555 timer circuit using a transistor as a variable resistor, base being fed thru an rc filter with pwm or just toggle a pin on the arduino solely for the speaker(difference being 555 can provide 200ma instead of 30)

The speaker has its own pin. I'll give the 555 idea a shot.

even if it has its own pin, if its on the shift register you will get noise

... They don't share any wiring.

But they do share the Arduino.

You are using five different libraries, probably written by five different people, each one relatively unconcerned about what anyone else might be doing with the processor resources. It's amazing that it works as well as it does.

Don

griphus: Everything works as it should, but the tone coming out of the speaker is very buzzy unless I comment out the code that writes to the LCD.

That library does this to write to the LCD:

void LiquidCrystal_SR3W::loadSR(uint8_t value) 
{
   // Load the shift register with information
   fio_shiftOut(_data_reg, _data, _clk_reg, _clk, value, MSBFIRST);
   
   // Strobe the data into the latch
   ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
   {
      fio_digitalWrite_HIGH(_strobe_reg, _strobe);
      fio_digitalWrite_SWITCHTO(_strobe_reg, _strobe, LOW);
   }
}

ATOMIC_BLOCK disables interrupts. The tone library uses interrupts. Hence tones stop when you are writing to the LCD.

Oh, that makes sense. Thank you!

Would you know if there is either a tone-generating library that doesn't use interrupts or an shift register-based LCD library that doesn't disable them? I'm afraid I don't actually know enough about how either library works to tell if either of those qualities are inherent to the output. Or if there's a way to correct for the interrupts in hardware?

I don’t particularly see why that code needs interrupts disabled. You could try turning this line into a comment and see what happens:

   ATOMIC_BLOCK(ATOMIC_RESTORESTATE)

You could generate tones with pure PWM manipulation of the timers which would not involve interrupts. Not sure there is a library to do that.