Go Down

Topic: Timelapse with 4-digit 7 segment problem (Read 900 times) previous topic - next topic

swiftless

Hi there, i'm trying to build a timelapse controller that will show the set time on the 7-segment display. The timelapse code i found online, slightly modified the loop to

Code: [Select]
void loop() {
  currentTime = millis();
  seg.setTime(interval);
  if (currentTime-(previousTime)==interval || analogRead(buttons) > 1000) {
    previousTime = currentTime;
    takePicture();
  }
  if (analogRead(buttons) >= 890 && analogRead(buttons) <= 910 && (currentTime - previousTime) > 150) {
    interval += 5000;
    previousTime = currentTime;
  }
  if (analogRead(buttons) >= 950 && analogRead(buttons) <= 970 && (currentTime - previousTime) > 150) {
    if(interval > 5000) {
      interval -= 5000;
      previousTime = currentTime;
    }
  }
}


so it's possible to use the buttons to set the time or take a picture.

However the
Quote
seg.setTime(interval)
calls this function in a class i made. It works besides one fault, the interrupt delay before setting the segment high(for multiplexing) makes the
Code: [Select]
if (currentTime-(previousTime)==interval skip it's check so no pictures are taken. Is there any way around this? For example using millis() in some way to control the multiplexing?

Quote
void SevenSeg::setNumber(int segment, int number, boolean dot) {
  _pin = _a;
  _segment = segment;
  if (dot) {
   digitalWrite(_dp, HIGH);
  } else digitalWrite(_dp, LOW);
  digitalWrite(_segment, LOW);
  for (int i=0;i<7;i++) {
    digitalWrite(_pin, digits[number]);
    _pin++;
  }
  delay(5);
  clearSegment(_segment);
}

void SevenSeg::clearSegment(int segment) {
   digitalWrite(_segment, HIGH);
}



-Swift

AWOL

A bit lacking in detail, but how about
Code: [Select]
if (currentTime-(previousTime)>=interval?
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

swiftless

Thank you :) didn't even think about that :smiley-roll:

swiftless

All though the above fix works, it causes the interval to take pictures to be off with ~16ms each time. Over time this will accumulate into several seconds, which is kinda annoying. I can live with it tho, but if someone could come up with some other fix I would be grateful.

As I said above, the problem is with the delay(5); if it's set to 0 the display won't work properly (no multiplexing?) but the interval works perfectly. Have tried to figure out a way to use millis(); to reset the display but failed horribly. Any suggestions here?

semi pseudo:
Code: [Select]

currentTime = millis();
if(currentTime - someTime equals delay)
    reset segment X
    someTime = currentTime
else
    nothing


entire code for displaying time, the delay() is at the bottom
Code: [Select]
#include "WProgram.h"
#include "SevenSeg.h"

//                      a,b,c,d,e,f,g
int digits[11][7] = { { 1,1,1,1,1,1,0 },  // = 0
                      { 0,1,1,0,0,0,0 },  // = 1
                      { 1,1,0,1,1,0,1 },  // = 2
                      { 1,1,1,1,0,0,1 },  // = 3
                      { 0,1,1,0,0,1,1 },  // = 4
                      { 1,0,1,1,0,1,1 },  // = 5
                      { 1,0,1,1,1,1,1 },  // = 6
                      { 1,1,1,0,0,0,0 },  // = 7
                      { 1,1,1,1,1,1,1 },  // = 8
                      { 1,1,1,0,0,1,1 },  // = 9
                      { 0,0,0,0,0,0,0 }   // = blank
                      };
 
unsigned long _currentTime;
unsigned long _seg1Time = 0;
unsigned long _seg2Time = 0;
unsigned long _elapsed = 0;
unsigned long _start = 0;

SevenSeg::SevenSeg(int seg1, int seg2, int seg3, int seg4, int a, int b, int c, int d, int e, int f, int g, int dp) {
  pinMode(seg1, OUTPUT);
  pinMode(seg2, OUTPUT);
  pinMode(seg3, OUTPUT);
  pinMode(seg4, OUTPUT);
  pinMode(a, OUTPUT);
  pinMode(b, OUTPUT);
  pinMode(c, OUTPUT);
  pinMode(d, OUTPUT);
  pinMode(e, OUTPUT);
  pinMode(f, OUTPUT);
  pinMode(g, OUTPUT);
  pinMode(dp, OUTPUT);
 
  _seg1 = seg1;
  _seg2 = seg2;
  _seg3 = seg3;
  _seg4 = seg4;
  _a = a;
  _b = b;
  _c = c;
  _d = d;
  _e = e;
  _f = f;
  _g = g;
  _dp = dp;
 
  digitalWrite(_seg1, HIGH);
  digitalWrite(_seg2, HIGH);
  digitalWrite(_seg3, HIGH);
  digitalWrite(_seg4, HIGH);
}

void SevenSeg::setTime(long time) {
_time = time;
if(_time <= 5999000) { //max 99 minutes 59 seconds
_clockValue = _time/1000;
_seconds = _clockValue%60;
_minutes = _clockValue/60;
//_hours = _minutes/60;
//_minutes = _minutes-(_hours*60);
setNumber(_seg1, (int)(_minutes/10), false);
setNumber(_seg2, (int)(_minutes)-(_minutes/10)*(10), true);
setNumber(_seg3, (int)(_seconds/10), false);
setNumber(_seg4, (int)(_seconds)-(_seconds/10)*(10), false);
  } else _time=0;
}


void SevenSeg::setNumber(int segment, int number, boolean dot) {
_pin = _a;
_segment = segment;
if (dot) {
   digitalWrite(_dp, HIGH);
} else digitalWrite(_dp, LOW);
digitalWrite(_segment, LOW);
for (int i=0;i<7;i++) {
digitalWrite(_pin, digits[number][i]);
_pin++;
  }
clearSegment(_segment);
}

void SevenSeg::clearSegment(int segment) {
delay(4);
digitalWrite(segment, HIGH);
}


Or is there any hardware out there i could use to drive the 7-segment for example, that won't have any interrupt calls to it?

dc42

If I understand correctly, you are using something like this:

Code: [Select]

  if (currentTime - previousTime >= interval {
    previousTime = currentTime;


and the problem is that the interval between pictures is not 'interval' but 'interval + 16ms'. In which case, try the following instead:

Code: [Select]

  if (currentTime - previousTime >= interval {
    previousTime += interval;

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

AWOL

Code: [Select]
int digits[11][7] = { { 1,1,1,1,1,1,0 },  // = 0
                      { 0,1,1,0,0,0,0 },  // = 1
                      { 1,1,0,1,1,0,1 },  // = 2
                      { 1,1,1,1,0,0,1 },  // = 3
                      { 0,1,1,0,0,1,1 },  // = 4
                      { 1,0,1,1,0,1,1 },  // = 5
                      { 1,0,1,1,1,1,1 },  // = 6
                      { 1,1,1,0,0,0,0 },  // = 7
                      { 1,1,1,1,1,1,1 },  // = 8
                      { 1,1,1,0,0,1,1 },  // = 9
                      { 0,0,0,0,0,0,0 }   // = blank
                      };

OT: RAM is a very precious resource.
Using 1232 bits of it to store 77 bits worth of information is wasteful in the extreme.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

swiftless

Correct dc42, here is the loop code with your suggestion
Code: [Select]
void loop() {
  currentTime1 = millis();
  seg.setTime(interval);
  if ((currentTime1-previousTime >= interval && interval > 0) || analogRead(buttons) > 1000) {
    Serial.println(currentTime1);
    previousTime += interval;
    takePicture();
  }
  if (analogRead(buttons) >= 890 && analogRead(buttons) <= 910 && (currentTime1 - previousTime) > 150) {
    interval += 5000;
    previousTime = currentTime1;
  }
  if (analogRead(buttons) >= 950 && analogRead(buttons) <= 970 && (currentTime1 - previousTime) > 150) {
    if(interval > 0) {
      interval -= 5000;
      previousTime = currentTime1;
    }
  }
}


Will have to move the button to take pictures to another if statement though, and for some reason
Quote
previousTime += interval;
delivers this result at 5sec intervals:
Code: [Select]
13405
18404
23404
28403
33402
38402
43401
48400
53399
58398
63397
68397
73396
78396
83395
88394
93393
98393
103392
108393
113393
118394
123395
128395
133396
138396
143396
148397
153398
158398
163398
168398
173399
178400
183400
188400
193400
198402
203402
208402
213403
218403
223404
228404
233404
238405
243405
248406
253407
258390
263390
268390
273391
278391
283392
288392
293393
298393
303393
308393
313395
318395
323395
328395
333396
338397
343397
348397
353398
358398
363399
368399
373400
378400
383400
388401
393401
398402
403402
408402
413403
418404
423404
428404
433404
438405
443405
448405
453405
458405





Quote
OT: RAM is a very precious resource.
Using 1232 bits of it to store 77 bits worth of information is wasteful in the extreme.

Any way I can store them differently? And where did you get 1232bits from?

dc42


... and for some reason
Quote
previousTime += interval;
delivers this result at 5sec intervals: ...


Assuming you are printing the time returned by millis(), it looks to me that you are indeed averaging 5 seconds, with jitter of about 10ms. Is that good enough for you?


Quote
OT: RAM is a very precious resource.
Using 1232 bits of it to store 77 bits worth of information is wasteful in the extreme.

Any way I can store them differently? And where did you get 1232bits from?


You're storing each 1 or 0 is an int, which takes 16 bits. So the total is 16 * 11 * 7 bits. You could halve the memory use very simply by using type uint8_t or byte (which are aliases for 'unsigned char') instead of int.

You can also do very much better by storing each group of 7 bits in a uint8_t, like this:

Code: [Select]

int digits[11] = { B01111110,  // = 0
                   B00110000,  // = 1
                   ...
                 };

You'll then need to use shift operations to extract each bit, unless you wire the displays so that all 7 segments are on the same port, in which case you can output the byte direct to that port.

You could also put the table in PROGMEM, with or without doing one of the above as well.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

swiftless

Yep, more than good enough. Thank you for the help and explanation dc42, much appreciated   :%

Go Up