Use both ultrasonic library and volume library

Hey Guys,
I'm trying to make a theremin with Arduino, using an arduino UNO, shield base, two ultrasonic sensor (one for the frequency, one for the volume), and a speaker.
The thing is with the integrated tone module I can't control the volume, but with every other library (I've tried libraries for the speaker and for the Ultrasonic sensor) there's a problem. I don't really understand what is it but it might be because they are all setting on the same timer on the arduino card.
Could you help me?

Here's my code :

#define BUZZER_PIN 8
#include "Ultrasonic.h"
Ultrasonic telemetre1(2);
Ultrasonic telemetre2(3);

// Fréquences des notes de Do3 à Do4
#define Do3 261
#define Dod3 277
#define Re3 293
#define Red3 311
#define Mi3 329
#define Fa3 349
#define Fad3 369
#define So3 391
#define Sod3 415
#define La3 440
#define Lad3 466
#define Si3 493
#define Do4 523

// Distance
long distance;

// Frequences
int note[] = {
  Do3, Dod3, Re3, Red3,  Mi3, Fa3, Fad3, So3, Sod3, La3, Lad3, Si3, Do4
};

// Volumes
int vol[] = {
  0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100
};

void setup() {
  Serial.begin(9600);
}

void loop() {
  int frequence = disttofreq();
  sound(frequence);
  delay(10);
}

int disttofreq() {
  distance = telemetre1.MeasureInCentimeters();
  if (distance > 50){
    return 0;
  }
  int inote = map(distance, 0, 50, 0, 13);
  int frequence = note[inote];
  return frequence;
}

int disttovol() {
  distance = telemetre2.MeasureInCentimeters();
  if (distance > 50){
    return 0;
  }
  int ivol = map(distance, 0, 50, 0, 11);
  int volume = vol[ivol];
}

void sound(int frequence) {
  tone(BUZZER_PIN, frequence, 500); // Pin du Buzzer, frequence qu'on veut jouer et temps ou on joue la note
}

The function does not return a volume if distance <= 50.
It is nowhere used?

Note that tone() has no volume parameter, so you should make your own sound with e.g. mcp4725 DAC to generate a wave of which you can control frequency and amplitude.

Have a look at MCP4725_wave_generator.ino

You could add amplitude by changing the value 4095 (max value) to a variable that is between 0 and 4095. The demo does not implement that.

Hey, sorry for not responding, I had no time to look it up. I trying to understand what the code of MCP4725_wave_generator does, and how I can use it for a better volume control but I don't know if just need to modify the frequency like on line 20. IN fact I do'nt really understand the code I think...

//
//    FILE: MCP4725_wave_generator.ino
//  AUTHOR: Rob Tillaart
// PURPOSE: demo function generators
//     URL: https://github.com/RobTillaart/FunctionGenerator
//
//  depending on the platform, the range of "smooth" sinus is limited.
//  other signals are less difficult so have a slightly larger range.
//
//  PLATFORM     SINUS    SQUARE  SAWTOOTH  TRIANGLE
//  UNO          -100 Hz
//  ESP32        -200 Hz  -1000   -250      -100
//


#include "MCP4725.h"
#include "Wire.h"

uint16_t   freq = 100;
uint32_t period = 0;
uint32_t halvePeriod = 0;


//  q = square       z = zero
//  s = sinus        m = mid
//  w = sawtooth     h = high
//  t = stair
//  r = random
char mode = 'q';


MCP4725 MCP(0x63);
uint16_t count;
uint32_t lastTime = 0;


//  LOOKUP TABLE SINE
uint16_t sine[361];


void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("MCP4725_VERSION: ");
  Serial.println(MCP4725_VERSION);

  Wire.begin();
  //  Wire.setClock(3400000);
  
  //  fill table
  for (int i = 0; i < 361; i++)
  {
    sine[i] = 2047 + round(2047 * sin(i * PI / 180));
  }

  MCP.begin();
  Wire.setClock(800000);

  MCP.setValue(0);
  if (!MCP.isConnected())
  {
    Serial.println("err");
    while (1);
  }
  period = 1e6 / freq;
  halvePeriod = period / 2;

  while (1)
  {
    yield();
    uint32_t now = micros();

    count++;

    if (now - lastTime > 100000)
    {
      lastTime = now;
      //  show # updates per 0.1 second
      //  Serial.println(count);
      count = 0;
      if (Serial.available())
      {
        int c = Serial.read();
        switch (c)
        {
          case '+':
            freq++;
            break;
          case '-':
            freq--;
            break;
          case '*':
            freq *= 10;
            break;
          case '/':
            freq /= 10;
            break;
          case '0' ... '9':
            freq *= 10;
            freq += (c - '0');
            break;
          case 'c':
            freq = 0;
            break;
          case 'A':
            break;
          case 'a':
            break;
          case 'q':
          case 's':
          case 'w':
          case 't':
          case 'r':
          case 'z':
          case 'm':
          case 'h':
            mode = c;
            break;
          default:
            break;
        }
        period = 1e6 / freq;
        halvePeriod = period / 2;
        Serial.print(freq);
        //        Serial.print('\t');
        //        Serial.print(period);
        //        Serial.print('\t');
        //        Serial.print(halvePeriod);
        Serial.println();
      }
    }

    uint32_t t = now % period;

    switch (mode)
    {
      case 'q':
        if (t < halvePeriod ) MCP.setValue(4095);
        else MCP.setValue(0);
        break;
      case 'w':
        MCP.setValue(t * 4095 / period );
        break;
      case 't':
        if (t < halvePeriod) MCP.setValue(t * 4095 / halvePeriod);
        else MCP.setValue( (period - t) * 4095 / halvePeriod );
        break;
      case 'r':
        MCP.setValue(random(4096));
        break;
      case 'z':  //  zero
        MCP.setValue(0);
        break;
      case 'h':  //  high
        MCP.setValue(4095);
        break;
      case 'm':  //  mid
        MCP.setValue(2047);
        break;
      default:
      case 's':
        //  reference
        //  float f = ((PI * 2) * t)/period;
        //  MCP.setValue(2047 + 2047 * sin(f));
        //
        int idx = (360 * t) / period;
        MCP.setValue(sine[idx]);   //  fetch from lookup table
        break;
    }
  }
}


