98. Space and Time

“Space and Time” 4: Software

One of the main features that I wanted to implement in this project was fading from one lamp to another. The process of fading a lamp is a bit different to the dimmer you may have in your house. Having said that, they both create the illusion of dimming by turning the lamp on and off very quickly, and changing the proportion of time it’s on or off.

The lamp in your house uses the fact that mains electricity already turns on and off 100 times a second, with each alternate “on” going in the opposite direction. All the dimmer has to do is prevent the lamp from turning on each time the power starts, but turn it on instead a fraction of a second later. The longer it waits each time, the dimmer the lamp will appear.

The arduino outputs direct current. There’s no on/off cycle. When it’s on, it’s on. So in order to dim a lamp the arduino output has to be turned on and off fast enough to not look like it’s flickering, with a varying proportion of on/off time according to how dim the lamp should be. It’s called pulse-width modulation (PWM).

There are two ways to do this. Firstly, six of the outputs have a built-in PWM mechanism. You just tell the arduino to turn that feature on, and, presto! Except there’s a problem. It’s ok if you’re just dimming one lamp, but when you want to fade between lamps it’s complicated. You see, there’s only one power supply, and it’s a constant current. So, if you turn on two lamps at once they will run at half the usual current, i.e. much less bright.

Suppose you are half-way through a fade, and both lamps are at half brightness. This means that they are both running at full brightness for half of the time. Now this would be ok if the pulses from the arduino were synchronised, i.e. if it turned on lamp A for a few milliseconds, then turned lamp A off and turned on lamp B for the same amount of time. However, it doesn’t work like that, and what would happen is that sometimes the “on” times would overlap, randomly reducing the brightness of both lamps.

The alternative is to control the fade oneself in software. This is what I did. There are two parameters to consider:
1) Flicker speed
2) Number of brightness levels

I decided on a flicker (or refresh) speed of 200 times a second (twice mains frequency, which some people can perceive), and 200 brightness levels. It works like this: time is divided into 5000 microsecond units (I call them “ticks”). Each tick is divided into 200 parts (25 microseconds each). So, for example, to fade between lamp A and lamp B over 2 seconds, the first tick would be 5000 / (200 * 2)  = 12 microseconds for lamp B, and (5000 – 12.5) = 4987 microseconds for lamp A (with some rounding). Then the next tick would be 25 and 4975 microseconds for each lamp respectively. At half way (after one second) it would be 2500 microseconds for each lamp, and so on, until the last one at 4987 and 12, and then full brightness for lamp B.

The arduino can only control things down to three or four microseconds, so without some additional code this only works properly for fades up to about 6 seconds (since the shortest flash would then be 4 microseconds. However, it won’t become a noticeable problem until very long fades.

The program calculates how many ticks to fade over and then loops like this:
* Calculate the proportion of time between lamps for this tick
* Turn on lamp A; turn off lamp B
* Wait
* Turn on lamp B; turn off lamp A
* Wait

Now, there’s a slight complication. switching an arduino output from Off to On (or vice versa) is not instantaneous. In fact, it takes about 4 microseconds. It’s not so much, but since we are trying to use 4 microsecond units, 8 microseconds (one on plus one off) is going to affect the timing.

There are a number of ways around this. It’s possible to reduce the time to 0.0125 microseconds, but not so easily. However, I found a library on the internet that includes a command digitalwritefast2() which does the job in 0.75 microseconds. I decided that would be fast enough.

Finally, I turn one lamp on before, rather than after, turning the other lamp off. This is to prevent the power supply seeing no load and increasing the voltage to maximum for a brief moment – instead it will reduce the voltage as two lamps will be in parallel for a moment. (Not that it should matter, it’s just the principle.) The fade function is shown below.

This is what it looks like, fading between five lamps with a short “on” time in between.

 

The time taken for a fade, and the time between fades, can be adjusted using two potentiometers (variable resisters) wired between +5 Volts from the arduino (via a 1K resistor, just to be on the safe side) and negative, with the sliders going to two of the arduino’s analogue inputs. The analogRead() function returns a value between 0 and 1023 depending on the voltage (i.e. where the potentiometer is set). There is also a 12 position switch used to select different types of change (clockwise, anti0-clockwise, random, etc. – not all 12 were used). There’s a 33K resistor between each of the switch positions, so it acts like a 363K potentiometer.

The settings are not checked continuously – it takes about 100 micro seconds to read an analogue input, during which you can’t do other things, like turn on LEDs, so the settings are checked when there’s at least 300 milliseconds where nothing else has to happen.

There is an argument against using delay(), on the grounds that the processor can’t do anything else while it’s waiting. However, if it did go off and do something else, and took too long, then it could create a visible artifact in the lighting; I prefer to incorporate whatever else it is myself, and adjust the timing accordingly.

The other thing is that the actual code is a little more complicated, as there’s an overall brightness level; if set to less than 100% then all the calculated “on” times are reduced and an “all off” time is added to each tick.

 

#include <digitalWriteFast.h>
int LampPins[] = {5, 0, 1, 2, 3, 4}; // Element 0 holds lamp count
// Fade between lamps over a number of 5 millisecond (5000 microsecond) ticks
// Each Tick consists of (1) old (previous) lamp on; (2) new (current) lamp on
void FadeAcross(int PreviousLamp, int CurrentLamp, int FadeTime)
{
 // Number of ticks to fade over is FadeTime (in tenths of a second)
 //  x 200 ticks per sec (5000 microseconds per tick)
 int TickTotal = FadeTime * 20;
 long TickLength = 5000;
 
 // Cycle through the ticks
 for (int tick = 1; tick < TickTotal; tick++)
 {
  // Calculate the proportion of the 5ms is lit by each lamp
  long OnTimeCurrent = (TickLength * tick) / TickTotal;
  long OnTimePrevious = TickLength - OnTimeCurrent;
  // Flash the previous lamp (it may already be on)
  digitalWriteFast2(LampPins[PreviousLamp], HIGH);
  digitalWriteFast2(LampPins[CurrentLamp], LOW);
  delayMicroseconds(OnTimePrevious);
  // Flash the current lamp
  digitalWriteFast2(LampPins[PreviousLamp], LOW);
  digitalWriteFast2(LampPins[CurrentLamp], HIGH);
 
  delayMicroseconds(OnTimeCurrent);
 }
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s