Best way to parse total seconds to hour,min,sec

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Trying to convert a 32bit register containing the current time of day in seconds into hours(24), min, sec format.

Using this causes time_calc to explode at the hours = (time_calc/3600) line.

	hours = (time_calc/3600); //load up the hours
	time_calc = (time_calc - (hours*3600));
	minutes = time_calc/60; //load up the minutes
	time_calc = (time_calc - (minutes*60));
	seconds = time_calc;

time_calc has a value of 71166 going into this. After the 1st line hours goes to 19, which is correct, but time_calc goes to 181272576. I cant figure out why that's happening.

You don't gno-me!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lets see your variable declarations. Hours is probably decalred as a char so the hours * 3600 won't work too well. You'll need to cast the variables to force the compiler to do 32bit calcs.

eg:
time_calc = time_calc - ((uint32_t)hours * 3600L);

also read up on the modulus % operator.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
also read up on the modulus % operator.
Using modulus would be wasteful here as it would invoke a second divide. However you can use ldiv() to get both the quot and the remainder in one divide.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
Lets see your variable declarations.

	volatile uint32_t time_temp=0, time_calc=0;
	volatile uint8_t hours=0, minutes=0, seconds=0;

I changed to:

time_calc = time_temp;
	hours = ((uint32_t)time_calc/3600L); //load up the hours
	time_calc = time_calc - ((uint32_t)hours * 3600L); 
	minutes = time_calc/60; //load up the minutes
	time_calc = (time_calc - (minutes*60));
	seconds = time_calc;

and ran it and for whatever reason it seems to work. Although I cant understand why it works because after it runs hours = ((uint32_t)time_calc/3600L); time_calc goes to some ridiculously high value still. But the minutes calculation seems to come out correct still. Why would that line cause the value of time_calc to change when it shouldn't?

As I single step though the lines:
Going into: hours = ((uint32_t)time_calc/3600L); //load up the hour
time_calc value is 78886
On the next line: time_calc = time_calc - ((uint32_t)hours * 3600L);
hours is 21 and time_calc is 215351296 (wrong!)
Next: minutes = time_calc/60; //load up the minutes
time_calc is 3286
next: time_calc = (time_calc - (minutes*60));
time_calc is 3286 and minutes is 54
then the next two time_calc and sec turn into 46

You don't gno-me!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When single stepping, you may get weird values displayed as the compiler may not necessarily order the code as you expect. If you do a printf of the results, are they correct?

The next question is what toolset are you using? I did see some defect reports recently.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
Using modulus would be wasteful here as it would invoke a second divide.
Well, you could use an optimizing compiler like avr-gcc.

With the current version of that compiler and optimizing for code size, you'll get

toHMS:
	ldi r18,lo8(60)
	ldi r19,0
	ldi r20,0
	ldi r21,0
	rcall __udivmodsi4
	sts seconds,r22
	movw r24,r18
	ldi r22,lo8(60)
	ldi r23,0
	rcall __udivmodhi4
	sts minutes,r24
	sts hours,r22
	ret

out of

unsigned char hours, minutes, seconds;

void toHMS (unsigned long time_calc)
{
    unsigned tc;
    seconds = time_calc % 60;
    tc = time_calc / 60;
    
    minutes = tc % 60;
    hours   = tc / 60;
}

If you are after code site rather than after speed, you can perform the second divmod as long.

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As hours will be fairly small (0-23), and minutes also a rather small number (0-59) I think that repeated subtraction (as might be used for binary->BCD) might work out fine.

(Nice compiler work recognizing the divmod situation without explicitly being invoked.)

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This same requirement comes up again and again here. If you just search "time.h" you may hit prior traffic.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The tech note AVR134 has a pretty efficient clock algorithm. When combined with AVR204 BCD conversion codes, it makes for a nice clock program. I am using these with my Wurlitzer record system as there needs to be a minimal DOS timestamp on the saved file. It is not too difficult to mod AVR35 code to save the time using the bit packed DOS date/time code. For my use 2 second resolution is fine.