This commit is contained in:
e2002
2022-05-24 10:09:19 +03:00
parent 4f6d131cf5
commit 90d97af3e8
12 changed files with 310 additions and 41 deletions

View 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;
}

View 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