Integer wrapper is not very clear

I have the following piece of code called about 100 times per second

if (elapsed_centiseconds_mod_60000 < 59999) {
    ++elapsed_centiseconds_mod_60000;
} else {
    elapsed_centiseconds_mod_60000 = 0;
}
if (elapsed_centiseconds_mod_60000 % 6000 == 0) {
    ++elapsed_minutes;
}

      

Types of variables and constants

volatile uint16_t elapsed_centiseconds_mod_60000;
volatile uint8_t start_minute_mod_10;
const int8_t calibration_second = 5;

      

Then exactly once per second the

int16_t get_phase_deviation(uint8_t current_second, uint8_t current_minute_mod_10) {
    int32_t deviation=
         (int32_t) elapsed_centiseconds_mod_60000 -
        ((int32_t) current_second        + (int32_t)600 - (int32_t)calibration_second) * (int32_t) 100 -
        ((int32_t) current_minute_mod_10 + (int32_t) 60 - (int32_t)start_minute_mod_10)* (int32_t)6000;
    deviation %= 60000;

    return (int16_t)(deviation<=30000? deviation: deviation-60000);
}

      

The idea behind the code is to detect the relative frequency error of two oscillators. However, the code doesn't work as expected. It will start to output the deviation from zero. But as soon as the elapsed centiseconds are greater than they should immediately jump to output 5537, matches 2 ^ 16% 60000 + 1. I tried to pass intermediate values ​​to int32_t, but still the problem remains. Usually the problem occurs after 100 seconds or 10,000 centimeters. I suspect some are wrapping up the problem, but I can't see it.

Are there any ideas what term is causing this and why?

+3


source to share


1 answer


You chose the wrong return value get_phase_deviation()

because the range deviation %= 60000

is -59999 to 59999

(not 0 to 59999

). You must change the line:

 return (int16_t)(deviation<=30000? deviation: deviation-60000);

      

to properly treat deviations <= -30000 as appropriate, or change the return type to int32_t

.

Taking a look at specific cases to understand the numbers you were getting assuming:

 calibration_second = 0;
 start_minute_mod_10 = 0;

      



Then for an ideal system it get_phase_deviation()

returns:

 deviation = -420000; // As computed
 deviation %= 60000;  // == 0
 return 0;

      

If you are 1 centimeter ahead, this changes to:

 deviation = -419999; // As computed
 deviation %= 60000;  // == -59999
 return (int16_t) (-59999);  // == 5537

      

+3


source







All Articles