v0.6.262
This commit is contained in:
151
yoRadio/src/yoEncoder/yoEncoder.cpp
Normal file
151
yoRadio/src/yoEncoder/yoEncoder.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
// based on https://github.com/igorantolic/ai-esp32-rotary-encoder code
|
||||
//
|
||||
//
|
||||
|
||||
#include "esp_log.h"
|
||||
#define LOG_TAG "yoEncoder"
|
||||
|
||||
#include "yoEncoder.h"
|
||||
|
||||
void IRAM_ATTR yoEncoder::readEncoder_ISR()
|
||||
{
|
||||
|
||||
unsigned long now = millis();
|
||||
portENTER_CRITICAL_ISR(&(this->mux));
|
||||
if (this->isEnabled)
|
||||
{
|
||||
// code from https://www.circuitsathome.com/mcu/reading-rotary-encoder-on-arduino/
|
||||
/**/
|
||||
this->old_AB <<= 2; //remember previous state
|
||||
|
||||
int8_t ENC_PORT = ((digitalRead(this->encoderBPin)) ? (1 << 1) : 0) | ((digitalRead(this->encoderAPin)) ? (1 << 0) : 0);
|
||||
|
||||
this->old_AB |= (ENC_PORT & 0x03); //add current state
|
||||
|
||||
//this->encoder0Pos += ( this->enc_states[( this->old_AB & 0x0f )]);
|
||||
int8_t currentDirection = (this->enc_states[(this->old_AB & 0x0f)]); //-1,0 or 1
|
||||
|
||||
if (currentDirection != 0)
|
||||
{
|
||||
long prevRotaryPosition = this->encoder0Pos / this->encoderSteps;
|
||||
this->encoder0Pos += currentDirection;
|
||||
long newRotaryPosition = this->encoder0Pos / this->encoderSteps;
|
||||
|
||||
if (newRotaryPosition != prevRotaryPosition && rotaryAccelerationCoef > 1)
|
||||
{
|
||||
//additional movements cause acceleration?
|
||||
// at X ms, there should be no acceleration.
|
||||
unsigned long accelerationLongCutoffMillis = 200;
|
||||
// at Y ms, we want to have maximum acceleration
|
||||
unsigned long accelerationShortCutffMillis = 4;
|
||||
|
||||
// compute linear acceleration
|
||||
if (currentDirection == lastMovementDirection &&
|
||||
currentDirection != 0 &&
|
||||
lastMovementDirection != 0)
|
||||
{
|
||||
// ... but only of the direction of rotation matched and there
|
||||
// actually was a previous rotation.
|
||||
unsigned long millisAfterLastMotion = now - lastMovementAt;
|
||||
|
||||
if (millisAfterLastMotion < accelerationLongCutoffMillis)
|
||||
{
|
||||
if (millisAfterLastMotion < accelerationShortCutffMillis)
|
||||
{
|
||||
millisAfterLastMotion = accelerationShortCutffMillis; // limit to maximum acceleration
|
||||
}
|
||||
if (currentDirection > 0)
|
||||
{
|
||||
this->encoder0Pos += rotaryAccelerationCoef / millisAfterLastMotion;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->encoder0Pos -= rotaryAccelerationCoef / millisAfterLastMotion;
|
||||
}
|
||||
}
|
||||
}
|
||||
this->lastMovementAt = now;
|
||||
this->lastMovementDirection = currentDirection;
|
||||
}
|
||||
|
||||
//respect limits
|
||||
if (this->encoder0Pos > (this->_maxEncoderValue))
|
||||
this->encoder0Pos = this->_circleValues ? this->_minEncoderValue : this->_maxEncoderValue;
|
||||
if (this->encoder0Pos < (this->_minEncoderValue))
|
||||
this->encoder0Pos = this->_circleValues ? this->_maxEncoderValue : this->_minEncoderValue;
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL_ISR(&(this->mux));
|
||||
}
|
||||
|
||||
|
||||
yoEncoder::yoEncoder(uint8_t encoder_APin, uint8_t encoder_BPin, uint8_t encoderSteps, bool internalPullup)
|
||||
{
|
||||
this->old_AB = 0;
|
||||
|
||||
this->encoderAPin = encoder_APin;
|
||||
this->encoderBPin = encoder_BPin;
|
||||
this->encoderSteps = encoderSteps;
|
||||
|
||||
pinMode(this->encoderAPin, internalPullup?INPUT_PULLUP:INPUT_PULLDOWN);
|
||||
pinMode(this->encoderBPin, internalPullup?INPUT_PULLUP:INPUT_PULLDOWN);
|
||||
}
|
||||
|
||||
void yoEncoder::setBoundaries(long minEncoderValue, long maxEncoderValue, bool circleValues)
|
||||
{
|
||||
this->_minEncoderValue = minEncoderValue * this->encoderSteps;
|
||||
this->_maxEncoderValue = maxEncoderValue * this->encoderSteps;
|
||||
|
||||
this->_circleValues = circleValues;
|
||||
}
|
||||
|
||||
long yoEncoder::readEncoder()
|
||||
{
|
||||
return (this->encoder0Pos / this->encoderSteps);
|
||||
}
|
||||
|
||||
void yoEncoder::setEncoderValue(long newValue)
|
||||
{
|
||||
reset(newValue);
|
||||
}
|
||||
|
||||
long yoEncoder::encoderChanged()
|
||||
{
|
||||
long _encoder0Pos = readEncoder();
|
||||
long encoder0Diff = _encoder0Pos - this->lastReadEncoder0Pos;
|
||||
|
||||
this->lastReadEncoder0Pos = _encoder0Pos;
|
||||
|
||||
return encoder0Diff;
|
||||
}
|
||||
|
||||
void yoEncoder::setup(void (*ISR_callback)(void))
|
||||
{
|
||||
attachInterrupt(digitalPinToInterrupt(this->encoderAPin), ISR_callback, CHANGE);
|
||||
attachInterrupt(digitalPinToInterrupt(this->encoderBPin), ISR_callback, CHANGE);
|
||||
}
|
||||
|
||||
void yoEncoder::begin()
|
||||
{
|
||||
this->lastReadEncoder0Pos = 0;
|
||||
}
|
||||
|
||||
void yoEncoder::reset(long newValue_)
|
||||
{
|
||||
newValue_ = newValue_ * this->encoderSteps;
|
||||
this->encoder0Pos = newValue_;
|
||||
this->lastReadEncoder0Pos = this->encoder0Pos;
|
||||
if (this->encoder0Pos > this->_maxEncoderValue)
|
||||
this->encoder0Pos = this->_circleValues ? this->_minEncoderValue : this->_maxEncoderValue;
|
||||
if (this->encoder0Pos < this->_minEncoderValue)
|
||||
this->encoder0Pos = this->_circleValues ? this->_maxEncoderValue : this->_minEncoderValue;
|
||||
}
|
||||
|
||||
void yoEncoder::enable()
|
||||
{
|
||||
this->isEnabled = true;
|
||||
}
|
||||
void yoEncoder::disable()
|
||||
{
|
||||
this->isEnabled = false;
|
||||
}
|
||||
68
yoRadio/src/yoEncoder/yoEncoder.h
Normal file
68
yoRadio/src/yoEncoder/yoEncoder.h
Normal file
@@ -0,0 +1,68 @@
|
||||
// yoEncoder.h
|
||||
// based on https://github.com/igorantolic/ai-esp32-rotary-encoder code
|
||||
|
||||
#ifndef _YOENCODER_h
|
||||
#define _YOENCODER_h
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BUT_DOWN = 0,
|
||||
BUT_PUSHED = 1,
|
||||
BUT_UP = 2,
|
||||
BUT_RELEASED = 3,
|
||||
BUT_DISABLED = 99,
|
||||
} ButtonState;
|
||||
|
||||
class yoEncoder
|
||||
{
|
||||
|
||||
private:
|
||||
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
|
||||
portMUX_TYPE buttonMux = portMUX_INITIALIZER_UNLOCKED;
|
||||
volatile long encoder0Pos = 0;
|
||||
|
||||
volatile int8_t lastMovementDirection = 0; //1 right; -1 left
|
||||
volatile unsigned long lastMovementAt = 0;
|
||||
unsigned long rotaryAccelerationCoef = 150;
|
||||
|
||||
bool _circleValues = false;
|
||||
bool isEnabled = true;
|
||||
|
||||
uint8_t encoderAPin;
|
||||
uint8_t encoderBPin;
|
||||
long encoderSteps;
|
||||
|
||||
long _minEncoderValue = -1 << 15;
|
||||
long _maxEncoderValue = 1 << 15;
|
||||
|
||||
uint8_t old_AB;
|
||||
long lastReadEncoder0Pos;
|
||||
|
||||
int8_t enc_states[16] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
|
||||
void (*ISR_callback)();
|
||||
|
||||
public:
|
||||
yoEncoder(
|
||||
uint8_t encoderAPin,
|
||||
uint8_t encoderBPin,
|
||||
uint8_t encoderSteps,
|
||||
bool internalPullup = true);
|
||||
void setBoundaries(long minValue = -100, long maxValue = 100, bool circleValues = false);
|
||||
void IRAM_ATTR readEncoder_ISR();
|
||||
|
||||
void setup(void (*ISR_callback)(void));
|
||||
void begin();
|
||||
void reset(long newValue = 0);
|
||||
void enable();
|
||||
void disable();
|
||||
long readEncoder();
|
||||
void setEncoderValue(long newValue);
|
||||
long encoderChanged();
|
||||
|
||||
unsigned long getAcceleration() { return this->rotaryAccelerationCoef; }
|
||||
void setAcceleration(unsigned long acceleration) { this->rotaryAccelerationCoef = acceleration; }
|
||||
void disableAcceleration() { setAcceleration(0); }
|
||||
};
|
||||
#endif
|
||||
Reference in New Issue
Block a user