Tone issues while using Software Serial

Use a PWM output for the tone. A bit harder to set up but should work well for a single tone.

Smoke I’ll look into it. Once I get past prototype everything will be SMT. Army has some fun toys. High speed low drag.

I can bit bang. I got a few more things to try including ToneAC. Just trying to get some time with the friggin family and wife :).

Marle I can try PWM but I think it’s restricted to something like 940 HZ for the 328. It might work. 2200 is a perfect 5th from A.

Defaults are 480 Hz and 960 Hz depending on the pin used but with some smart register manipulation you should be able to get different frequencies - you'll have to do the research on how to do this yourself as I also don't know the details.

PWM gives you the square wave you're after, and as it's an alarm buzzer the exact frequency shouldn't be too important.

wvmarle:
Use a PWM output for the tone. A bit harder to set up but should work well for a single tone.

I'm pretty sure that changing PWM frequency messes with the micros and millis clocks.

Looking for the page that tells how to change PWM frequency, I found this:
http://playground.arduino.cc/Code/PCMAudio
http://www.cs.nott.ac.uk/~pszjm2/projects/other/Arduino_Octo_Synth_.html

Here it is! Arduino Playground - PwmFrequency

Please keep in mind that changing the PWM frequency changes the Atmega's timers and disrupts the normal operation of many functions that rely on time (delay(), millis(), Servo library).

Worse comes to worse I can move Bluetooth to serial pins. I think I can code around that.

As I understand, there are three timers, each responsible for two PWM pins.

Millis() and micros() use timer0 if I remember correctly. Indeed rather not touch those.
Servo maybe timer1? If no servos in the project no problem there.
Timer2 may be in use by the SoftwareSerial.

So check the libraries that are in use and mess with the correct timer :slight_smile:

Here is a beep function that I tested with a led (speaker is in a box… somewhere) because I could.
It uses both 32-bit and 16-bit micros timing. Beep can last over an hour, not sure how low tone can get.

I threw in a loop counter to show how the load affects sketch response time.

#include "Arduino.h"

unsigned long beepStart, beepLen; // timing with micros
// cycle times are microsecs OFF, ON 
word cycleStart, cycleTime[ 2 ] = { 400, 45 }; // add to 445us for ~2200Hz
byte cycleState;
const byte beepPin = 13; // shows on led13, make it beep a different pin

unsigned long loopCount, countStart;


void setup()
{
  Serial.begin( 115200 );
  pinMode( beepPin, OUTPUT );
}

void beepOnce()
{
  if ( beepLen > 0 )
  {
    if ( micros() - beepStart < beepLen ) // beep duration
    {
      if ( word( micros()) - cycleStart >= cycleTime[ cycleState ] ) // modulation
      {
        cycleStart += cycleTime[ cycleState ];
        cycleState = !cycleState; // ! is logical NOT, if == 0 then = 1 else = 0
        digitalWrite( beepPin, cycleState );
      }
    }
    else
    {
      beepLen = cycleState = 0;
      digitalWrite( beepPin, cycleState );
    }
  }
}


void loop()
{
  beepOnce();

  if ( Serial.available())
  {
    if ( Serial.read() == '\n' ) // hit enter in serial monitor
    {
      beepStart = micros(); 
      cycleStart = word( micros());
      cycleState = 0;     
      beepLen = 2000000; // 2 secs in micros to show with led
    }
  }

  loopCount++;
  if ( micros() - countStart >= 1000000 )
  {
    countStart += 1000000;
    Serial.print( F( "LC " ));
    Serial.println( loopCount );
    loopCount = 0;
  }
}

Update. It wasn’t the Arduino it was the code. I forgot the brackets to encapsulate the tone statement in the if statement so tone kept looping every millisecond. Sounded like a weird modem. So happy camper no changes needed. Maybe it will help someone.

Okay, did you see what code I left? I got the intervals slightly wrong, should be 454 micros total not 445.

It gets the note from the total ON+OFF=454 time for 2202 Hz. Change the total time changes the note.

How much ON time, maybe up to 50% of total maybe not, makes the volume.

ON and OFF values for many notes and volume levels could be tabled in flash to save a lot of cycles on mults and divs.

It's possible to vary the volume as the note plays in ADSR fashion.

If the ON time gets small amounts added to or subtracted from it can the volume changes make a secondary frequency as a ripple (small amount) on the wave (ON time=volume)? I'm not sure how the ear would react, we can fill a major note in a chord (BB King said that) so maybe make better sounds than plain square wave tones?

Smoke your coding Kung fu is way more advanced than mine.

I will try it but I’m stuck on ADC project atm. So many questions about the S/H cap and the responsiveness from higher impedance divider circuit.

One thing I’m a little confused about isn’t it amplitude that determines volume? - just thought it through so from 0-50% it increases volume.

These are not generated nice AC sound waves but when the current hits the speaker, physically moving the diaphragm and air knocks corners off and averages the sound a bit. It sounds chintzy but it's still tones and music.

The ON time is how much pow is behind any wave and the total time is how often the wave gets made.

You can run my sketch and mess with the sound easily enough. Here in the top....

#include "Arduino.h"

unsigned long beepStart, beepLen; // timing with micros
// cycle times are microsecs OFF, ON
word cycleStart, cycleTime[ 2 ] = { 400, 45 }; // add to 445us for ~2200Hz

Those values for cycleTime are the OFF and ON times for the sound.... that need correcting, the 45 should be 54.

