Go Down

### Topic: Tone Function Arduino (Read 1 time)previous topic - next topic

#### DelfinDelfin

##### May 28, 2019, 07:35 pmLast Edit: May 28, 2019, 07:46 pm by DelfinDelfin
Hello, I am trying to understand how the Tone Function on Arduino works. This function allows you to interface a buzzer at certain frequency.

Code: [Select]
`// frequency (in hertz) and duration (in milliseconds).void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){  uint8_t prescalarbits = 0b001;  long toggle_count = 0;  uint32_t ocr = 0;  int8_t _timer;  _timer = toneBegin(_pin);  if (_timer >= 0)  {    // Set the pinMode as OUTPUT    pinMode(_pin, OUTPUT);        // if we are using an 8 bit timer, scan through prescalars to find the best fit    if (_timer == 0 || _timer == 2)    {      ocr = F_CPU / frequency / 2 - 1;      prescalarbits = 0b001;  // ck/1: same for both timers      if (ocr > 255)      {        ocr = F_CPU / frequency / 2 / 8 - 1;        prescalarbits = 0b010;  // ck/8: same for both timers        if (_timer == 2 && ocr > 255)        {          ocr = F_CPU / frequency / 2 / 32 - 1;          prescalarbits = 0b011;        }        if (ocr > 255)        {          ocr = F_CPU / frequency / 2 / 64 - 1;          prescalarbits = _timer == 0 ? 0b011 : 0b100;          if (_timer == 2 && ocr > 255)          {            ocr = F_CPU / frequency / 2 / 128 - 1;            prescalarbits = 0b101;          }          if (ocr > 255)          {            ocr = F_CPU / frequency / 2 / 256 - 1;            prescalarbits = _timer == 0 ? 0b100 : 0b110;            if (ocr > 255)            {              // can't do any better than /1024              ocr = F_CPU / frequency / 2 / 1024 - 1;              prescalarbits = _timer == 0 ? 0b101 : 0b111;            }          }        }      }#if defined(TCCR0B)      if (_timer == 0)      {        TCCR0B = (TCCR0B & 0b11111000) | prescalarbits;      }      else#endif#if defined(TCCR2B)      {        TCCR2B = (TCCR2B & 0b11111000) | prescalarbits;      }#else      {        // dummy place holder to make the above ifdefs work      }#endif    }    else    {      // two choices for the 16 bit timers: ck/1 or ck/64      ocr = F_CPU / frequency / 2 - 1;      prescalarbits = 0b001;      if (ocr > 0xffff)      {        ocr = F_CPU / frequency / 2 / 64 - 1;        prescalarbits = 0b011;      }      if (_timer == 1)      {#if defined(TCCR1B)        TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;#endif      }#if defined(TCCR3B)      else if (_timer == 3)        TCCR3B = (TCCR3B & 0b11111000) | prescalarbits;#endif#if defined(TCCR4B)      else if (_timer == 4)        TCCR4B = (TCCR4B & 0b11111000) | prescalarbits;#endif#if defined(TCCR5B)      else if (_timer == 5)        TCCR5B = (TCCR5B & 0b11111000) | prescalarbits;#endif    }        // Calculate the toggle count    if (duration > 0)    {      toggle_count = 2 * frequency * duration / 1000;    }    else    {      toggle_count = -1;    }    // Set the OCR for the given timer,    // set the toggle count,    // then turn on the interrupts    switch (_timer)    {#if defined(OCR0A) && defined(TIMSK0) && defined(OCIE0A)      case 0:        OCR0A = ocr;        timer0_toggle_count = toggle_count;        bitWrite(TIMSK0, OCIE0A, 1);        break;#endif      case 1:#if defined(OCR1A) && defined(TIMSK1) && defined(OCIE1A)        OCR1A = ocr;        timer1_toggle_count = toggle_count;        bitWrite(TIMSK1, OCIE1A, 1);#elif defined(OCR1A) && defined(TIMSK) && defined(OCIE1A)        // this combination is for at least the ATmega32        OCR1A = ocr;        timer1_toggle_count = toggle_count;        bitWrite(TIMSK, OCIE1A, 1);#endif        break;#if defined(OCR2A) && defined(TIMSK2) && defined(OCIE2A)      case 2:        OCR2A = ocr;        timer2_toggle_count = toggle_count;        bitWrite(TIMSK2, OCIE2A, 1);        break;#endif#if defined(OCR3A) && defined(TIMSK3) && defined(OCIE3A)      case 3:        OCR3A = ocr;        timer3_toggle_count = toggle_count;        bitWrite(TIMSK3, OCIE3A, 1);        break;#endif#if defined(OCR4A) && defined(TIMSK4) && defined(OCIE4A)      case 4:        OCR4A = ocr;        timer4_toggle_count = toggle_count;        bitWrite(TIMSK4, OCIE4A, 1);        break;#endif#if defined(OCR5A) && defined(TIMSK5) && defined(OCIE5A)      case 5:        OCR5A = ocr;        timer5_toggle_count = toggle_count;        bitWrite(TIMSK5, OCIE5A, 1);        break;#endif    }  }}`

