Volt Meter Clock

Hi all,
This is indeed my first post. I've had my arduino for a while and have been feel particularly hobbyish lately so I decided to break it out and give a project a go. I have seen some cool things done with analog volt meters and decided to make a clock. I decided to go ahead and make a volt meter clock. I did a bit of searching and there has been some work with them but I wanted to write my own code since I just finished a course in C programming. I did look at some other code but it seemed very complex. So I gave it a go myself.
Basic idea is that there are three voltmeters (hour(0-12), minute(0-60), second(0-60)) that will serve as the dials for my clock. I will use the arduino to control the voltages to each meter in accordance to the time. I am using the analogWrite() function and would really appreciate someone to take a look at my code. I dont have my arduino or the volt meters at the moment but have already written the code. There is a variable for a set button but it is not yet implemented. Anyways, the code:

int pinSecond = 11; //pins for each voltmeter
int pinMinute = 10;
int pinHour   = 9;
int pinSet    = 8;

double stepHour = 0; //increase for each step
double stepSecond = 0;
double stepMinute = 0;

double voltHour = 0; //"volts" for each setting. Not actually volts
                    //but percentage(?) of 5V.
double voltMinute = 0;
double voltSecond = 0;

void setup()
{
    pinMode(pinSecond, OUTPUT);
    pinMode(pinMinute, OUTPUT);
    pinMode(pinHour, OUTPUT);
    pinMode(pinSet, INPUT);

    stepHour = 12/255;
    stepMinute = 60/255;
    stepSecond = 60/255;
}

void loop()
{
    for (int h=0; h<12; h++)
    {
        analogWrite(pinHour, voltHour);

        for (int m=0; m<60; m++)
        {
            analogWrite(pinMinute, voltMinute);

            for(int s=0; s<60; s++)
            {
                analogWrite(pinSecond, voltSecond);
                voltSecond = voltSecond + stepSecond;
                delay(1000);
            }

            voltMinute=voltMinute+stepMinute;
            voltSecond=0;
        }

        voltHour=voltHour+stepHour;
        voltMinute=0;
    }
    voltHour=0;
}

So that's it. Seems a bit too simple to be correct but perhaps it is. I will eventually go back and try to do a bit of optimization with variables. Seems like I could use some more ints and bytes to make it a bit smaller.
I will also implement some code that upon a button press will progress the time by one minute and perhaps add a second button for hours.
Any suggestions?
My one question is about the analogWrite function. This takes a value between 0 and 255 and I understand a bit of how it works but would a value of 0=0V and a value of 255=5V on the voltmeter?

The analogWrite controls a PWM signal going out. You'll probably want to run the output into an RC filter to make smooth(er) DC to into the meters.
Once you get working to your satisfaction, I think you'll want to control the seconds going by by keeping track of the millis() or micros() going by for better accuracey, delay(1000) may give you a lot of drift.

It's usually better (or at least clearer) to seperate the input and calculations from the output. So in that context I would do something like this psuedo code

#define MAX_PWM_VAL 50 // for example

#define HOURS_PIN 2
#define MINUTES_PIN 3
#define SECONDS_PIN 4


every second
seconds++
if (seconds > 59) {
   seconds = 0;
   minutes++
}

if (minutes > 59) {
   minutes = 0;
   hours++;
}

if (hours > 24) {
   hours = 0;
}

// now we have a set of variables to use
// map the time variables to PWM values that make sense for the dials being used

analogueWrite (SECONDS_PIN, map (seconds, 0, 59, 0, MAX_PWM_VAL));
analogueWrite (MINUTES_PIN, map (minutes, 0, 59, 0, MAX_PWM_VAL));
analogueWrite (HOURS_PIN,   map (hours, 0, 24, 0, MAX_PWM_VAL));

but would a value of 0=0V and a value of 255=5V on the voltmeter?

Depends on the meter, but 5V may be too high. Hense the mapping above.


Rob

the way you did the code will make the minute and hour meters move in discrete steps, rather than smoothly move from one number to the other. Also you should be able to do all of the calculations with only integers. Let me know if you need any more help. I have my own arduino powered meter clock on my front table. (check out Make vol 13)

Hey all,

Thank you for the great replies, all very helpful.
Of course, I am left with some(less) questions.
@graynomad.
The psuedo code looks great though at first I didnt catch the psuedo and was like, "Holy crap! When did C++ get so plain language?"
In your code you use #define. How does this compare in memory usage to an int or byte. Seems like one could replace a lot of constants with these but I haven't seen them much.
As far as the gauges? You say that this depends on the gauge. I was thinking of using a 0-5V meter but perhaps there are better ones.
I have seen some 0-5V meters online for cheap, seems like they could work pretty well. I also have some old pyrometers I would like to use. I guess I'll have to get over to a powersupply and see about their specs.
@Crossroads.
RC circut? I have learned of this but will have to go back and refresh myself. The basic idea is this will smooth the power out, yeah?
As far as millis. I have searched around for some clock code (forgot that a clock doesnt need to be a volt clock for the code to be applicable) and found some millis() implementations such as this one:

if (millis() - lastTick >= 1000) {
lastTick = millis();
serialOutput();
second++;
}

I understand and like this usage but what happens with millis() overflows?
@gradbert
I definitely want the discret steps, at least for now. I have seen your clock and when I started my hunt (inspired by the torrent meter) yours was one of the ones that I saw. I had a bit of a hard time deciphering your code though/wanted to write my own anyways. I think my biggest need for help right now is the electronics end of things.
I will certainly let you all know as the project progresses and let you know how it turns out.
Thanks!

In your code you use #define. How does this compare in memory usage to an int or byte.

#define is a preprocessor directive, it doesn't use any memory, just performs a text substitution before the compiler sees the code.

So

#define CONST_VAL 1

is IMO it's a better option than say

const int CONST_VAL = 1;

for that reason but also in the resultant code, say

if (CONST_VAL == x)

using a variable the processor has to go and get the CONST_VAL value at run time, as a #define it's a load immediate instruction which has to be faster.

I know every man and his dog uses const for this so maybe my reasoning is all wrong, but that's what I've done for years.

You say that this depends on the gauge.

I was just thinking of doing this with say converted current meters (or maybe those "old pyrometers") that may have a limited full scale voltage. But if you're getting 5v dials then it doesn't matter.

As for the RC filter on the PWM, it may not be required if the meter needles have enough inertia and the PWM frequency is high enough.


Rob

As long as you define the variables used with millis() as
unsigned long
and do all your math as subtractions (millis_now - millis_before)
the math will work out.
For example, say the time just rolled over and you captured it at 0x0000 0030
and time before was 0xFFFF FF10
then 0000 0030 - FFFF FF10 will yield a correct result of 0x0000 0120

I know every man and his dog uses const for this so maybe my reasoning is all wrong

It is. :wink: "const" is usually free. "static const" is always free. With the advantage that "const" is typed...

#define MILLISPERSECOND (1000)
unsigned long Stop;
Stop = 68 /*seconds*/ * MILLISPERSECOND;  // Oops!
static const unsigned long MILLISPERSECOND = 1000;
unsigned long Stop;
Stop = 68 /*seconds*/ * MILLISPERSECOND;  // Whew!

Thanks CB, so the I assume the typing helps protect against doing the wrong thing, but I can't get the second one to throw an error.


Rob