Scales on the Arduino With an SPI 12 Bit Dac

You will need:

  1. An arduino DAC shield http://tinyurl.com/AudioShield
  2. A powered speaker with a 3.5mm plug
  3. an arduino uno compatible
  4. a host computer for compiling and uploading code

You will get:

  1. The ability to play scales
  2. The ability to play any song you would like to encode
  3. endless hours of great fun and learning

Teacher Notes

Teachers! Did you use this instructable in your classroom?
Add a Teacher Note to share how you incorporated it into your lesson.

Step 1: Scales on the Arduino Audio Shield

First download and compile the code

/*  freqout(freq, t)
// freq in hz, t in ms a simple tone generation function generates square waves of arbitrary frequency and duration program also includes a top-octave lookup table & transposition function */
#include 
#define LDAC        8
#define ChipSel     9
//using macros for pin numbers is better than using a variable -BM
///Danger Will Robinson!
/****************************
*****************************
  This code will work ONLY with
  Arduino boards using ATMega
  328 or 168 processors!
  Ex: Uno, Nano, Pro Mini. - BM
*****************************
****************************/
void DACWrite( uint16_t );
int ptime;
int   k,  x, dur, freq, t;
int i, j;
float ps;
// variable for pow pitchShift routine
float noteval;
// note values for two octave scale
// divide them by powers of two to generate other octaves
float A     = 14080;
float AS    = 14917.2;
float B     = 15804.3;
float C     = 16744;
float CS    = 17739.7;
float D     = 18794.5;
float DS    = 19912.1;
float E     = 21096.2;
float F     = 22350.6;
float FS    = 23679.6;
float G     = 25087.7;
float GS    = 26579.5;
float AA2    = 28160;
float A2S   = 29834.5;
float B2    = 31608.5;
float C2    = 33488.1;
float C2S   = 35479.4;
float D2    = 37589.1;
float D2S   = 39824.3;
float E2    = 42192.3;
float F2    = 44701.2;
float F2S   = 47359.3;
float G2    = 50175.4;
float G2S   = 53159;
float AA3    = 56320;
//octaves  - corresponds to piano octaves
float oct8 = 4;
float oct7 = 8;
float oct6 = 16;
float oct5 = 32;
float oct4 = 64;
float oct3 = 128;
float oct2 = 256;
float oct1 = 512;
float oct0 = 1024;
//rhythm values
int wh = 1024;
int h  = 512;
int dq = 448;
int q = 256;
int qt = 170;
int de = 192;
int e = 128;
int et = 85;
int dsx = 96;
int sx = 64;
int thx = 32;
// major scale just for demo, hack this
float majScale[] = { A, B, CS, D, E, FS, GS, AA2,
                     B2, C2S, D2, E2, F2S, G2S, AA3
                   };
void setup() {
  pinMode( ChipSel, OUTPUT );     // sets the digital pin as output
  pinMode( LDAC, OUTPUT );
  SPI.begin();
  PORTB |= 0b00000011;
  //set chip select and LDAC to default high state - BM
  Serial.begin(115200);
}
void loop() {
  for (i = 0; i <= 11; i++)  {
    ps = (float)i / 12;
    // choose new transpose interval every loop
    for (x = 0; x <= 15; x++) {
      noteval = (majScale[x] / oct4) * pow(2, ps);
      // transpose scale up 12 tones
      // pow function generates transposition
      // eliminate " * pow(2,ps) " to cut out transpose routine
      dur = 100;
      freqout((int)noteval, dur);
      delay(10);
    }
  }
}
void DACWrite( uint16_t outbuf ) {
  outbuf |= 0b0111000000000000;   //change some bits at the beginning to configure DAC
  char* w_bytes;
  w_bytes = (char*)&outbuf;       //split the two bytes in outbuf into an array
  PORTB &= 0b11111101;            //pull chip select low
  SPI.transfer( w_bytes [1] );    //send them one at a time
  SPI.transfer( w_bytes [0] );
  PORTB |= 0b00000010;            //pull chip select high
  PORTB &= 0b11111110;            //pull LDAC low
  asm volatile("nop");            //wait one clock cycle
  PORTB |= 0b00000001;            //pull LDAC high
}
// freq in hz, t in ms
void freqout(int freq, int t) {
  int hperiod;
  //calculate 1/2 period in us
  long cycles, i;
  hperiod = (500000 / freq) - 7;
  // subtract 7 us to make up for digitalWrite overhead
  cycles = ((long)freq * (long)t) / 1000;
  // calculate cycles
  // Serial.print(freq);
  // Serial.print((char)9);
  // ascii 9 is tab - you have to coerce it to a char to work
  // Serial.print(hperiod);
  // Serial.print((char)9);
  // Serial.println(cycles);
  // play note for t ms
  for (i = 0; i <= cycles; i++) {
    DACWrite( 4095 );
    //send max value to DAC -- equivalent to logic HIGH - BM
    delayMicroseconds(hperiod);
    DACWrite( 0 );
    //send 0 to DAC -- equivalent to logic LOW - BM
    delayMicroseconds(hperiod);
    // - 1 to make up for digitaWrite overhead
    //removed - PORT is much faster - BM
  }
}

Step 2: Upload

Then upload the code sample to the arudino.

If you have the shield (available at: http://tinyurl.com/AudioShield)

You should be able to hear scales on the speaker.

You will need an amplified speaker with a 3.5mm plug to plug into the shield.

The shield has no amplifier and cannot drive a speaker directly.

Be the First to Share

    Recommendations

    • Made with Math Contest

      Made with Math Contest
    • Multi-Discipline Contest

      Multi-Discipline Contest
    • Robotics Contest

      Robotics Contest

    Discussions