Storing Cookies (See : http://ec.europa.eu/ipg/basics/legal/cookies/index_en.htm ) help us to bring you our services at overunity.com . If you use this website and our services you declare yourself okay with using cookies .More Infos here:
https://overunity.com/5553/privacy-policy/
If you do not agree with storing cookies, please LEAVE this website now. From the 25th of May 2018, every existing user has to accept the GDPR agreement at first login. If a user is unwilling to accept the GDPR, he should email us and request to erase his account. Many thanks for your understanding

User Menu

Custom Search

Author Topic: Arduino signal generator  (Read 32087 times)

ayeaye

  • Hero Member
  • *****
  • Posts: 866
Arduino signal generator
« on: October 27, 2016, 08:33:55 PM »
I will put it here so that it will not be lost. This signal generator is capable of generating square wave with a varying duty cycle, from 4 Hz to 8 MHz, on the Arduino pin d10. The frequency comes from the Arduino 16 MHz clock frequency, which is generated by quartz, thus should be accurate. It was necessary to calibrate my oscilloscope. I used for that Arduino Nano, that i bought from eBay for $2.30, but the same must work for Arduino Uno, and several other varieties.
Quote
#include <avr/sleep.h>

#define BUFSIZE 80

char buffer[BUFSIZE];

void setup()
{
   Serial.begin(9600);
   pinMode(10, OUTPUT);
}

void loop()
{
   float frequency0, frequency1, duty0, duty1;
   unsigned long period, duty, clock;
        char ch;

   duty0 = 0;
   frequency0 = 0;
   Serial.print("Frequency? \n");
        sprintf(buffer, "");
        while (strlen(buffer) < BUFSIZE - 1)
                if (Serial.available()) {
                        ch = Serial.read();
                        if (ch == '\n') break;
                        sprintf(buffer, "%s%c", buffer, ch);
        }
        frequency0 = atof(buffer);
   Serial.print("Duty Cycle? \n");
        sprintf(buffer, "");
        while (strlen(buffer) < BUFSIZE - 1)
                if (Serial.available()) {
                        ch = Serial.read();
                        if (ch == '\n') break;
                        sprintf(buffer, "%s%c", buffer, ch);
        }
        duty0 = atof(buffer);
   if (duty0 < 0) duty0 = 0;
   if (duty0 > 100) duty0 = 100;
        clock = 16000000l;
        if (frequency0 < 300.) clock = 250000l;
          period = int(clock / frequency0);
          if (period < 2) period = 2;
        if (period > 65000) period = 65000;
          frequency1 = (double) clock / period;
          duty = int(period * duty0 / 100);
         if (duty < 1) duty = 1;
          if (duty > period - 1) duty = period - 1;
         duty1 = duty * 100. / period;
         OCR1A = period - 1;
          OCR1B = duty - 1;
   /* Timer1 fast PWM mode */
   TCCR1A = _BV(WGM11) | _BV(WGM10) | _BV(COM1B1);
        if (frequency0 > 300.)
                /* No prescaling */
                  TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
        else
                /* 64 prescaling */
           TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10) | _BV(CS11);
   Serial.print("Frequency ");
        Serial.print(frequency1);
        Serial.print(", Duty Cycle ");
        Serial.println(duty1);
   Serial.println();
   delay(100);
   while (!Serial.available()) {
      set_sleep_mode(SLEEP_MODE_IDLE);
      sleep_enable();
      sleep_mode();
      sleep_disable();
   }
   TCCR1A = _BV(WGM11) | _BV(WGM10) | _BV(COM1B1);
   TCCR1B = _BV(WGM13) | _BV(WGM12);       /* Timer stop */
   TCNT1 = 0;                      /* Timer value 0 */
   digitalWrite(10, 0);                   /* Output 0 */
   Serial.read();
}

Tink

  • Full Member
  • ***
  • Posts: 222
Re: Arduino signal generator
« Reply #1 on: October 27, 2016, 09:07:34 PM »
Thanks! :D
I made a copy of it.

MagnaProp

  • Sr. Member
  • ****
  • Posts: 431
Re: Arduino signal generator
« Reply #2 on: October 30, 2016, 12:42:19 AM »
Thanks for posting the code!

ronotte

  • elite_member
  • Sr. Member
  • ******
  • Posts: 417
Re: Arduino signal generator
« Reply #3 on: October 30, 2016, 04:52:10 PM »
Hi all,

