Square wave generator Arduino Mega 2560 // Rechtecksignalgenerator Arduino Mega

Hey guys,

i want to generate two square waves with variable frequencies (50% duty cycle and same amplitude). The problems is when i generate two square waves they need to have the same frequency, if not the signal does not match the given frequency. I dont understand this because the two output pins have different timers. I show you a simple code where i test this:

void setup() {
  // initialize digital pin 13 as an output.
  pinMode(11, OUTPUT);
  pinMode(2, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(11, HIGH);   // turn the LED on (HIGH is the voltage level)
  delayMicroseconds(125);              // wait for a second
  digitalWrite(11, LOW);    // turn the LED off by making the voltage LOW
  delayMicroseconds(125);              // wait for a second
   digitalWrite(2, HIGH);   // turn the LED on (HIGH is the voltage level)
  delayMicroseconds(125);              // wait for a second
  digitalWrite(2, LOW);    // turn the LED off by making the voltage LOW
  delayMicroseconds(125);              // wait for a second 
}

It is just a simple Blink Code, so i think the idea with delayMicroseconds is not that good. I get a hint to use ISR but dont know how to handle it. So my target is to get the variable frequency by a serial signal. And this should set the frequencies of the square waves. I need frequencies of about 400 Hz to 2600 Hz, so i think this should be possible with this board with no problems, i hope so. So does anybody have an idea which could help me? The following is in German, maybe there is someone who would like to write in german. Thank you for taking time.

best regards

Hallo Jungs,

also ich möchte gerne zwei variable Rechtecksignale mit verschiedenen Frequenzen generieren (der Tastgrad sollte 50% sein und die amplituden sollten gleich sein). Das Problem jedoch ist, dass wenn ich zwei Rechtecksignale generiere und sie nicht die selbe Frequenz haben dann stimmen die Frequenzen nicht. Dieses verstehe ich nicht da ja die beiden Outputs verschiedene Timer haben sollten sie doch unabhängig sein. Der nachfolgende Code stellt den Fall dar mit dem ich es getestet habe.

void setup() {
  // initialize digital pin 13 as an output.
  pinMode(11, OUTPUT);
  pinMode(2, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(11, HIGH);   // turn the LED on (HIGH is the voltage level)
  delayMicroseconds(125);              // wait for a second
  digitalWrite(11, LOW);    // turn the LED off by making the voltage LOW
  delayMicroseconds(125);              // wait for a second
   digitalWrite(2, HIGH);   // turn the LED on (HIGH is the voltage level)
  delayMicroseconds(125);              // wait for a second
  digitalWrite(2, LOW);    // turn the LED off by making the voltage LOW
  delayMicroseconds(125);              // wait for a second 
}

Das ist ein simpler Blink Code den ich bisschen verändert habe. Ich habe einen Tipp bekommen ISR zu nutzen jedoch weiss ich damit nicht umzugehen. Also mein Ziel ist es die variablen Frequenzen über eine serielle Leitung dem Board zuzuspielen und die Frequenzen der Rechtecksignale damit zu stellen. I benötige Frequenzen von ca. 400 Hz bis 2600 Hz, dass denke ich sollte möglich sein mit dem Board. Ich hoffe jemand hat eine gute Idee oder Vorgabe an die ich mich halten kann. Vielen Dank und Grüße im Voraus.

semo54:
The problems is when i generate two square waves they need to have the same frequency, if not the signal does not match the given frequency. I dont understand this because the two output pins have different timers.

What you write doesn't make sense in English as well as in German.

But there is one difference:

What you write in English doesn't make sense and is almost not understandable.
What you write in German doesn't make sense, but at least it is understandable for a German like me.

So I'm asking myself: Why don't you take part in the "Deutsch forum" where you could write in German?

Now something about the problem with your code: Your loop always generates one HIGH/LOW cycle on each pin during one run through your code, I added the etimated execution time as a comment to each line:

void loop() {
  digitalWrite(11, HIGH);   // takes 4µs
  delayMicroseconds(125);// takes 125µs
  digitalWrite(11, LOW);    // takes 4µs
  delayMicroseconds(125);// takes 125µs
   digitalWrite(2, HIGH);   // takes 4µs
  delayMicroseconds(125); // takes 125µs
  digitalWrite(2, LOW);    //  takes 4µs
  delayMicroseconds(125);   takes 125µs
}

Total execution time of your loop is 44µs + 4125µs = circa 516 µs.

So the frequency at both pins is ALWAYS the same, when you do it that way using "delay". And the duty cycle on any pin is never ever 50% as you want it.

So trying to generate two square wave frequencies this way is totally wrong.

If your requirements for correct frequency and correct duty cycle is low, then you could try that:

Create one square wave using hardware PWM and the Arduino tone function. Frequency may be a bit off, but duty cycle is 50%.

And create the second square wave using your beloved "delayMicroseconds()".

Normally, each and every "delay" is an absolutely forbidden function call that may not be used in any type of a "multi-tasking" sketch that has to handle more than one thing "at the same time".

At first thank you for your answer. You are right, i could post this on the german forum but i didnt know that it even exists. And i also know that i could explain my ideas a bit clearer sorry for that. I would like to mention here that this is my first Arduino experience, i am not even a programmer or something like that. I try to learn some new stuff by my study. So have a bit mercy on me please.

But to my topic, at first i must say it works. But i think it is not the smartest solution, i dont even request the best solution from you guys. This is enough for me at first. I also research the tone function and have some tests with it but the fact that it only can generate one square wave at once let me search for other solutions. I also think about to generate one square wave with tone function and the other with my "beloved" (haha laughed at this one) code before you post it. Anyway thank you again, and other ideas are welcome too.

best regards

semo54:
I also research the tone function and have some tests with it but the fact that it only can generate one square wave at once let me search for other solutions.

Although the tone library that is shipping with Arduino provides only one tone playing at a time, this is not the only tone library ever developed for Arduino.

This one was developed for older IDE versions before Arduino 1.0:
https://code.google.com/p/rogue-code/wiki/ToneLibraryDocumentation
(In fact the Arduino tone library is a simplified version derived from that library.)

With some efforts it would be possible to make this library compile with current version of Arduino and use at least a polyphonic dual-tone playing at the same time.

I will try my best to do this. Hope it will works.

best regards

semo54:
I will try my best to do this. Hope it will works.

It's not complicated, if you know how to do.

I made an example program for you, providing the patched "old" tone library and an example program for Atmega328 based boards.

The example program will generate two frequencies on two different pins, and set up two hardware interrupts to count rising flanks on those pins to count the actual frequency. The current count will be displayed once per second on Serial.

You don't have to install the library, just unpack the ZIP file in your sketch folder and open the ino sketch file. The library is then available on two extra tabs in the Arduino editor.

Tested with Arduino UNO and Arduino version 1.0.5.
Should work with other Atmega328 boards and other versions of Arduino as well.

Will need small changes for boards which have another Atmega controller.

toneDualTone.zip (4.74 KB)

Sorry for writing so late, but i try the uploaded code on my Arduino MEGA 2560 (which got a Atmega 2560 controller) and it works well. I dont know why there is a interrupt function because it work also without it. I can generate frequencies from 40 Hz to approx. 8000 Hz which is absolutely enough for my application.

The next step is to make these frequencies variable and dependent from the serial communication. Because i want to set the frequencies from matlab by the serial communication. Maybe now my project is a little bit clearer. I want to run a simulation on matlab and send over the serial communication the frequencies to the arduino board and set the frequency of the square wave.

Now i have to read the serial message with arduino, but have problems with reading the message sent because it is not an integer. I think it is a string and i have to change it to an integer. i try it with toInt() function but it doesnt work.

Now i have to look forward, thank you anyway it was very helpful "jurs".

best regards

Hi,

its me again. I would like to share some thoughts made during my testings. So i try to set the frequency with the given tone library over a serial communication. When i send just one serial message, it directly changes the frequency of the square wave. But when i send the same message faster than once per second then the square wave doesnt get generated. I just cant see any signal on my oscilloscope, when i stop sending serial messages the constant frequency square wave come back after a few seconds. So i think the tone function is not able to deal with quick changing frequencies. I cant explain it anyway, may someone have an opinion?

best regards

P.S I forget that i use a Arduino Mega 2560, maybe it could be because of that. The tone library was written for Atmega328 Boards i guess. But i can use the tone function, except of the fact that it is not able to set frequencies quickly.

[/code
#include "OldTone.h"

Tone tone1;
Tone tone2;

unsigned char x1;
int freq=100;

void setup() {
  Serial.begin(9600);
  tone1.begin(2); // playing tone1 on pin-2
  tone2.begin(3); // playing tone2 on pin-3
 // tone1.play(500);
 // tone2.play(2500);
 
}


void loop() 
{
  if(Serial.available()>0){
    
    x1=Serial.read();
    freq=map(x1, 0, 255, 0, 2600);
  }
 tone1.play(freq);
 tone2.play(1000);
   

}]

semo54:
So i think the tone function is not able to deal with quick changing frequencies. I cant explain it anyway, may someone have an opinion?

You can easily measure how long it takes for the play() function to recalculate and change Timer settings.

This will randomly change the frequency 1000 times and set to random frequencies in the range from 32 to 2531 Hz:

  randomSeed(analogRead(A0));
  unsigned long timer=micros();
  for (int i=0;i<1000;i++) tone2.play(32+random(2500));
  timer=micros()-timer;
  Serial.print(timer/1000.0);Serial.println(" microseconds per frequency change");
  while(1);

Execution time for play() function is ca. 200 µs when using tone2 (Timer1) and ca. 310 µs when using tone1 (Timer0).

I don't know what you are sending across Serial, but if you should send bytes from 0 to 255, this is surely wrong:

freq=map(x1, 0, 255, 0, 2600);

The mapping range is then starting from zero, but you most likely want higher frequencies than 32 Hz. Perhaps:

freq=map(x1, 0, 255, 32, 2600);

From what I can see, the "map()" function to calculate your range will cause much longer execution time than the play() function.

And you should consider: When changing the play() frequency, each time a new wave generation starts. So if you should start a new wave using the play() function, while less than half of the cycle time has passed, the output state will never change. A change of the output state of the square wave will only happen after 'cycletime/2', but if you reset the wave generation before 'cycletime/2', what do you think will happen? 'cycletime/2' will then never be reached, so the square wave never changes its state.

I'd use timers other than 0 (or even the same timer, if you need them to always have the same frequency), and control the registers directly, instead of trying to bitbash it with delays - that won't give acceptable results if you're using digitalWrite() (as it takes a few microseconds to run - i think someone said 50-some clock cycles), and keeps the part busy when you could have the timers doing it for you in the background (that's what they're for).

DrAzzy:
I'd use timers other than 0

I see, I think in my reply #8 I mixed up something with the timer numbers.
The old tone library uses this sequence for generating tones:

// Leave timer 0 to last.
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2, 1, 0 };

So tone1 is generated by Timer2 and tone2 is generated by Timer1.

So at first i change the output pins to tone1 at pin 8 and tone2 at pin 3 to have different timers, so the square wave cant be affected of any inteference in the timer. (maybe it is not even necessary but i do it to be sure)

Execution time for play() function is ca. 200 µs when using tone2 (Timer1) and ca. 310 µs when using tone1 (Timer0).

And you should consider: When changing the play() frequency, each time a new wave generation starts. So if you should start a new wave using the play() function, while less than half of the cycle time has passed, the output state will never change.

I measure a execution time on pin 9 (Timer 2) of ca. 152 us and on pin 3 (Timer 3) it needs 256 us. I also measure the time for the map() and serial.red() function and it is only 1,75 us.

So i think it must be possible to send a serial message ( in my case i send a byte fro 0-255) every millisecond and change the frequency. I also think that the new wave generation is after cycle/2, but i am not sure about it. It could be possible that "jurs" is right, because when i send a serial message every second the frequency changes like i would. But when i increase the "frequency" of sending serial messages like to 500 milliseconds the square wave is steady at 0. When i am not wrong the problem is than that the tone() function start a new wave at every execution, but it has to take the state before and just increase oder decrease the frequency of the wave.

For a better understanding i explain what my target is. Think of a rev-sensor from a car that creates a square wave for every revolution of the engine. Like 1000 rev/min is figured by a 400 Hz square wave and when the revolution speed of the engine changes the square wave changes to. I would like to realize something like this, just give the frequency order from a serial message. That worked so far but i only can send one message per second and thats a bit slow. Do i make a general mistake anywhere?

best regards

semo54:
Do i make a general mistake anywhere?

Most likely.

The original libary is for playing audio sound. Typical audio sound can easily go at 180 "beats per minute" or more, which stands for "180 quarter notes per minute", which is 3 quarter notes per second. And as that library should easily be able to play 1/16 notes or even 1/32 notes, there should be absolute no problem changing the played frequency 24 times per second.

So if the library is intended for "at least 24 frequency changes per second" and you even cannot get "more than 1 frequency change per second", you surely must be doing wrong.