Arduino Function Generator (Part 2)

Last time, we looked at some Arduino code that we could use to generate some square waves.

The problem with the setup we’ve been looking at so far, is that we can only produce signals of one amplitude – equivalent to the HIGH logic level.

In order to be able to produce any other waveforms we’ll need to be able to produce a variety of different output voltages. Although the PWM method we looked at last time gives us a way to do this, it’s not suitable for producing variable waveforms – as it’s time-based. We can see this, if we try to use PWM to produce a triangular waveform: and view the output with an oscilloscope.

void setup() 
{ 
    pinMode(11, OUTPUT); 
} 

void loop() 
{ 
    for (int i=0; i<0; i--)
    {
        analogWrite(11, i); 
        delay(1); 
    }
}

Creative Commons License


PWM Triangle code is by AJP is licensed under a Creative Commons Attribution-Share Alike 2.0 UK: England & Wales License.


If we hook that up to our oscilloscope – it looks like this:

Failed Triangular Waveform

It’s not too easy to see that as a still image – so here’s a video clip of the same thing…


That’s clearly not really what we wanted: so we need to do something differently.

The solution to this problem, is to use some kind of digital-to-analogue converter (or DAC). To begin with, let’s build our own…

R-2R DAC Breadboard

Or, if you prefer, in schematic…
R-2R DAC Schematic

This circuit is an 8-bit DAC known as an R-2R resistor ladder network. Each of our eight bits contributes to the resultant output voltage. If all 8-bits are HIGH – then the output is approximately equal to the reference voltage… If we switch the most-signifincant bit to LOW – then we get approximately half of that voltage.

More precisely, for an 8-bit DAC if all 8-bits are HIGH – then we get 255/256th of the reference voltage. Switching the most-significant bit to LOW gives us 127/256th of the reference voltages. More generally for any bit value x, between 0 & 255, our DAC will us x/256th of the reference voltage.

There’s a short article on wikipedia explaining R-2R DACs in a little more detail, if you want to know more…

Okay, now that we’ve built our circuit – let’s do something with it.

We’ll start by producing a triangular waveform…

void setup() 
{ 
    pinMode(0, OUTPUT); 
    pinMode(1, OUTPUT);
    pinMode(2, OUTPUT);
    pinMode(3, OUTPUT); 
    pinMode(4, OUTPUT); 
    pinMode(5, OUTPUT); 
    pinMode(6, OUTPUT); 
    pinMode(7, OUTPUT); 
}

void loop() 
{
    for (int i=0;i<255;i++) 
    {
        PORTD=i;
    }
    
    for (int i=255;i>0;i--) 
    {
        PORTD=i 
    }
}

Creative Commons License


R-2R ADC triangle code by AJP is licensed under a Creative Commons Attribution-Share Alike 2.0 UK: England & Wales License.


Triangular Waveform

Note that here we’re using PORTD instead of setting the state of the individual output pins one at a time. This is much faster, and it (critically) ensures that all of the pins change at the same time – and that’s important given we want to switch smoothly though digital values to create a smoothly changing analogue voltage.

PORTD is port register D. Our use of it here works because it maps to the 0-7 digital pins (giving us 8-bits); and writing either a binary or decimal value to the register – we control all 8 pins in one operation. For example, if we assigned it the decimal value 123 (which equates to B01111011) would set pins 6, 5, 4, 3, 1, & 0 to HIGH… Now the problem is that pin 0 is used for communicating serial data – so using PORTD means that we can’t use any serial communications whilst code it running. It is, however, the only way to manipulate 8 output pins simultaneously (and we didn’t need serial communications for this application anyway).

We can modify our code very easily, to produce a saw-tooth waveform – by simply commenting out (or otherwise removing) the second of the two for loops.

Note that if we want to drive anything significant (even something as lowly as an LED) we need add a transistor into the circuit, like this:

DAC with transistor & LED

Finally, on to a sine wave. We’ll need to pre-compute some values for the output voltages over time (the arduino just isn’t quite fast enough to be able to this in real-time, in a situation quite as time-sensitive as producing a waveform).

A sine wave has a cycle of 2π radians – so to produce a sine wave with 256 time-steps per cycle, we just need to calculate y=sin((x/255)*2π) for each point value of x. Since the sine function gives us values between 1 and -1; and we want values between 0 and 255, the simplest way to do this is to multiply the float value by 128 – giving us a value between -128 & +128; and then add 128 – to give us the correct range.

We could do this off-line; but that’s a bit tedious – so we’ll get the arduino to do this for us, in the setup() phase, storing the results in a global array. Then all we need to do in our main loop, is cycle through the array.

int sine[255]; 
void setup() 
{ 
    pinMode(0, OUTPUT);
    pinMode(1, OUTPUT); 
    pinMode(2, OUTPUT);  
    pinMode(3, OUTPUT); 
    pinMode(4, OUTPUT); 
    pinMode(5, OUTPUT); 
    pinMode(6, OUTPUT); 
    pinMode(7, OUTPUT); 
    float x; 
    float y; 
    for(int i=0;i<255;i++) 
    { 
        x=(float)i;
        y=sin((x/255)*2*PI); 
        sine[i]=int(y*128)+128; 
    }
 } 