But anyhow you can try making the total time 454 while trading OFF time for ON and hear the volume, try 227 and 227?

My coding Kung Fu is mostly approach and code literacy, what I have left after a major trauma and what I have relearned since.
The approach is simple but you have to find the view that funny enough the Arduino setup() and loop() do serve well.
The initialization is setup() and after that whatever is inside of loop should expect an ongoing process.

Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.

Round and round, void loop() is the driving wheel.

I love the Arduino IDE. I started in BASIC with an Apple II plus back in the day. I’ve been wanting to get into programming stamps ever since the 90s but they were expensive. C++ is so much easier than BASIC.

I get blown away when you guys do direct port manipulation and using hex.

I think I’m going to an SoC like the nrf 51 and 52 next. What a great time this is. All the open source and free stuff out there. I don’t even miss the old radio shacks any more.

wolframore:
C++ is so much easier than BASIC.

That's probably debatable - especially if you compare 90s BASIC to 90s C (did C++ exist already?), and it depends very much on the application.

I get blown away when you guys do direct port manipulation and using hex.

I prefer to use binary for that. Much more readable.

But there's better fun to be had - for a simple sensor library I used a 32-bit integer (unsigned long) as FIFO buffer. It sends bytes of the serial interface, and of course you can never be sure whether the first you get is really the first of a sequence. Solution: just shift bytes left until you have a working set of four bytes in that 32-bit integer :slight_smile:

wolframore:
I love the Arduino IDE. I started in BASIC with an Apple II plus back in the day. I’ve been wanting to get into programming stamps ever since the 90s but they were expensive. C++ is so much easier than BASIC.

I get blown away when you guys do direct port manipulation and using hex.

I think I’m going to an SoC like the nrf 51 and 52 next. What a great time this is. All the open source and free stuff out there. I don’t even miss the old radio shacks any more.

I started BASIC in 1980 on an S-100 bus 4 MHz 8085 with 32K RAM and 1 360K FD, "my" work machine. Prior to that I had a TI SR-59 on print cradle that I used to generate coordinates for tape control punch, mill and lathe. I had work to save and programming let me do it so I learned. I was also sharp at maths, logic and cards before I ever wrote computer code.

That 8085 at 4 MHz was not much better than a 6502 at 1 MHz. I've heard the hot chip was the 6809.

Hex just takes repeated use. It's 4 bits per digit that prints in 1 char space, put 0x before the hex and the compiler recognizes it. 0xF is 15 is 8+4+2+1 is 0b1111. It works the same in decimal 1234 is 1000+200+30+4, except more digits than 0 and 1. Hex is 0-9/A-F with A-F being 10 to 15.

Go to PJRC.com and look at the Teensy 3.6. It has an ARM with FPU for about $30.

I’m thinking the nRF 52 for BT 5.0. It’s so handy to have and 5.0 with long range promises 1000m with good antenna and open air. The M4 is just added bonus. Don’t need anything like that yet but who knows it’s a lot of processing and will come in handy one day. Did someone mention video or audio or high res IMU calculations?

You make hex sound almost easy.

4 bit hex digit can count from 0 to 15. You can do that with 4 fingers on 1 hand, count past ten with your shoes on!

0b1111 = 8 + 4 + 2 + 1 = 15

0b0000 = 0x0 = 0 ← no bits set
0b0001 = 0x1 = 1 ← low bit mask
0b0010 = 0x2 = 2
0b0011 = 0x3 = 3 ← low 2 bits mask
0b0100 = 0x4 = 4
0b0101 = 0x5 = 5
0b0110 = 0x6 = 6
0b0111 = 0x7 = 7 ← low 3 bits mask
0b1000 = 0x8 = 8 ← low 3 bits clear
0b1001 = 0x9 = 9
0b1010 = 0xA = 10
0b1011 = 0xB = 11
0b1100 = 0xC = 12
0b1101 = 0xD = 13
0b1110 = 0xE = 14
0b1111 = 0xF = 15 ← all bits set

0b10000 = 0x10 = 16 ← the lower 4 bits have rolled over

The rollover is important, you know that the lower pattern repeats.

Consider that a 12 hour clock uses base 12 to count hours and base 60 to count seconds. 12 is 0, you count around past 11 and you cross 0, rollover. You can count backwards through rollover too. If it is 3:00 and I put a roast in the oven at 11:00, I subtract 11 (start time) from 3 (end time) by moving the hand backwards 11 from 3 and get 4 for 4 hours since 11.

Look at the hex, it rolls over, goes around too. If it’s 3 and I put the roast in at 11 (0xB) then count 11 back from 3 (after 0, go to 0xF the top and keep counting down) and wind up at 8 with a 16 hour clock. From 0xB to 0x3 is 8 steps forward, count it and see.

If you get that then you get Arduino time and are not limited to using unsigned long. Arduino unsigned int (aka word) can time 65 seconds about twice as fast as unsigned long can. Who blinks leds for 60 second intervals? Or times debounce for more than 100 ms? Debounce can be timed with bytes.

I owned 4-bit programmable calculators. They did math using BCD, binary coded decimal where the 4 bits hold 0 to 9 and your numbers are stored in an array of BCD values operated on using pencil and paper math routines 1 digit at a time. Hey, 20 place mantissa with 3 place exponent that NEVER does what IEEE FP does does have a lot to say for itself.

You have to sit down and intentionally work with bits, make marks on paper, write some code just to get your head started with new ideas. Don’t grind, just make light impressions with short try and sees. You’ll know when you get familiar.