it could be interesting to know that it is possible to setup a single frequency precision oscillator (with high stability). It uses an Arduino uP to program via the internal I2C interface an oscillator IC like DS1077. In such a case it is only necessary to write a program on arduino to setup the internal programmable frequency divider (in DS1077 chip). After the write operation you can detach the DS1077 chip and use it for your application simple & elegant & easy...This is a professional generator to be used intead of 555 chip or similar. Frequency spans up to 100 MHz range. I used it to generate high precision low frequency square wave needed by a TMT project. In case you are interested I can publish the code.

Ciao
ronotte

TinselKoala

  • Hero Member
  • *****
  • Posts: 13958
Re: Arduino signal generator
« Reply #4 on: October 31, 2016, 03:38:57 AM »
I will put it here so that it will not be lost. This signal generator is capable of generating square wave with a varying duty cycle, from 4 Hz to 8 MHz, on the Arduino pin d10. The frequency comes from the Arduino 16 MHz clock frequency, which is generated by quartz, thus should be accurate. It was necessary to calibrate my oscilloscope. I used for that Arduino Nano, that i bought from eBay for $2.30, but the same must work for Arduino Uno, and several other varieties.

I tried it on a genuine Italian-made UNO R3. The code compiles but with several "warnings" that don't cause the compiler to stop.
I couldn't get it to work at first, it would simply hang after printing "frequency" to the serial monitor. So I discovered that the Serial Monitor "send" needs to end with a CR or CR/LF rather than just the plain number string. This is a selectable option in the Arduino IDE Serial Monitor. So once I selected "CR" and sent, say, "1000000" it replied with "duty cycle" and so I put in "50" and it worked, sent a pretty nice square wave to the oscilloscope.
BUT--- it did not work properly at low frequencies, giving strange results. I didn't explore just where the strange results started, but it certainly got weird when under 10 kHz. Sometimes the Serial Monitor string reported numbers that I didn't enter as freq and duty cycle, and often the reported numbers did not agree with the resulting signal as shown on the scope. At really low frequencies like 4Hz or 10Hz it did not produce oscillations at all, the output signal just stayed high.
But at higher frequencies it worked fine and the scope showed it to be accurate in terms of duty cycle and frequency.

TinselKoala

  • Hero Member
  • *****
  • Posts: 13958
Re: Arduino signal generator
« Reply #5 on: October 31, 2016, 04:01:04 AM »
Here are some examples. The numbered screenshots and the Serial Monitor window of the same number.

In the last one (45) I actually entered 2520000 for the frequency -- and look what the program gave me!

ayeaye

  • Hero Member
  • *****
  • Posts: 866
Re: Arduino signal generator
« Reply #6 on: October 31, 2016, 06:23:23 AM »
I don't know whether your scope is capable of 4 Hz, mine is not. So i tested 10 Hz, and it was correct, though i couldn't trigger it. I also tried 100 Hz and 200 Hz with various duty cycles, different from your results all was correct. So the problems you had, i couldn't reproduce.

I'm sorry, there is one bug though

period = int(clock / frequency0);

there, using int() is wrong, because the period can be more than the maximum int, instead a cast (unsigned long) should be used there. But this affects only frequencies below 8 Hz, and 300 to 500 Hz. So as it was, it worked only in the frequency ranges 8 Hz to 299 Hz, and 500 Hz to 8 MHz, again sorry for that. The code with that fixed

Quote
#include <avr/sleep.h>

#define BUFSIZE 80

char buffer[BUFSIZE];

float getvalue(char *text)
{
   char ch;

   Serial.print(text);
   sprintf(buffer, "");
   while (strlen(buffer) < BUFSIZE - 1)
      if (Serial.available()) {
         ch = Serial.read();
         if (ch == '\n') break;
         sprintf(buffer, "%s%c", buffer, ch);
      }
   return atof(buffer);
}

void setup()
{
   Serial.begin(9600);
   pinMode(10, OUTPUT);
}

