Audiometric Circuit using Arduino

I want to make a simple circuit to measure a person's hearing. I used 8x8 LED matrix that is driven by MAX7219 module in order to generate the waveform. I used OLED to display the tested frequencies and volumes. The encoder controls the OLED, the matrix and volume.
So the rows on matrix represent the volumes used while the column are the frequencies. So when the encoder is turned , different LEDs in a column light up depending on the number of turns while if the switch of the encoder is pressed, then next column LEDs light up depending on the rotation of encoder.
The code segments for the OLED, matrix and encoder work well and I have tested this code with hardware and it works as desired. However when I add the code for the speaker , the matrix starts to light up randomly.

The code compiles however I'm unable to the mistake in the code, can someone please guide me?

Here is the code:

[code]
#include <Encoder.h>
#include <U8glib.h>
#include <Volume.h>

U8GLIB_SSD1306_128X32 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0);


// Delays for certain events in ms
const int ROTARY_DELAY = 10;    // Time between checking for rotary turns
const int BUTTON_DELAY = 800;    // Button debouncing, and repeating
const int FLASH_DELAY = 600;     // How long to flash the entire row after button press
const int CURSOR_DELAY = 200;    // How quickly to flash the cursor led

// Pin Assignments
uint8_t rota = 2;
uint8_t rotb = 3;
uint8_t button = 4;
uint8_t dataIn = 5;
uint8_t load = 6;
uint8_t clock = 7;

Volume vol;


int maxInUse = 1;
uint8_t x = 0;
int a = 1;

char db[9][10]
{ "0 db",
  "10 db",
  "20 db",
  "30 db",
  "40 db",
  "50 db",
  "60 db",
  "70 db",
  "80 db"
};

char freq[8][10]
{ "125 Hz",
  "250 Hz",
  "500 Hz",
  "1000 Hz",
  "2000 Hz",
  "3000 Hz",
  "4000 Hz",
  "8000 Hz"
};

int freqn[8][2]
{
  125, 250, 500, 1000, 2000, 3000, 4000, 8000
};



byte max7219_reg_noop        = 0x00;
byte max7219_reg_digit0      = 0x01;
byte max7219_reg_digit1      = 0x02;
byte max7219_reg_digit2      = 0x03;
byte max7219_reg_digit3      = 0x04;
byte max7219_reg_digit4      = 0x05;
byte max7219_reg_digit5      = 0x06;
byte max7219_reg_digit6      = 0x07;
byte max7219_reg_digit7      = 0x08;
byte max7219_reg_decodeMode  = 0x09;
byte max7219_reg_intensity   = 0x0a;
byte max7219_reg_scanLimit   = 0x0b;
byte max7219_reg_shutdown    = 0x0c;
byte max7219_reg_displayTest = 0x0f;


Encoder knobLeft(rota, rotb);


char id = 0;

void putByte(byte data) {
  byte i = 8;
  byte mask;
  while (i > 0) {
    mask = 0x01 << (i - 1);
    digitalWrite( clock, LOW);
    if (data & mask) {
      digitalWrite(dataIn, HIGH);
    } else {
      digitalWrite(dataIn, LOW);
    }
    digitalWrite(clock, HIGH);
    --i;
  }
}

void maxSingle( byte reg, byte col) {


  digitalWrite(load, LOW);
  putByte(reg);
  putByte(col);//((data & 0x01) * 256) + data >> 1);
  digitalWrite(load, LOW);
  digitalWrite(load, HIGH);
}

void maxAll (byte reg, byte col) {
  int c = 0;
  digitalWrite(load, LOW);  // begin
  for ( c = 1; c <= maxInUse; c++) {
    putByte(reg);  // specify register
    putByte(col);
  }
  digitalWrite(load, LOW);
  digitalWrite(load, HIGH);
}

void maxOne(byte maxNr, byte reg, byte col) {


  int c = 0;
  digitalWrite(load, LOW);  // begin

  for ( c = maxInUse; c > maxNr; c--) {
    putByte(0);
    putByte(0);
  }

  putByte(reg);  // specify register
  putByte(col);

  for ( c = maxNr - 1; c >= 1; c--) {
    putByte(0);
    putByte(0);
  }

  digitalWrite(load, LOW);
  digitalWrite(load, HIGH);
}


void setup () {

  pinMode(dataIn, OUTPUT);
  pinMode(clock,  OUTPUT);
  pinMode(load,   OUTPUT);
  pinMode(button, INPUT);

  digitalWrite(button, HIGH);
  digitalWrite(13, LOW);


  //initiation of the max 7219
  maxAll(max7219_reg_scanLimit, 0x07);
  maxAll(max7219_reg_decodeMode, 0x00);
  maxAll(max7219_reg_shutdown, 0x01);
  maxAll(max7219_reg_displayTest, 0x00);
  for (x = 1; x <= 8; x++) { // empty registers, turn all LEDs off
    maxAll(x, 0);
  }
  maxAll(max7219_reg_intensity, 0x01 & 0x0f);
  u8g.setFont(u8g_font_unifont);
  u8g.setColorIndex(1); // display draws with pixel on


  vol.begin(); // After calling this, delay() and delayMicroseconds will no longer work
  // correctly! Instead, use vol.delay() and vol.delayMicroseconds() for
  // the correct timing

  vol.setMasterVolume(3.00); // Self-explanatory enough, right? Try lowering this value if the speaker is too loud! (0.00 - 1.00)
  vol.delay(500);

}

