#define calculation problem

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

Could you please give me some sort of hint as to why the following does not work:

#define FOSC 4000000L
#define BAUDRATE 19200L
#define BAUDCOUNT (FOSC/(BAUDRATE*16) - 1)

(results in -195 being loaded into registers), but this does:

#define FOSC 4000000L
#define BAUDCOUNT (FOSC/(307200) - 1)

I'm using the latest version of WinAVR.
I would have thought that they were identical!

Gavin

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

What seems to be happening is BAUDRATE remains a 16bit value even though the 'L' modifier is being used.
(19200UL*4) yields 11264 as the answer which is 0x2C00. The answer should have been 76800 which is 0x12C00.

How can I force the size of 19200 to be a long and thus have enough room to hold the result after the multiplication?

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

Try forcing all components of the calculation as longs.

#define FOSC 4000000L
#define BAUDRATE 19200L
#define BAUDCOUNT (FOSC/(BAUDRATE*16L) - 1L) 

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

Thanks, that seems to have done the trick!

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

BTW - Be careful with those style. Integer math trunacts - right?

For example if you have a clock of 3.68 MHz, and a baud of 115200. By integer math you get 0, by floating point you get 1. And the correct value is 1. Does the preprocessor use Integer or Floating Point style math here? Its late so I'm not going to worry about it tonight :p

-Colin

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

You can implement rounding by modifying the equation like this:

#define BAUDCOUNT ((((FOSC / BAUDRATE) + 8L) / 16L) - 1L) 

Be aware, however, that if rounding significantly affects the result, the actual bit rate may not be close enough to the required bit rate for reliable serial comm. The manual recommends, for best noise immunity, that the variance be no more than 0.5%.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

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

I still seem to have a problem. Try something like the following:

uint16_t Value;

Value = (256UL*256UL)/2UL);

You'll find that Value ends up with 0x0000 in it because when the two 256 values are multiplied they still seems to be stored as a 16 bit value which then overflows and 0x0000 / 2UL is still 0x0000!

Why does the 'UL' get ignored?

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

Not confirmed. The following code:

int
main(void)
{
        return (256UL * 256UL) / 2UL;
}

translates here into:

...
/* prologue end (size=4) */
        ldi r24,lo8(-32768)
        ldi r25,hi8(-32768)
/* epilogue: frame size=0 */
...

which looks correct to me.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

The problem was the -mint8 option. It would seem that constants that are declared using the 'UL' are treated as 16 bits. When I used the 'ULL' option for the constants together with the -mint8 option the problem went away.

Thanks for the help

Gavin

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

That makes sense. When -mint8 is used int is 8 bits, long is 16 bits, long long is 32. Without -mint8 int is 16 bits, long is 32 bits and long long is 64.

- Bill