Go Down

Topic: Simple Timer using 8 Digit, 7 Segment Display (MAX7219) (Read 10641 times) previous topic - next topic

programmable

Dec 01, 2013, 07:52 pm Last Edit: Dec 01, 2013, 08:23 pm by programmable Reason: 1
Hi all. This if my first post and one of my first arduino projects so go easy on me  :D.

For now, i want to build a simple "high speed" timer.
ideally i would like the first digit to represent 0.01mS/ the second digit 0.1mS and so on. But so far the fastest i've managed to get the first digit clock speed is 1mS (using the delay command). is there anyway i can get a faster clock speed?

I will post the code as im guessing you are going to ask for it. The code is messy and far from perfect but it works. If there is a neater, easier way of coding this project im all open to good advice  :). - the code is not commented, but it does work.

Thanks

Code: [Select]

#include "LedControl.h"


pin 12 is connected to the DataIn
pin 11 is connected to the CLK
pin 10 is connected to LOAD
We have only a single MAX72XX.

LedControl lc=LedControl(12,11,10,1);

unsigned long delaytime=1;

void setup() {
  /*
   The MAX72XX is in power-saving mode on startup,
   we have to do a wakeup call
   */
  lc.shutdown(0,false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0,8);
  /* and clear the display */
  lc.clearDisplay(0);
}

int time = 0;
int s0 = 0;
int s1 = -1;
int s2 = -1;
int s3 = -1;
int s4 = -1;
int s5 = -1;
int s6 = -1;
int s7 = -1;
void loop() {
 
  s0=time;
 
  if (time==9){
    time=-1;
  }
 
  if (s0==0){
    s1=s1+1;
  }
 
  //---------------------------------------------------------
 
    if (s1==10){
    s1=0;
  }
 
  if (s1==0&&s0==0){
    s2=s2+1;
  }
 
  //---------------------------------------------------------
 
     if (s2==10){
    s2=0;
  }
 
  if (s2==0&&s1==0&&s0==0){
    s3=s3+1;
  }
 
    //---------------------------------------------------------
 
     if (s3==10){
    s3=0;
  }
 
  if (s3==0&&s2==0&&s1==0&&s0==0){
    s4=s4+1;
  }
 
      //---------------------------------------------------------
 
     if (s4==10){
    s4=0;
  }
 
  if (s4==0&&s3==0&&s2==0&&s1==0&&s0==0){
    s5=s5+1;
  }
 
        //---------------------------------------------------------
 
     if (s5==10){
    s5=0;
  }
 
  if (s5==0&&s4==0&&s3==0&&s2==0&&s1==0&&s0==0){
    s6=s6+1;
  }
 
          //---------------------------------------------------------
 
     if (s6==10){
    s6=0;
  }
 
  if (s6==0&&s5==0&&s4==0&&s3==0&&s2==0&&s1==0&&s0==0){
    s7=s7+1;
  }
 
 
  lc.setChar(0,0,s0 ,false);
  lc.setChar(0,1,s1 ,false);
  lc.setChar(0,2,s2 ,false);
  lc.setChar(0,3,s3 ,false);
  lc.setChar(0,4,s4 ,false);
  lc.setChar(0,5,s5 ,false);
  lc.setChar(0,6,s6 ,false);
  lc.setChar(0,7,s7 ,false);
 
   delay(delaytime);
  time=time+1;
}

arduinodlb

Welcome,

Please go back and modify your original post and include the code inside [ code] [ /code] tags.

Instead of using delay(), take that out and use the millis() function to determine what digits to display. This will ensure your timer is accurate.
Do not IM me. I will not respond. Ask questions in the forum.

programmable

Thanks for the pointer - post edited.

I had a feeling someone would say that.
my attempts of using the millis function have so far all failed when i've tried to replace the delay function.
I find the arduino site doesn't break each part of the code up enough for me to understand how each part comes together to create a sequence/ function that actually works.

maybe i should learn more "basics" before trying to build the things i need from the off  :smiley-roll:

arduinodlb

Oh, sorry. I just realised you want to go faster than 1ms accuracy. millis() won't do that.

Hopefully someone here can let you know if it's possible with the Arduino.
Do not IM me. I will not respond. Ask questions in the forum.

programmable

hmm. What if i used an external high speed clock and have the arduino "count" that? .. with no delay/ millis function, is that viable or will it just make the segments do funny things?
... feed the PWM output back into intself on another pin and count that? lol

Thanks for your help

arduinodlb

I haven't really looked at the arduino core as my projects didn't need this level of accuracy. I have seen people doing things with ISRs and the onboard timers though, so it's probably possible to do something. Just not anything I've looked into personally.
Do not IM me. I will not respond. Ask questions in the forum.

nickgammon

I have a page about the 7219 and displays:

http://www.gammon.com.au/forum/?id=11516

