|
|
@ -1,13 +1,5 @@ |
|
|
|
/* interrupt routine for Rotary Encoders
|
|
|
|
tested with Noble RE0124PVB 17.7FINB-24 http://www.nobleusa.com/pdf/xre.pdf - available at pollin.de
|
|
|
|
and a few others, seems pretty universal |
|
|
|
|
|
|
|
The average rotary encoder has three pins, seen from front: A C B |
|
|
|
Clockwise rotation A(on)->B(on)->A(off)->B(off) |
|
|
|
CounterCW rotation B(on)->A(on)->B(off)->A(off) |
|
|
|
|
|
|
|
and may be a push switch with another two pins, pulled low at pin 8 in this case |
|
|
|
raf@synapps.de 20120107 |
|
|
|
idea from: https://github.com/marcmerlin/IoTuz/blob/95f53be6569c68f7fbef491bb36082870f82d629/IoTuz.cpp
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
@ -15,7 +7,11 @@ |
|
|
|
|
|
|
|
//using namespace std;
|
|
|
|
|
|
|
|
Rotary::Rotary() {} |
|
|
|
Rotary* Rotary::instance = NULL; |
|
|
|
|
|
|
|
Rotary::Rotary() { |
|
|
|
instance = this; |
|
|
|
} |
|
|
|
|
|
|
|
bool Rotary::begin(uint8_t pinA, uint8_t pinB, uint8_t pinButton) { |
|
|
|
this->pinA = pinA; |
|
|
@ -25,9 +21,6 @@ bool Rotary::begin(uint8_t pinA, uint8_t pinB, uint8_t pinButton) { |
|
|
|
pinMode(pinB, INPUT_PULLUP); |
|
|
|
pinMode(pinButton, INPUT_PULLUP); |
|
|
|
|
|
|
|
encoder = new ClickEncoder(pinA, pinB, pinButton, 4); |
|
|
|
//encoder->setButtonOnPinZeroEnabled(true);
|
|
|
|
|
|
|
|
xTaskCreate( |
|
|
|
&cTaskWrapper, /* Task function. */ |
|
|
|
"encoderTask", /* String with name of task. */ |
|
|
@ -35,6 +28,10 @@ bool Rotary::begin(uint8_t pinA, uint8_t pinB, uint8_t pinButton) { |
|
|
|
this, /* Parameter passed as input of the task */ |
|
|
|
tskIDLE_PRIORITY+2, /* Priority of the task. */ |
|
|
|
&taskHandle); /* Task handle. */ |
|
|
|
|
|
|
|
attachInterrupt(digitalPinToInterrupt(pinA), doEncoder, CHANGE); |
|
|
|
attachInterrupt(digitalPinToInterrupt(pinB), doEncoder, CHANGE); |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
@ -43,14 +40,13 @@ void Rotary::cTaskWrapper(void* parameters) { |
|
|
|
} |
|
|
|
|
|
|
|
void Rotary::task(void *pvParameters) { |
|
|
|
xTaskToNotify = xTaskGetCurrentTaskHandle(); |
|
|
|
uint32_t ulNotificationValue; |
|
|
|
while(true) { |
|
|
|
encoder->service(); |
|
|
|
value += encoder->getValue(); |
|
|
|
if (value != last) { |
|
|
|
last = value; |
|
|
|
if (callback) callback(value); |
|
|
|
} |
|
|
|
vTaskDelay(1 / portTICK_PERIOD_MS); |
|
|
|
ulNotificationValue = ulTaskNotifyTake( pdFALSE, portMAX_DELAY ); |
|
|
|
int newPos = encoderPos/2; |
|
|
|
if (lastPos != newPos) |
|
|
|
if (callback) callback(newPos); |
|
|
|
} |
|
|
|
vTaskDelete(NULL); |
|
|
|
} |
|
|
@ -59,3 +55,28 @@ bool Rotary::registerCallback(std::function<void(int)> callback) { |
|
|
|
this->callback = callback; |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
// Interrupt on changing state
|
|
|
|
void Rotary::doEncoder() { |
|
|
|
if ((millis() - instance->debounceMillis) > instance->debounceDelay) { |
|
|
|
instance->debounceMillis = millis(); |
|
|
|
|
|
|
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE; |
|
|
|
|
|
|
|
static uint8_t old_AB = 0; |
|
|
|
// grey code
|
|
|
|
// http://hades.mech.northwestern.edu/index.php/Rotary_Encoder
|
|
|
|
// also read up on 'Understanding Quadrature Encoded Signals'
|
|
|
|
// https://www.pjrc.com/teensy/td_libs_Encoder.html
|
|
|
|
// another interesting lib: https://github.com/0xPIT/encoder/blob/arduino/ClickEncoder.cpp
|
|
|
|
static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; |
|
|
|
|
|
|
|
old_AB <<= 2; |
|
|
|
old_AB |= ((digitalRead(instance->pinB))?(1<<1):0) | ((digitalRead(instance->pinA))?(1<<0):0); |
|
|
|
instance->encoderPos += ( enc_states[( old_AB & 0x0f )]); |
|
|
|
|
|
|
|
configASSERT( instance->xTaskToNotify != NULL ); |
|
|
|
vTaskNotifyGiveFromISR( instance->xTaskToNotify, &xHigherPriorityTaskWoken ); |
|
|
|
portYIELD_FROM_ISR(); //portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
|
|
|
} |
|
|
|
} |
|
|
|