Sunday, October 1, 2017

Arduino sine wave siren code using a lookup table in flash memory (PROGMEM)


Subscribe by Email!
By Gabriel Staples
Posted: 30 Sept. 2017
Last Updated: 30 Sept. 2017

Related Articles:
Other Articles:
(*Articles containing or linking to source code are marked with an asterisk)
Demo Video: 




ADVERTISEMENT:
Source Code:


/*
lookup_table_sine_wave_arduino_siren.ino
- play a frequency-varying sine wave in a piezo buzzer
- Published: http://www.electricrcaircraftguy.com/2017/10/arduino-sine-wave-siren-code.html
By Gabriel Staples
www.ElectricRCAircraftGuy.com 
Written: 5 Nov. 2015 
Last Updated: 30 Sept. 2017 

Update History (newest on TOP):
 - 30 Sept. 2017: cleaned up code so I can share it on my website 
 - 20 Jan 2016: modified code to use ToneAC to dual drive a 120W peak/60W 
   RMS speaker through a high-power H-bridge I made
 - 5 Nov. 2015: first version, uses built-in Arduino tone() function: 
   https://www.arduino.cc/en/Reference/Tone

References:
-http://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml
-https://www.arduino.cc/en/Reference/Tone
-https://en.wikipedia.org/wiki/Siren_(alarm)

Libraries needed:
-ToneAC: http://playground.arduino.cc/Code/ToneAC 
*/

//Includes
#include <avr/pgmspace.h> //http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html 
#include <toneAC.h> //plays on pins 9 & 10 for ATmega328

//Global vars & consts
byte sirenVolume = 1; //for ToneAC; from 0-10
const unsigned int SIREN_SLOW = 25000; //us; desired delta time between siren freq updates
const unsigned int SIREN_FAST = 5000; //us
unsigned int sirenPeriod = SIREN_SLOW; //us

//sine wave lookup table to produce the siren sound
static const unsigned int sineLookupTable[] PROGMEM = 
{
  //Sine wave lookup table generator: 
  // - http://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml
  //Number of points: 256
  //Max Amplitude: 255
  //Numbers per row: 8
  //Decimal
  128,131,134,137,140,143,146,149,
  152,155,158,162,165,167,170,173,
  176,179,182,185,188,190,193,196,
  198,201,203,206,208,211,213,215,
  218,220,222,224,226,228,230,232,
  234,235,237,238,240,241,243,244,
  245,246,248,249,250,250,251,252,
  253,253,254,254,254,255,255,255,
  255,255,255,255,254,254,254,253,
  253,252,251,250,250,249,248,246,
  245,244,243,241,240,238,237,235,
  234,232,230,228,226,224,222,220,
  218,215,213,211,208,206,203,201,
  198,196,193,190,188,185,182,179,
  176,173,170,167,165,162,158,155,
  152,149,146,143,140,137,134,131,
  128,124,121,118,115,112,109,106,
  103,100,97,93,90,88,85,82,
  79,76,73,70,67,65,62,59,
  57,54,52,49,47,44,42,40,
  37,35,33,31,29,27,25,23,
  21,20,18,17,15,14,12,11,
  10,9,7,6,5,5,4,3,
  2,2,1,1,1,0,0,0,
  0,0,0,0,1,1,1,2,
  2,3,4,5,5,6,7,9,
  10,11,12,14,15,17,18,20,
  21,23,25,27,29,31,33,35,
  37,40,42,44,47,49,52,54,
  57,59,62,65,67,70,73,76,
  79,82,85,88,90,93,97,100,
  103,106,109,112,115,118,121,124,
};
//calculate the length of the lookup table above
const unsigned int NUM_SINEWAVE_ELEMENTS = sizeof(sineLookupTable)/sizeof(unsigned int); 

//Function declarations/prototypes
void playSirenSound(byte volume = 1, unsigned int period_us = SIREN_SLOW);

//Function definitions:

//-------------------------------------------------------------------------------------------------
//setup
//-------------------------------------------------------------------------------------------------
void setup()
{
  Serial.begin(115200);
  Serial.println(F("begin")); 
  
  //FOR DEBUGGING
  Serial.print(F("NUM_SINEWAVE_ELEMENTS = ")); Serial.println(NUM_SINEWAVE_ELEMENTS);
}

//-------------------------------------------------------------------------------------------------
//loop 
//-------------------------------------------------------------------------------------------------
void loop()
{
  playSirenSound();
  //OR
  // playSirenSound(sirenVolume, sirenPeriod);
}

//-------------------------------------------------------------------------------------------------
//playSirenSound
//-------------------------------------------------------------------------------------------------
void playSirenSound(byte volume, unsigned int period_us)
{
  //local vars
  static unsigned long t_start = micros(); //us
  unsigned long t_now = micros(); //us
  if (t_now - t_start >= period_us)
  {
    t_start = t_now; //us; update
    static unsigned int sirenIndex = 0;
    //look up value in lookup table
    // - NB: pgm_read_word is for reading 2 byte values, 
    //   pgm_read_byte is for reading 1 byte values 
    unsigned int freq = pgm_read_word(sineLookupTable + sirenIndex); 
    sirenIndex++;
    if (sirenIndex >= NUM_SINEWAVE_ELEMENTS)
      sirenIndex = 0; //start back at beginning of sine wave 
    toneAC(freq+635, volume);
  }
}



END

Keywords: Arduino nano, H-bridge, audio, speaker, siren, siren sound, police siren, lookup table, sine wave lookup table, AVR PROGMEM, AVR-LibC, toneAC

***Subscribe by Email!***

3 comments:

Thanks for your comment or question! If it is a question, I will try to get back to you quickly. Notice to spammers: I personally remove all spam promptly and report spammers to Google, so please don't do it.

Note: some HTML tags are allowed in your comments. To learn how to add bold (<b>...</b>), italics (<i>...</i>), or hyperlinks (<a href="URL">NAME</a>) to your comments, read here.

~Sincerely, Gabriel Staples.

P.S. Yo hablo español también. Je parle français aussi. (I speak Spanish & French too).