void loop()
{
   float frequency0, frequency1, duty0, duty1;
   unsigned long period, duty, clock;

   frequency0 = getvalue("Frequency? \n");
   duty0 = getvalue("Duty Cycle? \n");
   if (duty0 < 0) duty0 = 0;
   if (duty0 > 100) duty0 = 100;
   clock = 16000000l;
   if (frequency0 < 300.) clock = 250000l;
   period = (unsigned long) (clock / frequency0);
   if (period < 2) period = 2;
   if (period > 65000l) period = 65000l;
   frequency1 = (double) clock / period;
   duty = (unsigned long) (period * duty0 / 100);
   if (duty < 1) duty = 1;
   if (duty > period - 1) duty = period - 1;
   duty1 = duty * 100. / period;
   OCR1A = period - 1;
   OCR1B = duty - 1;
   /* Timer1 fast PWM mode */
   TCCR1A = _BV(WGM11) | _BV(WGM10) | _BV(COM1B1);
   if (frequency0 > 300.)
      /* No prescaling */
      TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
   else
      /* 64 prescaling */
      TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10) | _BV(CS11);
   Serial.print("Frequency ");
   Serial.print(frequency1);
   Serial.print(", Duty Cycle ");
   Serial.println(duty1);
   Serial.println();
   delay(100);
   while (!Serial.available()) {
      set_sleep_mode(SLEEP_MODE_IDLE);
      sleep_enable();
      sleep_mode();
      sleep_disable();
   }
   TCCR1A = _BV(WGM11) | _BV(WGM10) | _BV(COM1B1);
   TCCR1B = _BV(WGM13) | _BV(WGM12);   /* Timer stop */
   TCNT1 = 0;            /* Timer value 0 */
   digitalWrite(10, 0);         /* Output 0 */
   Serial.read();
}

MagnaProp

  • Sr. Member
  • ****
  • Posts: 431
Re: Arduino signal generator
« Reply #7 on: October 31, 2016, 07:25:08 AM »
Hi all,

it could be interesting to know that it is possible to setup a single frequency precision oscillator (with high stability). It uses an Arduino uP to program via the internal I2C interface an oscillator IC like DS1077. In such a case it is only necessary to write a program on arduino to setup the internal programmable frequency divider (in DS1077 chip). After the write operation you can detach the DS1077 chip and use it for your application simple & elegant & easy...This is a professional generator to be used intead of 555 chip or similar. Frequency spans up to 100 MHz range. I used it to generate high precision low frequency square wave needed by a TMT project. In case you are interested I can publish the code.

Ciao
ronotte
Sounds interesting to me. Posting your code would be greatly appreciated.

ronotte

  • elite_member
  • Sr. Member
  • ******
  • Posts: 417
Re: Arduino signal generator
« Reply #8 on: October 31, 2016, 11:35:13 AM »
OK here you find a paper containing detailed info about DS1077 programming and a practical code that is still in use...hence fully debugged. The project is dated 2014 and has been tested on Arduino Due uP board. I think that it could run easily on all Arduino family: just check the I2C pin availability.
The code is emebedded with debugging lines very useful to have a direct view (on the serial console) of what is happening!.

ayeaye

  • Hero Member
  • *****
  • Posts: 866
Re: Arduino signal generator
« Reply #9 on: October 31, 2016, 09:15:28 PM »
Here are some examples. The numbered screenshots and the Serial Monitor window of the same number.

In the last one (45) I actually entered 2520000 for the frequency -- and look what the program gave me!

Yes, i could now reproduce. The matter is, the frequencies were wrong when generating signal the first time after starting the serial monitor, they were right every next time. The order in which to assign the registers matters. What concerns the frequency 2520000 Hz then, because of the discreteness of the timer period, it is not able to provide an exact frequency with so high frequencies. Calculate, the period should be 16000000 / 2520000 = 6.349, but because period must be integer, it's 6. Then the frequency generated, is 16000000 / 6 = 2666666.7, as it was. This is the code with that fixed, it provided the right frequency the first time, every time i tested it.

Quote
#include <avr/sleep.h>

#define BUFSIZE 80

char buffer[BUFSIZE];

float getvalue(char *text)
{
   char ch;

   Serial.println(text);
   sprintf(buffer, "");
   while (strlen(buffer) < BUFSIZE - 1)
      if (Serial.available()) {
         ch = Serial.read();
         if (ch == '\n') break;
         sprintf(buffer, "%s%c", buffer, ch);
      }
   return atof(buffer);
}

void setup()
{
   Serial.begin(9600);
   pinMode(10, OUTPUT);
}