// Value to display a single LED on a row
uint8_t values[9] = {0, 1, 2, 4, 8, 16, 32, 64, 128};
// Array with all rows, indicating which 'value' to show
uint8_t line[8] = {0, 0, 0, 0, 0, 0, 0, 0};
// The row we  currently utilized
uint8_t idx = 0;
// Delay counters (in ms)
int delayButton = 0;
int delayRotary = ROTARY_DELAY;
int delayFlash = 0;
int delayCursor = CURSOR_DELAY;
int cursorState = 0;



// Rotary position, reset after each loop
long pos = 0;

uint8_t update = 1;

void loop () {



  // Flash the row after a button is pressed
  if (delayFlash && idx != 8) {
    maxSingle(idx + 1, 255);

    if (delayFlash == 1) {
      maxSingle(idx + 1, values[line[idx + 1]]);
    }

    delayFlash--;
    if (delayButton) delayButton--;

    return;
  }

  // Checks whther the  button is pressed
  if (delayButton) delayButton--;
  if (!digitalRead(4) && delayButton == 0) {
    if (idx == 8)
      idx = 0;
    else
      idx++;
    delayButton = BUTTON_DELAY;
    delayFlash = FLASH_DELAY;
  }


  // Checks for whether the rotary encorder is  turned and updates the 8x8 led matrix 7219 module
  if (delayRotary) delayRotary--;
  if (delayRotary == 0 && idx != 8) {
    pos = knobLeft.read();
    if (pos > 1) {
      if (line[idx] != 0)
        line[idx]--;
      else
        line[idx] = 8;
      update = 1;
    } else if (pos < -1) {
      if (line[idx] != 8)
        line[idx]++;
      else
        line[idx] = 0;
      update = 1;
    }

    if (update) {
      knobLeft.write(0);
      delayRotary = ROTARY_DELAY;

      if (pos) {
        cursorState = 1;
        delayCursor = CURSOR_DELAY;
      }
    }
      vol.tone (freqn[idx], db[line[idx]]);

  }


  // Toggle the state of the cursor after the
  //  cursor delay (in ms) has been reached
  if (delayCursor) delayCursor--;
  if (delayCursor == 0 && idx != 8) {
    delayCursor = CURSOR_DELAY;
    cursorState = 1 - cursorState;
    update = 1;
  }

  // Update the matrix only if a change has been made
  if (update) {
    for (x = 0; x < 8; x++) {
      if (x == idx) {
        if (cursorState && line[x] != 0)
          maxSingle(x + 1, values[line[x]]);
        else
          maxSingle(x + 1, 0);
      } else {
        if (line[x] == 0) continue;

        maxSingle(x + 1, values[line[x]]);

      }
    }
    update = 0;
  }

 vol.delay(1);

  if (a < 3) {
    u8g.firstPage();
    do {


      u8g.drawStr(0, 15, "Vol");
      u8g.drawStr(0, 30, "Freq");
      u8g.drawStr(50, 15, db[line[idx]]);

      u8g.drawStr(50, 30, freq[idx]);

    } while ( u8g.nextPage() );
  } else {
    u8g.firstPage();
    do {
      u8g.drawStr(0, 12, "FINAL GRAPH");
      u8g.drawStr(0, 32, "EXCUTED");
    } while ( u8g.nextPage() );
  }
}
[/code]

You connect the speaker directly to the Arduino? That probably fried your speaker pin. A typical speaker has an impedance of 8Ω so the current gets too high too fast if connected directly.

If I interpreted the circuit wrongly it's your picture not being enough to show the circuitry. Post a complete wiring diagram.

Actually I replaced the speaker with earphone because the speaker had issues prior to connection to Arduino. I connected earphone to GND and pin 9 of Arduino Uno.WhatsApp Image 2021-05-04 at 01.20.32|690x388

I still don't think that this circuit will work. You should at least insert a simple amplifier using a transistor.
And you should check the Arduino pin, it may be already fried.

1 Like

OK I shall do so. Thanks for the guidance given. I appreciate it.

Is there any problem in my code as well?

I have had many hearing tests and likely another one this afternoon. There is NO way you can test hearing using a square wave, since it includes all the possible harmonic frequencies of the fundamental frequency. You need a pure sine wave for each frequency.
Paul

1 Like

That's exactly what I was going to say! Oh, except that it contains all the odd harmonics, of course, but you knew that. :grinning:

Yes that is what makes the corners square!
Paul

1 Like

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