0

So I am trying to use a rotary encoders to control menu on my STM32 project. I am using two rotary encoders to control each side of the screen (split menu).

When I initialize the ARR registers of both timers which are responsible for counting the encoder's pulses, it initializes the registers to a 0 value and when I move the encoders counterclockwise the registers overflow and goes to maximum values of 65535 and messes with how my code calculates detents.

Can you guys tell me if there is any way to set the the TIM->CNT value to a custom value somewhere in the middle between 0 and 65535 ? This way I could easily check differences between values and not worry about the jump in numbers.

  • The difference will fall out naturally when modular arithmetic matching the range of the counter, in this case doing the subtraction with 16-bit integers. That is `(int16_t) (new_count - old_count)` will compute the difference between the two samples, assuming that the total change in between did not exceeded -32768 to +32767. – doynax Nov 24 '17 at 22:07
  • That is exactly what I thought when I first wrote the code, but I noticed inconsistent behavior when around 0. For whatever reason I cannot get the negative values out of the TIM->CNT, it goes straight to the largest possible value, and I made sure the variable is a signed integer. – Pawel_Sparky Nov 24 '17 at 22:44

1 Answers1

1

when I move the encoders counterclockwise the registers overflow and goes to maximum values of 65535 and messes with how my code calculates detents.

The counter is a 16 bit value put into a 32 bit unsigned register. To get a proper signed value, cast it to int16_t.

int wheelposition = (int16_t)TIMx->CNT;

A value of 65535 (0xFFFF) would be sign-extended to 0xFFFFFFFF, which is interpreted as -1 in a 32 bit integer variable. But then you'd have the problem that it'd overflow from -32768 to +32767.

If you are interested in the signed difference of two position readings, you can do the subtraction on the unsigned values, and cast the result to int16_t.

uint32_t oldposition, newposition;
int wheelmovement;
oldposition = TIMx->CNT;
/* wait a bit */
newposition = TIMx->CNT;
wheelmovement = (int16_t)(newposition - oldposition);

It will give you the signed difference, with 16 bit overflow taken into account.

is any way to set the the TIM->CNT value to a custom value somewhere in the middle between 0 and 65535 ?

You can simply assign any value to TIMx->CNT, it will continue counting from there.

  • Setting the TIMx->CNT has resolved my problem! Thank you very much. For whatever reason I cannot get negative values even casting to a signed integer. But staying away from zero will be just fine, there is no way anyone would turn the encoder far enough to go past 32K pulses. Also in my microcontroller the ARR is a 16 bit register as I am using STM32L152RCT6 – Pawel_Sparky Nov 25 '17 at 15:37