It realies in this other function:
Code: [Select]
`static int8_t toneBegin(uint8_t _pin){  int8_t _timer = -1;  // if we're already using the pin, the timer should be configured.    for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {    if (tone_pins[i] == _pin) {      return pgm_read_byte(tone_pin_to_timer_PGM + i);    }  }    // search for an unused timer.  for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {    if (tone_pins[i] == 255) {      tone_pins[i] = _pin;      _timer = pgm_read_byte(tone_pin_to_timer_PGM + i);      break;    }  }    if (_timer != -1)  {    // Set timer specific stuff    // All timers in CTC mode    // 8 bit timers will require changing prescalar values,    // whereas 16 bit timers are set to either ck/1 or ck/64 prescalar    switch (_timer)    {      #if defined(TCCR0A) && defined(TCCR0B) && defined(WGM01)      case 0:        // 8 bit timer        TCCR0A = 0;        TCCR0B = 0;        bitWrite(TCCR0A, WGM01, 1);        bitWrite(TCCR0B, CS00, 1);        timer0_pin_port = portOutputRegister(digitalPinToPort(_pin));        timer0_pin_mask = digitalPinToBitMask(_pin);        break;      #endif      #if defined(TCCR1A) && defined(TCCR1B) && defined(WGM12)      case 1:        // 16 bit timer        TCCR1A = 0;        TCCR1B = 0;        bitWrite(TCCR1B, WGM12, 1);        bitWrite(TCCR1B, CS10, 1);        timer1_pin_port = portOutputRegister(digitalPinToPort(_pin));        timer1_pin_mask = digitalPinToBitMask(_pin);        break;      #endif      #if defined(TCCR2A) && defined(TCCR2B)      case 2:        // 8 bit timer        TCCR2A = 0;        TCCR2B = 0;        bitWrite(TCCR2A, WGM21, 1);        bitWrite(TCCR2B, CS20, 1);        timer2_pin_port = portOutputRegister(digitalPinToPort(_pin));        timer2_pin_mask = digitalPinToBitMask(_pin);        break;      #endif      #if defined(TCCR3A) && defined(TCCR3B) &&  defined(TIMSK3)      case 3:        // 16 bit timer        TCCR3A = 0;        TCCR3B = 0;        bitWrite(TCCR3B, WGM32, 1);        bitWrite(TCCR3B, CS30, 1);        timer3_pin_port = portOutputRegister(digitalPinToPort(_pin));        timer3_pin_mask = digitalPinToBitMask(_pin);        break;      #endif      #if defined(TCCR4A) && defined(TCCR4B) &&  defined(TIMSK4)      case 4:        // 16 bit timer        TCCR4A = 0;        TCCR4B = 0;        #if defined(WGM42)          bitWrite(TCCR4B, WGM42, 1);        #elif defined(CS43)          // TODO this may not be correct          // atmega32u4          bitWrite(TCCR4B, CS43, 1);        #endif        bitWrite(TCCR4B, CS40, 1);        timer4_pin_port = portOutputRegister(digitalPinToPort(_pin));        timer4_pin_mask = digitalPinToBitMask(_pin);        break;      #endif      #if defined(TCCR5A) && defined(TCCR5B) &&  defined(TIMSK5)      case 5:        // 16 bit timer        TCCR5A = 0;        TCCR5B = 0;        bitWrite(TCCR5B, WGM52, 1);        bitWrite(TCCR5B, CS50, 1);        timer5_pin_port = portOutputRegister(digitalPinToPort(_pin));        timer5_pin_mask = digitalPinToBitMask(_pin);        break;      #endif    }  }  return _timer;}`

Does anyone know what does is this function doing? How it works? I am trying to code something simmilar in a PIC Microcotroller

#### DVDdoug

#1
##### May 28, 2019, 08:13 pm
I've never used a PIC chip, but every microcontroller has a different architecture and there are several different PIC chips.

High level languages like C++ isolate you from the hardware details but with microcontroller programming you're not using Standard ANSI/ISO C/C++ so the language functions and details are different depending on the chip.

What kind of timing functions does your PIC chip have?  If there is a timer interrupt you can use that.   (It might require Assembly Language.)

#### DelfinDelfin

#2
##### May 28, 2019, 08:46 pmLast Edit: May 28, 2019, 08:48 pm by DelfinDelfin
Yes, it has a Timer Interrupt ... I only need to know the signal that I have to generate ...

#### slipstick

#3
##### May 28, 2019, 11:46 pm
It's a very simple signal as tone() just produces a square wave at the specified frequency.

Steve

#### DelfinDelfin

#4
##### May 29, 2019, 12:56 amLast Edit: May 29, 2019, 12:57 am by DelfinDelfin
So .. I can do it with PWM with a duty cycle of 50% and the specified frequency

#### Grumpy_Mike

#5
##### May 29, 2019, 10:26 am
So .. I can do it with PWM with a duty cycle of 50% and the specified frequency
If you can fix the duty cycle then changing the frequency of the PWM will change the tone.
BUT
Simply changing the frequency of the PWM clock will also change the duty cycle so you have to adjust two register values in the timer, the count and the threshold.

#### v1n1c1usmov1ck

#6
##### May 30, 2019, 12:53 am
Hi, I would like to ask you for a help ... I have to present a work day 6, and I'm going to use a buzzer, but I wanted something nice and I do not know how to do code for arduino music ... I wanted someone to do it the code for my presentation, the ideal is the library tone because it will save me a lot of having to redo my code ... this is the music I wanted to do a funny thing, it's just to make the chorus