ofArduino tone() function or setting PIN HIGH & LOW with delay inbetween?

Dear openFrameworkers,

I’m trying to use Arduino’s tone() function or something similar with openFrameworks’ ofArduino and Arduino’s simpleDigitalFirmata, but I just don’t get it. Could anyone please help with this?

In Arduino, the tone function can be called like this:

void loop() {
  tone(PIN, FREQUENCY, DURATION);
}

… and almost the same could be achieved with:

void loop() {
  pinMode(PIN, OUTPUT);
  digitalWrite(PIN, HIGH);
  delay(FREQUENCY / 2);
  digitalWrite(PIN, LOW);
  delay(FREQUENCY / 2);
}

In openFrameworks, I think the closest I came up with is this solution, which sets the PIN HIGH & LOW for 3000 milliseconds, but there is not delay in between HIGH & LOW:

unsigned long int millis = ofGetElapsedTimeMillis();
while (millis < millis + 3000) {
    arduino.sendDigitalPinMode(11, ARD_HIGH);
    arduino.sendDigitalPinMode(11, ARD_LOW);
}

Looking forward to your advice and thank you in advance!

There is a slight problem with tone in firmata but there is a branch that implements it. https://github.com/firmata/arduino/tree/tone-standard-firmata

You would have a hard time achieving this accurately with normal firmata since the delay time is not consistent between the serial data packets and is even more unlikely using that method you illustrate though there are examples of making it work. https://github.com/rwaldron/johnny-five/blob/master/lib/piezo.js

Your options are essentially extend the ofArduino to include compatibility with the tone functionality of that branch of firmata or implement your own primitive communication protocol.

To do the latter look at the serial example that is in the examples folder. you can send data to the arduino to set the tone frequency and length which is probably the best route to take for this and will be the easiest. Trying to do this manually will not work consistently.

Hey DomAmato,

so if I get this right, either use the first link you provided or use/work with the serial example. You think the serial example would perform better?

BTW, I just realize that my while loop doesn’t make any sense.

Hey again,

if I didn’t get the ofSerial example wrong, all I have to do in openFrameworks is writing ‘1’ to serial via:

if (serial.isInitialized()) {
  serial.writeByte('1');
}

(BTW, how would this be possible with a boolean value?)

… and in Arduino:

const int pin = 11;
const unsigned int frq = 32;
const unsigned long dur = 1000;

void setup() {
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0) {
    if (Serial.read() == '1') {
      tone(pin, frq, dur);
    }
  }
}

And then Arduino plays the tone for the defined duration?

PS: I cannot try this right now, but I will do so in university in about three hours!

PPS: Seems to work!

Yeah that should work though you can also pass in more parameters. like

if (serial.isInitialized()) {
  serial.writeByte('1'); //the flag byte
  serial.writeByte('3'); //this is the pin
  serial.writeByte('800'); //this is the frequency
  serial.writeByte('1000'); //this is the duration
}

That is how Firmata works in a nut shell. It sends a flag for what kind of action to perform and then reads from the buffer until a stop flag is sent. You probably don’t need to do something that complex but it would allow you some extra control of the tone should you desire it. the reason I suggest using ofserial is that it is more flexible. Firmata has a pretty strict protocol and with this you can be much looser and not have to change any core library code to get things to work :slightly_smiling:

That sounds good!

Probably I should I stay in range of a byte, so 0—255. Though I can’t imagine, how Arduino knows, where to put each byte, or in which variable to store which byte. And … I’m not exactly sure what you mean by the ‘flag byte’ … like it’s the trigger for executing the Arduino code?

Kindest regards and thank you very much!

Ok, it seems the answer is a little more complicated.

The first thing is, ofSerial cannot directly send a string, that’s why I had to use the following code by @kylemcdonald

    if (serial.isInitialized()) {
        //serial.writeByte('1');
        string msg = "<" + ofToString(ARDUINO_PIN) + "," + ofToString(ARDUINO_FREQUENCY) + "," + ofToString(ARDUINO_DURATION) + ">";
        unsigned char* msguc = new unsigned char[msg.size()];
        memcpy(msguc, msg.c_str(), msg.size());
        serial.writeBytes(msguc, msg.size());
        delete [] msguc;
        cout << msg << endl;
    }

Then, in Arduino, when the start-of-packet character appears, store the characters in a string until the end-of-packet character appears. Also, split the string by delimiter. Thanks to PaulS for these snippets.

Any improvements, anyone?

thats actually probably a bad idea to convert it into a string since you are using up way more bytes than you need during transfer. Look at how the tone protocol works in firmata: https://github.com/firmata/protocol/blob/master/tone-proposal.md

// wrapper for tone function
0  START_SYSEX        (0xF0)
1  TONE_DATA          (0x5F)
2  TONE               (0x00)
3  pinNumber
4  frequency LSB      (in HZ)
5  frequency MSB      (in HZ) (audible range is 20 HZ to 15,000 HZ so 14 bits is sufficient)
6  duration bits 0-6  (in ms)
7  duration bits 7-14 (in ms) (max duration is 16,383 milliseconds)
11  END_SYSEX (0xF7)

This is what I meant by flag bit is the start-sysex flag, the tone data tells it what kind of message it is getting, the tone tells it that it needs to make a sound. Then the pin, the frequency which is split into 2 7bit bytes and the same for the duration. You could easily adapt this to your need and even get rid of the tone data and tone flag. This is how firmata handles it.

void sysexCallback(byte command, byte argc, byte *argv)
{
  byte mode;
  byte slaveAddress;
  byte data;
  int slaveRegister;
  unsigned int delayTime;

  switch (command) {
    case TONE_DATA:
      if (argc > 1) {
        byte toneCommand = argv[0];
        byte pin = argv[1];
  
        if (toneCommand == TONE_TONE && argc > 5) {
          unsigned int frequency = argv[2] + (argv[3] << 7);
          // duration is currently limited to 16,383 ms
          unsigned int duration = argv[4] + (argv[5] << 7);
          setPinModeCallback(pin, TONE);
          tone(pin, frequency, duration);
        }
        if (toneCommand == TONE_NO_TONE) {
          noTone(pin);
        }
   }
}

This method is probably more complex than you need but since the tone does exist for firmata you could upload the standard firmata from that branch and then use ofArduino and when you need to make a tone call a function that looks like so:

void ofApp::makeTone() {
  myOfArd.sendByte(FIRMATA_START_SYSEX);
  myOfArd.sendByte(0x5F);
  myOfArd.sendByte(0x00);
  myOfArd.sendByte(pin#);
  myOfArd.sendValueAsTwo7bitBytes(frequency);
  myOfArd.sendValueAsTwo7bitBytes(duration);
  myOfArd.sendByte(FIRMATA_END_SYSEX);
}

I sorta feel like im talking in circles but I had suggested using ofSerial so that you could make your own implementation but looking at it now this function is really simple

Thanks for explaining this, it really helps me understanding these things!

Though, unfortunately, I noticed yesterday, that I cannot use Arduino’s tone() function—simply because I cannot use a frequency lower than 31 Hz, which I need for my project. The speaker just needs to vibrate, so I can use HIGH-delay-LOW-delay and use longer delays between both states than with the lowest usable frequency.