Your code looks rather complex for displaying 8 digits. From that page I displayed 4 digits, doing 8 would be a minor change:

Code: [Select]

#include <SPI.h>

const byte MAX7219_REG_NOOP        = 0x0;
// codes 1 to 8 are digit positions 1 to 8
const byte MAX7219_REG_DECODEMODE  = 0x9;
const byte MAX7219_REG_INTENSITY   = 0xA;
const byte MAX7219_REG_SCANLIMIT   = 0xB;
const byte MAX7219_REG_SHUTDOWN    = 0xC;
const byte MAX7219_REG_DISPLAYTEST = 0xF;

void sendByte (const byte reg, const byte data)
 {    
 digitalWrite (SS, LOW);
 SPI.transfer (reg);
 SPI.transfer (data);
 digitalWrite (SS, HIGH);
 }  // end of sendByte

void setup ()
 {
 SPI.begin ();
 sendByte (MAX7219_REG_SCANLIMIT, 7);      // show 8 digits
 sendByte (MAX7219_REG_DECODEMODE, 0xFF);  // use digits (not bit patterns)
 sendByte (MAX7219_REG_DISPLAYTEST, 0);    // no display test
 sendByte (MAX7219_REG_INTENSITY, 7);      // character intensity: range: 0 to 15
 sendByte (MAX7219_REG_SHUTDOWN, 1);       // not in shutdown mode (ie. start it up)
}   // end of setup

void number (const unsigned long num)
 {

char buf [9];
sprintf (buf, "%08ld", min (max (num, 0), 99999999));

// send all 8 digits
for (int digit = 0; digit < 8; digit++)
  {
  byte c = buf [digit];
  if (c == ' ' )
    c = 0xF;  // code for a blank
  else
    c -= '0';
  sendByte (8 - digit, c);  
  }  
 }  // end of number
 
unsigned long i;

void loop ()
{
number (i++);
}  // end of loop


The above displays 8 digits on the LEDs.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

nickgammon


hmm. What if i used an external high speed clock and have the arduino "count" that?


Do you want it to count faster? In my test the last two digits are unreadable, it is counting so fast. Or do you want to time some external event? If so, what? How do you know it has started and stopped? You can use a timer to count up to 62.5 nS accuracy, and then just display the results of that on the LEDs.

http://www.gammon.com.au/forum/?id=11504
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

programmable

Thanks the replies guys.

Yes, in an ideal world i would like to count 1 million every second. 100,000 would do though.
It would be to measure the speed of objects etc... obviously there would be some slight modifications to the code but for now i just need it to count real fast. so it would be to time an external event like you say  :)
I just tried the delayMicrosecond function with no luck.
62.5nS... now we're talking! i looked at the code on that link you sent me and erm  :smiley-eek:... it's a bit beyond me
using the delay(1) or millis function i can get the last 2 digits unreadable but the 4th digit is very slow.

I built this circuit before using 6 segment driver, 6 decade counters and a few 555's IC. could i not use a 555 clock output to feed the arduino a sort of clock pulse? should get 100kHz out of it.
Thanks

nickgammon

You don't need an external timer, the CPU chip has one. Here is my code that times a ball running down a ramp:

Code: [Select]

const byte LED = 12;
const float DISTANCE = 0.9; // m

unsigned long startTime;
volatile unsigned long elapsedTime;
volatile boolean done;
boolean started;

void ballPassesGate1 ()
{
  startTime = micros ();
  started = true;
   
  digitalWrite (LED, HIGH); 
}  // end of ballPassesGate1

void ballPassesGate2 ()
{
  if (!started)
    return;
   
  elapsedTime = micros () - startTime; 
  done = true;
  started = false;
 
  digitalWrite (LED, LOW); 
}  // end of ballPassesGate2


void setup ()
{
  Serial.begin (115200);
  Serial.println ("Timer sketch started."); 
  pinMode (LED, OUTPUT);
  attachInterrupt (0, ballPassesGate1, FALLING);
  attachInterrupt (1, ballPassesGate2, FALLING);
}  // end of setup

void loop ()
  {
  if (!done)
    return;
   
  Serial.print ("Time taken = ");
  Serial.print (elapsedTime);
  Serial.println (" uS");
  float secs = float (elapsedTime) / 1.0e6;
  float velocity = DISTANCE / secs;
  Serial.print ("Time taken = ");
  Serial.print (secs);
  Serial.println (" seconds.");
  Serial.print ("Average velocity = ");
  Serial.print (velocity);
  Serial.println (" m/s.");
  Serial.println ();
 
  done = false;
  }  // end of loop


You don't want delays, you want to measure the start and end point. micros() has a 4 ┬ÁS resolution. To get better than that you need to use Timer 1 or Timer 2 with no prescaler.

That code doesn't display with LEDs, that's a separate issue, but it shows how to time things.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

Go Up