2

I would like to generate a sine wave with my Arduino Uno. As far as I know, there is no library for Uno to generate such a signal (correct me if I'm wrong), so the only option available is to write a function to generate the signal from scratch.

As far as my understanding of digital electronics goes, I believe it is possible to generate a sine wave signal by using PWM and varying the duty cycle accordingly. However, this route seems to me quite long, what other options do I have?

4 Answers 4

5

As far as I know, there is no library for Uno to generate such a signal (correct me if I'm wrong)

You are wrong, there is Mozzi, the sound synthesis library for Arduino. It works essentially along the lines sketched by uint128_t. Take a look at the Sinewave.ino for an example on how to make a (lookup table-based) sine wave. It can also do much more.

In its default mode, Mozzi works with a 16,384 Hz sample rate and a 32,768 Hz (not audible) PWM frequency.

1
  • I found Mozzi to be very heavyweight for a limited memory footprint. It is fine if there is no plan to perform a number of tasks with one Arduino board, pushing the limits of program executable space. Commented Jan 2, 2017 at 18:40
4

There are two parts to this:

One is the creation/derivation/storage of the digital representation of a sine wave. The other is the conversion of the digital representation of a sine wave to an analog voltage (if I understand what you want).


The easiest way to obtain the digital representation of a sine wave is a lookup table. Precompute the digital values, and store them in an array. Simple. It is up to you to decide how much resolution (both in vertical accuracy/number of bits and horizontal accuracy/number of samples) you require.

It is also possible to compute the values directly. There are a number of ways of doing this, but be aware that using floating point math on the Arduino is very slow and space-intensive. You may want to look at CORDIC for one possible solution to this.


Next is the conversion to analog. You are right, PWM is one way to do this, and one of the easiest as far as external components go: you only need an RC filter to smooth the PWM. However, PWM is limited in resolution, and performs poorly when your wave frequency becomes a significant fraction of your PWM frequency. Also, the Arduino doesn't run very fast, so your PWM frequency is limited.

Other DAC solutions (there are many many many, so I'm not going to go in depth on this):

  • R2R DAC: simple to construct, but requires precision resistors for decent resolution, limited in resolution, and requires many IO pins.

  • "proper" DAC: an I2C/SPI DAC can give you far better performance, but you will have to learn how to communicate with it. And it's going to be more expensive, and involve several components.


However, this route seems to me quite long, what other options do I have?

I'm not sure what you mean by "quite long", but this is pretty straightforward. For example, here's how I'd go about it:

  • store a sine wave in a lookup table
  • set up an interrupt to trigger at regular intervals
  • in the interrupt, pull a value from the lookup table and write it to PWM

You can now vary the frequency of your sine wave by either adjusting your interrupt interval, or adjusting the increment of your LUT position. You can vary the amplitude by simply multiplying the LUT values by a variable.

This is quite straightforward.

4
  • I meant that using the PWM option would be longer to implement compared to something easier such as a lookup table as you suggested. I think the lookup table option you suggested is exactly what I was looking for. It is fast and provides a quick way to tune frequency. Thanks.
    – mickkk
    Commented Jun 23, 2016 at 17:44
  • You still need both. And the PWM option is very difficult to implement, at most, you'll need to learn how interrupts work, and how PWM works, which might be a lot of work, but should be worthwhile if you're interested in Arduino in general.
    – uint128_t
    Commented Jun 23, 2016 at 18:04
  • @uint128_t: Did you mean "not very difficult..."?
    – JRobert
    Commented Jun 23, 2016 at 18:29
  • @JRobert I did, thank you. OP: PWM is not very difficult.
    – uint128_t
    Commented Jun 23, 2016 at 19:32
2

You can get a very fast, accurate, and compact sin(theta) function using a simple table of values. Just pull the code you need from the cordic.c here: https://people.sc.fsu.edu/~jburkardt/c_src/cordic/cordic.html. C runs in Arduino sketches almost out of the box. You may or may not need some things from the cordic.h. That's why I said "almost". The cordic_prb.c test file has a function test002() that shows you how to call the sine function.

Because the Uno does not have a real D-to-A converter, you will only get a rectangular wave that has digital noise over the primary harmonic. That's the down side of the pulse width modulation of the lower end Arduino chips. You will need a filter on the analog output if you need to remove the higher frequency noise harmonics.

1

I found that the Mozzi sinewave.ino demanded more and more include files during compile efforts, and once these (easy) problems were resolved, it ended up with horrific compile errors due to something missing in the code. NBG for a "C" dummy like me!

4
  • Douglas, So did I (have endless trouble) with Mozzi. It was said elsewhere in stack exchange that I might not have picked up on all the include files. If I solve in 2017 I'll post the solution!
    – Jim
    Commented Jan 11, 2017 at 17:13
  • Am also a C dunmy
    – Jim
    Commented Jan 11, 2017 at 17:17
  • You could look at. interface.khm.de/index.php/lab/interfaces-advanced/… which gives badly commented code and a PWM output on a digital pin. You need a low-pass filter to clean up the signal & reveal the sinewave. I still don't understand how the interrupt works . . .
    – Jim
    Commented Jan 11, 2017 at 17:25
  • Actually this code although it works (I think) is possibly the worst example of coding I have ever seen. Sorry!
    – Jim
    Commented Jan 11, 2017 at 18:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.