void loop()
{
   float frequency, duty;
   unsigned long clock, period, pulsewidth;

   frequency = getvalue("Frequency?");
   duty = getvalue("Duty Cycle?");
   if (duty < 0) duty = 0;
   if (duty > 100) duty = 100;
   clock = 16000000l;
   if (frequency < 300.) clock = 250000l;
   period = (unsigned long) (clock / frequency);
   if (period < 2) period = 2;
   if (period > 65000l) period = 65000l;
   pulsewidth = (unsigned long) (period * duty / 100);
   if (pulsewidth < 1) pulsewidth = 1;
   if (pulsewidth > period - 1) pulsewidth = period - 1;
   /* Timer1 fast PWM mode */
   TCCR1A = _BV(WGM11) | _BV(WGM10) | _BV(COM1B1);
   if (frequency > 300.)
      /* No prescaling */
      TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
   else
      /* 64 prescaling */
      TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10) | _BV(CS11);
   OCR1A = period - 1;
   OCR1B = pulsewidth - 1;
   Serial.print("Frequency ");
   Serial.print((float) clock / period);
   Serial.print(", Duty Cycle ");
   Serial.println(pulsewidth * 100. / period);
   Serial.println();
   delay(100);
   while (!Serial.available()) {
      set_sleep_mode(SLEEP_MODE_IDLE);
      sleep_enable();
      sleep_mode();
      sleep_disable();
   }
   TCCR1A = _BV(WGM11) | _BV(WGM10) | _BV(COM1B1);
   TCCR1B = _BV(WGM13) | _BV(WGM12);   /* Timer stop */
   TCNT1 = 0;            /* Timer value 0 */
   digitalWrite(10, 0);         /* Output 0 */
   Serial.read();
}

TinselKoala

  • Hero Member
  • *****
  • Posts: 13958
Re: Arduino signal generator
« Reply #10 on: November 01, 2016, 01:52:59 AM »
You still have quite a few compiler warning messages. To see them in your IDE, select File>Preferences then check the "Show verbose output during compilation" box. They don't prevent a successful compile but they may be causing problems in how the sketch actually works.

I'll be testing this new version later on this evening. Thanks for your good work!

Magluvin

  • Hero Member
  • *****
  • Posts: 5884
Re: Arduino signal generator
« Reply #11 on: November 01, 2016, 02:24:05 AM »
This is a tiny oscope with arbitrary wave form gen up to 44khz analog and 1mbps max. Bought one a few years ago. This can interface with pc with gabos software download on that page. the make larger ones also as the screen on this is too small to strain your eyes on but the pc interface software works pretty good.
http://www.gabotronics.com/development-boards/xmega-xprotolab.htm
$49

Mags

TinselKoala

  • Hero Member
  • *****
  • Posts: 13958
Re: Arduino signal generator
« Reply #12 on: November 01, 2016, 03:58:34 AM »
OK, I've done some testing of the new code. It does work better, at least at low frequencies.

But there is still some problem. At higher frequencies it does not do the duty cycle correctly. For example I input "8000000" for frequency and "33" for duty cycle and it gives me a 50 percent duty cycle. Or, if I don't reset the Arduino and put in 8000000 and 33 as a second setting, it gives me 125000 and 50. If I reset and put in 2520000 and 33, it gives me Frequency 2666666.75, Duty Cycle 16.67 .

The signal sent to the scope agrees with the Serial Monitor, but the program often gives me something other than what I put in as freq and duty cycle. Also it behaves differently if I reset the arduino before a new setting, than it does if I do not reset the arduino before a new setting.

But at least it oscillates at low frequencies now.

ayeaye

  • Hero Member
  • *****
  • Posts: 866
Re: Arduino signal generator
« Reply #13 on: November 01, 2016, 05:19:50 AM »
For example I input "8000000" for frequency and "33" for duty cycle and it gives me a 50 percent duty cycle. Or, if I don't reset the Arduino and put in 8000000 and 33 as a second setting, it gives me 125000 and 50.

I'm afraid that i cannot reproduce again. I tested it without oscilloscope. I copied the exact code from here, compiled it, uploaded to the Arduino. Started the serial monitor, entered frequency 8000000 and duty cycle 33. It showed frequency 8000000 and duty cycle 50. Then i again entered the frequency 8000000 and duty cycle 33, without restarting the serial monitor, and it again showed frequency 8000000 and duty cycle 50, not frequency 125000 and duty cycle 50 as you said. So i could not reproduce it behaving differently when resetting and when not resetting.

What concerns the program giving something other than put in, then one reason why it certainly happens is because it is limited by discreteness. Like with the frequency 8000000, the duty cycle can only be 50, because with the Arduino clock frequency 16 MHz. the timer can only go two steps. With the frequency 2520000 and duty cycle 33, the pulse width has to be integer. The period as integer is 6, and 33 percent of it when truncated is 1, which is 16.7% of 6. It is not good that it is truncated and not rounded, but this is a simple program.

Thank you for testing.

verpies

  • Hero Member
  • *****
  • Posts: 3473
Re: Arduino signal generator
« Reply #14 on: November 01, 2016, 10:19:33 AM »
At higher frequencies it does not do the duty cycle correctly. For example I input "8000000" for frequency and "33" for duty cycle and it gives me a 50 percent duty cycle.
Of course because the 16MHz Arduino clock is not capable of providing more than 50/50 precision at 8MHz output.