Tone on 2 pins simultaneously

Is there any need to use an interval of Micros as signed?

void setup() {
  Serial.begin(115200);
  test(100);
  test(16);
  test(15);
  
}

void loop() {
  // put your main code here, to run repeatedly:

}

void test(int frequncy){
   int  intervalMicros = ((1000000 / (frequncy*2))/4)*4;
   Serial.print(frequncy);
   Serial.print("\t");
   Serial.println(intervalMicros);
}

Result:

100	5000
16	31248
15	-32204

If you'd declare intervalMicros as uint16_t you'll get

100	5000
16	31248
15	33332

Maybe it's not really a problem if you avoid low frequencies.

Though it works here I would feel safer to use (unsigned) long and also UL at the end of the number like this

unsigned long  intervalMicros = ((1000000UL / (frequncy*2))/4)*4;

to avoid painful debugging sessions.

1 Like

Ok!
Thank you!
It is not that it need to be signed(I have no idea what that actually means), It is that I did not know a better way.....
I will follow your last suggestion.
What would be the results of the last one?

Oops, the knowledge about data types is crucial for programming ...

Go to https://www.arduino.cc/reference/en/
and then scroll down to "Variables", look for Data Types and click on byte, int etc.

You will find comprehensive information there!

In short:

  • Signed integers can be less than zero, zero or larger than zero
  • Unsigned integers can be zero or larger (never below zero)

The reason is that the highest bit of integers can be used for either more numbers (in fact doubling) or be used as a "minus" marker. So if two integer data types use the same number of bits (e.g. 16) the unsigned one can use the full 16 bit range from 0 ... 65535 to represent positive numbers. The signed one has one bit less (used to mark "minus" if set to 1 and therefore has only a 15 bit range for numbers so the value can go from -32768 up to 32767.

If you go above 32767 the value will be displayed and calculated as a minus value.

void setup() {
  Serial.begin(115200);
  int i = 32767;
  Serial.println(i);
  i++;
  Serial.println(i);
}

void loop() {

}

Result:

32767
-32768

And be aware that the absolute value of i drops the more you add!!
If you use (10 + 32767) for i you'll get -32759 etc.

int i = 65535 represents -1...

1 Like

If the number is frequency then it cannot be negative. It is cycles per second.

How do you get that value? As frequency or something else that gets turned into frequency?

1 Like

One way to go would be to use a dedicated library like Mozzi in Stereo Mode.

I

The frequency variable is the actual frequency…
I think.
Then I used your calculations to make that.
I will use:


unsigned long  intervalMicros = ((1000000UL / (frequncy*2))/4)*4;

As suggested by @ec2021

Yeah mask the low two bits... just like micros() and you get 250 usec intervals. 1/4 msec.

And if you mask the low byte of millis() the interval is 250 msec with no +/- 1. 1/4 sec.

If I design to those units, the values are decimal, not binary.
They fit the Arduino niche very well actually, like it was planned. ;^)

The answer is with signed integers I would mask, not shift a sign bit.

But if the tone was relative to middle C, some kind of negative could be converted to a frequency. But me, I'd make a 1D LUT of micros time for 88 notes.

The micros timing end - start = elapsed math even using 16 bit timing will be the cycle hog part hey?

1 Like

Sorry, there are 250 4 usec intervals in a millisec. Not 1/4 but 1/250.
Count 250 of those to get 1 ms. Is decimal.
Bit 8 of millis() flips every 250 ms. Also decimal.

and micros changes every 4 usecs. That's the grain. 1952 is the closest 4 us to 1953. The math will go faster as clock ticks than usecs so unsigned mask off the low 2 is 1 cycle and shifts happen 1 cycle per bit my earlier /4 * 4 might compile to 4 cycles or more... my bad.

You got it... That's what this thread is all about ... :wink:

I checked it and found that masking or shifting works as well for negative integers as for positive.

It just looks weird on the first glance but "rounding off" for negatives may end up with higher absolute values, e.g.

-20 --> - 20
-21 --> - 24
-22 --> - 24
-23 --> - 24
-24 --> - 24

etc.

So no worries! I second your post about the identical results if the different methods, finally you and @GoForSmoke are supporting the same idea, and the method is only a question of efficiency (I think dividing and multiplying by 4 will be solved by shifting anyway).

Actually the use of unsigned integer and UL for the magic number in the code seems not to be necessary in this specific case but is just safer. So my contribution is only marginal.

Off topic: I fully understand your intention to guard your answers. I guess it's something we have to live with and take it easy ... I enjoy to see how enthusiastic people like you, @GoForSmoke, @paulpaulson and many other well known members support others and learned a lot here. Nobody's perfect ... Let us always be kind and supportive ...

1 Like

Or skip all of that and make an array of interval micros values in PROGMEM? Of course write a sketch to print the table, lol.

Middle C at 1952 us ON <==> OFF intervals for when.
With a 2D array the ON time could be shorter, might reduce volume.

Writes to the PIN register perform a bitwise XOR on PORT register bits. 0 bits don't change the matching PORT buts but 1's do. 1 cycle, you write the mask instead of read-mask-write on PORT reg.

I would make micros time intervals multiples of four to match the clock ticks. Middle C is just 1 note.

1 Like

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