I am developing mobile robot. Hear i required to read quadrature encoder.So i am using stm32F401 using 16bit timer(encoder mode) to read the count.After 65535 count goes to 0. My question is how to make the counter larger.
Thanks
Electrical Engineering Stack Exchange is a question and answer site for electronics and electrical engineering professionals, students, and enthusiasts. It only takes a minute to sign up.
Sign up to join this communityI am developing mobile robot. Hear i required to read quadrature encoder.So i am using stm32F401 using 16bit timer(encoder mode) to read the count.After 65535 count goes to 0. My question is how to make the counter larger.
Thanks
I can see 2 solution :
Use a 32 bit timer instead of a 16 bit timer : you haven't specifyed the exact micro-controler you use, but at least for STM32F401xB/STM32F401xC (section 3.19.2), there are 2 timers with 32 bits (TIM2 and TIM5), which seem to be capable of encoder mode. That way, you get twice the number of bits. It might (or not) be enough for you to garantee that you will never exceed the limit. NB : I didn't checked if all other stm32F401 version have those 323 bits timers.
If you need more than 2 encoders, if TIM 2 or TIM5 are needed for something else (or your specific micro-controler don't have them), or if anyway even 32 bits is not enough, then you can solve the problem in software :
A better way (in the general case) to solve this problem than hard coding checks for jumps in value:
#define ONE_PERIOD 65536
#define HALF_PERIOD 32768
int32_t unwrap_encoder(uint16_t in, int32_t * prev)
{
int32_t c32 = (int32_t)in - HALF_PERIOD; //remove half period to determine (+/-) sign of the wrap
int32_t dif = (c32-*prev); //core concept: prev + (current - prev) = current
//wrap difference from -HALF_PERIOD to HALF_PERIOD. modulo prevents differences after the wrap from having an incorrect result
int32_t mod_dif = ((dif + HALF_PERIOD) % ONE_PERIOD) - HALF_PERIOD;
if(dif < -HALF_PERIOD)
mod_dif += ONE_PERIOD; //account for mod of negative number behavior in C
int32_t unwrapped = *prev + mod_dif;
*prev = unwrapped; //load previous value
return unwrapped + HALF_PERIOD; //remove the shift we applied at the beginning, and return
}
This is essentially doing output = previous + (current - previous). The magic happens in the (current-previous) part, by using modulo. Modulo allows you to determine the correct difference between two values, after a wrap has occurred.
For instance, if you're sampling an encoder and your current position is 3 radians, and the previous angle was -3 radians, you know that you probably made a jump of -0.2832 radians (as opposed to +6 radians).
So all this algorithm is doing is finding the 'nearest difference' between the last two samples and adding that difference to the previous value, thus restoring the true encoder count.
This method also implicitly turns an unsigned angle count (0 to 65535) into a signed angle count, whose size is capped by the max value of whatever container you use in the function (i.e. int32). So if you started at zero and spun the encoder backwards, the output of this function will give you a negative value without any additional logic needed.
Simple solution, if you see that the count jumps such a large value, it means in really just increased by one and rolled over.