Discussion board help and admin topics > Problems and Solutions for Accurate Measurements

Arduino signal generator

(1/9) > >>

ayeaye:
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();
}
--- End quote ---

Tink:
Thanks! :D
I made a copy of it.

MagnaProp:
Thanks for posting the code!

ronotte:
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:

--- Quote from: ayeaye 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.

--- End quote ---

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.

Navigation

[0] Message Index

[#] Next page

Go to full version