After having some experiments with encoder on breadboard with STM32F411CE (WeAct board), i am made simple example to use it with timer working in hardware encoder mode. Tested with all combinations of pins that can be used for encoder input. I didn't use any debounce hardware, encoder module have 10k pull-ups. No noticeable jitter, but not accurate at high-speed. Should be enough for some LCD menu or something. Tested also with internal pull-ups, but i found them unreliable.
Code: Select all
// pins must be channel 1 and channel 2 on a timer that support hardware encoder mode
/*
STM32F411CE:
+----------+-----------+-----------+
| | CLK | DT |
+----------+-----------+-----------+
| TIMER1 | PA8 | PA9 |
+----------+-----------+-----------+
| TIMER2 | PA0 | PA1 |
| | PA5 | PB3 |
| | PA15 | |
+----------+-----------+-----------+
| TIMER3 | PA6 | PA7_ALT1 |
| | PB4 | PB5 |
+----------+-----------+-----------+
| TIMER4 | PB6 | PB7 |
+----------+-----------+-----------+
| TIMER5 | PA0_ALT1 | PA1_ALT1 |
+----------+-----------+-----------+
*/
#define pinCLK PB4
#define pinDT PB5
// TIMER9-11 don't support hardware encoder mode
HardwareTimer *MyEncoder ; // encoder connected to ch1/ch2 of TIMx
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
delay(4000);
Serial.println("START");
// pinMode(pinCLK, INPUT_PULLUP); // internal pull-up
// pinMode(pinDT , INPUT_PULLUP); // but unreliable
// Instantiate HardwareTimer object. Thanks to 'new' instantiation, HardwareTimer is not destructed when setup() function is finished.
TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pinCLK), PinMap_PWM);
uint32_t channel_1 = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pinCLK), PinMap_PWM));
uint32_t channel_2 = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pinDT ), PinMap_PWM));
MyEncoder = new HardwareTimer(Instance);
MyEncoder->pause();
MyEncoder->setOverflow(65536 , TICK_FORMAT);
MyEncoder->setPrescaleFactor(1);
MyEncoder->setMode(channel_1, TIMER_INPUT_CAPTURE_FALLING, pinCLK);
MyEncoder->setMode(channel_2, TIMER_INPUT_CAPTURE_FALLING, pinDT );
Instance->SMCR |= TIM_ENCODERMODE_TI12; // set encoder moder (counting both rising and falling edges on both channels)
MyEncoder->resume();
if (Instance == TIM1) {
Serial.println("Encoder is on TIM1");
}
if (Instance == TIM2) {
Serial.println("Encoder is on TIM2");
}
if (Instance == TIM3) {
Serial.println("Encoder is on TIM3");
}
if (Instance == TIM4) {
Serial.println("Encoder is on TIM4");
}
if (Instance == TIM5) {
Serial.println("Encoder is on TIM5");
}
delay(1000);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.println(int16_t( MyEncoder->getCount() ) / 4);
delay(random(1000) + 1);
}