void loop()
{
    for (int i=0;i<255;i++) 
    { 
        PORTD=sine[i]; 
        delayMicroseconds(10); 
    }
 }

Creative Commons License


R-2R ADC sine code by AJP is licensed under a Creative Commons Attribution-Share Alike 2.0 UK: England & Wales License.


If we run that code, with our DAC, and have a look at that on our oscilloscope we see that we do indeed have something that looks quite a lot like a sine wave.

Sine Wave

That’s all for this part, next time we’ll have a look at varying the frequency of our waveforms; and look at a more compact and accurate way to do the digital-to-analogue conversion, using a dedicated IC…

Arduino Function Generator (Part 1)

I was looking around for an interesting Arduino project, and I came up with the idea of making a function generator (also called a signal generator). The reason I picked a function generator is that it gives us the chance of playing with some interesting circuits – and some interesting code…

Before we start with that – what is a function generator?

A function generator is a circuit that generates some kind of waveform. There are four main types of waveform – the square wave, triangular & saw-tooth waves, and the sine wave.

There’s a good article on function generators on wikipedia.

A dedicated function generator will cost a hundred pounds or more – but it would be very much more capable than anything we’ll build here; but this will give us a chance to look at a few interesting things.

The simplest waveform to get an Arduino to produce is a square wave. The square wave (as the name suggests) simply cycles between the HIGH and LOW logical levels.

An idealized square wave

(Actually it’s not really that simple at all – a square wave produced by an analogue oscillator is actually made up of a complex mixture of multiple harmonics – wikipedia has a description of this; but we won’t concern ourselves with this…)

The circuit we need to produce a square wave, is pretty much the most trivial circuit imaginable.

In fact all we need to do is connect whatever it is we’re driving, to one of the digital output pins of the arduino (I’m using pin 8 here); and the arduino’s ground.

Square Wave Circuit

The code is very simple, too…

void setup()
{ 
    pinMode(8, OUTPUT);
}

void loop() 
{
    // A total delay of 4 ms = 1/0.004 = 250 Hz… 
    digitalWrite(8, HIGH);
    delay(2); 
    digitalWrite(8, LOW); 
    delay(2); 
}

Creative Commons License


Square wave code by AJP is licensed under a Creative Commons Attribution-Share Alike 2.0 UK: England & Wales License.


If we want to drive something like a piezoelectric speaker we can connect it to the pin, and the arduino’s ground; and we’ll be able to hear a tone. Alternatively if we pick a low enough frequency we could hook up an LED to see it blink. In fact, if you do that, you’ll note that this setup and code is actually just the blink demo.

Note that we can also use delayMicroseconds() to enter smaller delay values – giving use the ability to produce higher frequencies than the 500Hz that we’d otherwise be limited to…

In fact it’s even easier than this – as Arduino has a function to generate a square wave. For example, to produce the same 250Hz square wave as we had before, we can use: tone(8, 250); in place of the digital writes…

Let’s see exactly what this square wave looks like – buy hooking it up to an oscilloscope…

Apart from the frequency of the wave, there are a couple of other main characteristic that we might want to modify: the amplitude (a measure of how much higher the HIGH level is, compared to the LOW), and the symetry of the wave – the so-called duty cycle. We’ll leave the amplitude aside until next time – as that’ll require us to do a little more work; but let’s look at the duty cycle of the wave.

The duty cycle is simply a measure of how much of the time our wave is at the HIGH level – compared with the total time of the cycle. So far all of our square waves have been symmetrical: with an equal amount of time spent in both states. This is known as a 50% duty cycle.

If we want to change that, we can’t use the tone() function – as that’s designed to produce a symmetrical wave. Instead we need to use the digitalWrite() and delay() functions. So to create a 25% duty cycle square wave at 250Hz – we’d use delays of 1 ms after the LOW, and 3ms after the LOW.

If we use an oscilloscope we can see the shape of the resulting wave…

250Hz 25% Square Wave

With the timebase set to 2ms per division, we can clearly see the 1ms width of the pulse, and the 3ms gap between the pulses.

What’s interesting is what happens if we try measuring the voltage with an instrument that’s less time-sensitive – such as a multimeter. A 250Hz signal with a 50% duty cycle, yields an average of 2.4V (which is exactly half of the 4.8V my meter shows the +5V output of the arduino to be). With a 25% duty cycle – we get 1.2V (one quarter of the HIGH voltage); and so on…

In fact, this concept may already be familiar to you – if you’ve used the analogWrite() function – we have just reimplemented the pulse width modulation (PWM) technique that Arduino uses to provide analog (or analog-like) voltages. We can show this in a couple of ways. Firstly we’ll measure the voltage across an LED during an analogue write with our oscilloscope; and then we’ll show that by adjusting the duty cycle of our code, we can dim an LED.