void loop()
{
}


//  -- END OF FILE --

@adrien_candela

Volume is the amplitude of the wave, I changed the sketch to have a amplitude variable which can be controlled by entering the character v == volume down or V == volume up.

The frequency is controlled by characters + - * /
The waveform is selected by characters q s w t r z m h

Here the same sketch now with amplitude control

  • V == volume up (to 100%)
  • v == volume down (to 0 %)
//
//    FILE: MCP4725_wave_generator_II.ino
//  AUTHOR: Rob Tillaart
// PURPOSE: demo function generators
//     URL: https://github.com/RobTillaart/FunctionGenerator
//     URL: https://github.com/RobTillaart/MCP4725
//
//  depending on the platform, the range of "smooth" sinus is limited.
//  other signals are less difficult so have a slightly larger range.
//
//  PLATFORM     SINUS    SQUARE  SAWTOOTH  TRIANGLE
//  UNO          -100 Hz
//  ESP32        -200 Hz  -1000   -250      -100
//

#include "MCP4725.h"
#include "Wire.h"

//  amplitude
//  between 0 and 100 percent, use  v  and V to control it
uint16_t amplitude = 100;

//  frequency
//  + - * /  to control it
uint16_t freq = 100;

// helpers
uint32_t period = 0;
uint32_t halvePeriod = 0;


//  wave form
//  q = square       z = zero
//  s = sinus        m = mid
//  w = sawtooth     h = high
//  t = stair
//  r = random
char waveForm = 'q';

MCP4725 MCP(0x63);
uint16_t count;
uint32_t lastTime = 0;

//  LOOKUP TABLE SINE
uint16_t sine[361];

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("MCP4725_VERSION: ");
  Serial.println(MCP4725_VERSION);

  Wire.begin();
  //  Wire.setClock(3400000);
  
  //  fill table
  for (int i = 0; i < 361; i++)
  {
    sine[i] = 2047 + round(2047 * sin(i * PI / 180));
  }

  MCP.begin();
  Wire.setClock(800000);

  MCP.setValue(0);
  if (!MCP.isConnected())
  {
    Serial.println("err");
    while (1);
  }
  period = 1e6 / freq;
  halvePeriod = period / 2;

  while (1)
  {
    yield();
    uint32_t now = micros();

    count++;

    if (now - lastTime > 100000)
    {
      lastTime = now;
      //  show # updates per 0.1 second
      //  Serial.println(count);
      count = 0;
      if (Serial.available())
      {
        int c = Serial.read();
        switch (c)
        {
          case 'V':
            if (amplitude < 100) amplitude++;
            break;
          case 'v':
            if (amplitude > 0) amplitude--;
            break;
          case '+':
            freq++;
            break;
          case '-':
            freq--;
            break;
          case '*':
            freq *= 10;
            break;
          case '/':
            freq /= 10;
            break;
          case '0' ... '9':
            freq *= 10;
            freq += (c - '0');
            break;
          case 'c':
            freq = 0;
            break;
          case 'A':
            break;
          case 'a':
            break;
          case 'q':
          case 's':
          case 'w':
          case 't':
          case 'r':
          case 'z':
          case 'm':
          case 'h':
            waveForm = c;
            break;
          default:
            break;
        }
        period = 1e6 / freq;
        halvePeriod = period / 2;
        Serial.print(freq);
        //        Serial.print('\t');
        //        Serial.print(period);
        //        Serial.print('\t');
        //        Serial.print(halvePeriod);
        Serial.println();
      }
    }

    uint32_t t = now % period;
    
    //  a = amplitude as float.
    float a = amplitude * 0.01;

    switch (waveForm)
    {
      case 'q':
        if (t < halvePeriod ) MCP.setValue(a * 4095);
        else MCP.setValue(0);
        break;
      case 'w':
        MCP.setValue(a * t * 4095 / period );
        break;
      case 't':
        if (t < halvePeriod) MCP.setValue(a * t * 4095 / halvePeriod);
        else MCP.setValue( a * (period - t) * 4095 / halvePeriod );
        break;
      case 'r':
        MCP.setValue(random(a * 4096));
        break;
      case 'z':  //  zero
        MCP.setValue(0);
        break;
      case 'h':  //  high
        MCP.setValue(4095);
        break;
      case 'm':  //  mid
        MCP.setValue(2047);
        break;
      default:
      case 's':
        //  reference
        //  float f = ((PI * 2) * t)/period;
        //  MCP.setValue(2047 + 2047 * sin(f));
        //
        int idx = (360 * t) / period;
        MCP.setValue(a * sine[idx]);   //  fetch from lookup table 
        break;
    }
  } 
}

void loop()
{
}

//  -- END OF FILE --

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