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?
source to share
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
source to share