First lets look at a PWM voltage, giving us a 50% duty cycle (or an average output of around 2.4V).

Arduino PWM 50% Duct Cycle

As you can see the shape is identical to what we saw before in our own version – although the frequency here is different (the Arduino reference document states that the PWM frequency should be approximately 490Hz…

Now let’s try implementing our own version of PWM…

First here’s a schematic of the new circuit…

As you can see we’re simply driving an LED via pin 8 (not forgetting the current limiting resistor, of course); and we’re getting a voltage (between approximately 0V and the reference voltage) from the potentiometer, and feeding it into analog pin 2.

Now for the code.

int value=0; 
void setup() 
{ 
    pinMode(8, OUTPUT); 
    pinMode(2, INPUT); 
} 

void loop() 
{
    value=analogRead (2); 
    value=map(value, 0, 1023, 1, 19); 
    digitalWrite(8, HIGH); 
    delay(1); 
    digitalWrite(8, LOW); 
    delay(value); 
}

Creative Commons License


PWM demo code by AJP is licensed under a Creative Commons Attribution-Share Alike 2.0 UK: England & Wales License.


As you can see this is also very simple code. We call analogRead() to get the voltage – and then (for simplicity) we map it onto a range between 1 & 20 – and then use that as our millisecond delay value on the LOW part of the cycle – giving us a (theoretical) duty cycle of between 50% and 5%. I say a theoretical duty cycle – because in reality the time it takes the arduino to do the read and the map will actually throw off our timings. My multimeter shows a voltage of 2.16V rather than the expected 2.4V – dividing the reference voltage (4.8V) by the measured voltage (2.16V) gives us a a duty cycle of around 45%…

PWM Demo

As we can see from a more accurate measurement of the duty cycle, we see it’s around 46% – which implies that the time spent in the LOW state is actually around 1.08ms: hence approximately 80µS of additional time in the cycle spent at LOW whilst arduino executes the analog read and map functions). So if we were going to use this in reality – we’d probably need to find a more efficient way of determining the value for the second delay.

Or, more realistically, we could just use the analogWrite() function (which uses it’s own timer – independent of the main processing loop…

If we adjust the ‘scope to show the average voltage – we see that we get approximately the same voltage as the volt meter gave us…

Okay; that’s all for now. But be sure to come back soon for part two – when we’ll start to look at some ways to implement one of the more interesting waveforms: the sine wave.

Google Chromebook

Google & Samsung have announced the details of the first generation of Chromebooks – thin-client laptops running Google’s Chrome OS & reliant on a web connection for all of their capabilities. But can they succeed in a competitive market-place?

The Chromebook is a nice idea. Thin-client (cloud) computing is becoming (if not yet the norm) common-place in many corporate data centres; but (to date) it’s not really been a viable option for the home-user. Chrome OS changes that – by putting a cloud-based OS (and thin-client laptop) into the hands of home users.

The question is – are home user’s ready for cloud computing?

Google claim that the Chromebook can still be used without a constant network connection, because off-line versions of Google Docs, GMail, and Google Calendars. This will redress one of the major concerns – especially in the UK where the prevalence of wifi isn’t nearly as common as it could be. Even a 3G-based Chromebook won’t guarantee a network connection – especially when travelling by train.

The other problem with cloud-computing, is the question of whether people trust the cloud… Web-based email has been around for a long-time now, and (in fact) lots of people use webmail as their primary means of reading their email. This is the first example of cloud-services that most people will have experienced. We trust the internet with our email – since it’s intended to travel over the internet anyway… But do we trust the cloud – be it google or Amazon, or anyone else for that matter with our data? Our spreadsheets? Our banking records? Our letters?

And that’s a real question. It’s not at all clear if people do… Yes there are quite a few advantages to using a cloud (your data is accessible from multiple locations, it’s backed up, and it’s not dependant on any specific user’s hardware); but are these outweighed by the dangers  – and (perhaps more importantly) the perception of danger that comes from not owning one’s own data?

And then there’s the price…

At £350 for the wifi only Samsung Chromebook, these machines aren’t cheap. In fact, apart from the battery-life (claimed to be around 8-hours) they stack up pretty unfavourably when compared to cheap laptops. £350 will buy you a Windows 7 laptop, with hundreds of Gb of local storage; and the ability to run real applications.

Alternatively it’ll go a long way towards buying an iPad or an Android tablet; and it’ll be these, I think, that’ll be the main competitors for the Chromebooks (at least as far as home users go). Given the choice between a portable tablet with all-day battery life, and a laptop – with less capability & (arguably worse usability for many tasks) – are people going to choose the Chromebook?

The US prices for the Chromebooks translate rather nearer to £250 – and at that price (less than £300) the Chromebook becomes a very different prospect; but at £350, its a far harder choice.

Now none of this means that Chromebooks won’t be successful. For business users (especially small to medium sized businesses) already using Google Apps, Chromebook can be a great platform; but for home users – where there’s so much competition – I think it’s going to come down to the price…