|
@ -15,12 +15,7 @@ |
|
|
|
|
|
|
|
|
//using namespace std;
|
|
|
//using namespace std;
|
|
|
|
|
|
|
|
|
TaskHandle_t Rotary::xTaskToNotify = NULL; |
|
|
Rotary::Rotary() {} |
|
|
Rotary* Rotary::instance = NULL; |
|
|
|
|
|
|
|
|
|
|
|
Rotary::Rotary() { |
|
|
|
|
|
instance = this; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool Rotary::begin(uint8_t pinA, uint8_t pinB, uint8_t pinButton) { |
|
|
bool Rotary::begin(uint8_t pinA, uint8_t pinB, uint8_t pinButton) { |
|
|
this->pinA = pinA; |
|
|
this->pinA = pinA; |
|
@ -30,112 +25,37 @@ bool Rotary::begin(uint8_t pinA, uint8_t pinB, uint8_t pinButton) { |
|
|
pinMode(pinB, INPUT_PULLUP); |
|
|
pinMode(pinB, INPUT_PULLUP); |
|
|
pinMode(pinButton, INPUT_PULLUP); |
|
|
pinMode(pinButton, INPUT_PULLUP); |
|
|
|
|
|
|
|
|
|
|
|
encoder = new ClickEncoder(pinA, pinB, pinButton, 4); |
|
|
|
|
|
//encoder->setButtonOnPinZeroEnabled(true);
|
|
|
|
|
|
|
|
|
xTaskCreate( |
|
|
xTaskCreate( |
|
|
&cTaskWrapper, /* Task function. */ |
|
|
&cTaskWrapper, /* Task function. */ |
|
|
"buttonTask", /* String with name of task. */ |
|
|
"encoderTask", /* String with name of task. */ |
|
|
2048, /* Stack size in words. */ |
|
|
1024, /* Stack size in words. */ |
|
|
this, /* Parameter passed as input of the task */ |
|
|
this, /* Parameter passed as input of the task */ |
|
|
tskIDLE_PRIORITY+2, /* Priority of the task. */ |
|
|
tskIDLE_PRIORITY+2, /* Priority of the task. */ |
|
|
&buttonTaskHandle); /* Task handle. */ |
|
|
&taskHandle); /* Task handle. */ |
|
|
return true; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Rotary::cTaskWrapper(void* parameters) { |
|
|
void Rotary::cTaskWrapper(void* parameters) { |
|
|
static_cast<Rotary*>(parameters)->button_task(NULL); |
|
|
static_cast<Rotary*>(parameters)->task(NULL); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Rotary::button_task(void *pvParameters) { |
|
|
void Rotary::task(void *pvParameters) { |
|
|
xTaskToNotify = xTaskGetCurrentTaskHandle(); |
|
|
|
|
|
|
|
|
|
|
|
attachInterrupt(digitalPinToInterrupt(pinA), doEncoderA, RISING); |
|
|
|
|
|
attachInterrupt(digitalPinToInterrupt(pinB), doEncoderB, RISING); |
|
|
|
|
|
// attachInterrupt(digitalPinToInterrupt(pinButton), doButton, FALLING);
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t ulNotificationValue; |
|
|
|
|
|
uint32_t ulStatusValue; |
|
|
|
|
|
|
|
|
|
|
|
while(true) { |
|
|
while(true) { |
|
|
rotating = true; // reset the debouncer
|
|
|
encoder->service(); |
|
|
|
|
|
value += encoder->getValue(); |
|
|
ulNotificationValue = xTaskNotifyWait(0x00, ULONG_MAX, &ulStatusValue, portMAX_DELAY ); |
|
|
if (value != last) { |
|
|
|
|
|
last = value; |
|
|
// if ( rotating ) delay (1); // wait a little until the bouncing is done
|
|
|
if (callback) callback(value); |
|
|
|
|
|
|
|
|
if( ulStatusValue == 1 ) { |
|
|
|
|
|
// adjust counter + if A leads B
|
|
|
|
|
|
encoderPos += 1; |
|
|
|
|
|
changed(); |
|
|
|
|
|
rotating = false; // no more debouncing until loop() hits again
|
|
|
|
|
|
} else if ( ulStatusValue == 2 ) { |
|
|
|
|
|
// adjust counter -1 if B leads A
|
|
|
|
|
|
encoderPos -= 1; |
|
|
|
|
|
changed(); |
|
|
|
|
|
rotating = false; // no more debouncing until loop() hits again
|
|
|
|
|
|
} else if ( ulStatusValue == 4 ) { |
|
|
|
|
|
Button_set = digitalRead(pinButton); |
|
|
|
|
|
|
|
|
|
|
|
if (! Button_set ) { |
|
|
|
|
|
encoderPos = 0; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
vTaskDelay(1 / portTICK_PERIOD_MS); |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Rotary::changed() { |
|
|
|
|
|
if (lastReportedPos != encoderPos) { |
|
|
|
|
|
if (callback) callback(encoderPos); |
|
|
|
|
|
lastReportedPos = encoderPos; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
vTaskDelete(NULL); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool Rotary::registerCallback(std::function<void(int)> callback) { |
|
|
bool Rotary::registerCallback(std::function<void(int)> callback) { |
|
|
this->callback = callback; |
|
|
this->callback = callback; |
|
|
return true; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Rotary::doButton() { |
|
|
|
|
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE; |
|
|
|
|
|
|
|
|
|
|
|
configASSERT( xTaskToNotify != NULL ); |
|
|
|
|
|
uint32_t intrBits = 4; |
|
|
|
|
|
xTaskNotifyFromISR( xTaskToNotify, intrBits, eSetValueWithoutOverwrite, &xHigherPriorityTaskWoken ); |
|
|
|
|
|
portYIELD_FROM_ISR(); //portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Interrupt on A changing state
|
|
|
|
|
|
void Rotary::doEncoderA() { |
|
|
|
|
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE; |
|
|
|
|
|
if (instance->skipA) { |
|
|
|
|
|
instance->skipA = false; |
|
|
|
|
|
instance->debounceA = millis(); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if (!digitalRead(instance->pinB) && ((millis() - instance->debounceA) > instance->debounceDelay)) { |
|
|
|
|
|
instance->debounceA = millis(); |
|
|
|
|
|
instance->skipB = true; |
|
|
|
|
|
configASSERT( xTaskToNotify != NULL ); |
|
|
|
|
|
uint32_t intrBits = 1; |
|
|
|
|
|
xTaskNotifyFromISR( xTaskToNotify, intrBits, eSetValueWithoutOverwrite, &xHigherPriorityTaskWoken ); |
|
|
|
|
|
portYIELD_FROM_ISR(); //portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Interrupt on B changing state, same as A above
|
|
|
|
|
|
void Rotary::doEncoderB() { |
|
|
|
|
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE; |
|
|
|
|
|
if (instance->skipB) { |
|
|
|
|
|
instance->skipB = false; |
|
|
|
|
|
instance->debounceB = millis(); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if (!digitalRead(instance->pinA) && ((millis() - instance->debounceB) > instance->debounceDelay)) { |
|
|
|
|
|
instance->debounceB = millis(); |
|
|
|
|
|
instance->skipA = true; |
|
|
|
|
|
configASSERT( xTaskToNotify != NULL ); |
|
|
|
|
|
uint32_t intrBits = 2; |
|
|
|
|
|
xTaskNotifyFromISR( xTaskToNotify, intrBits, eSetValueWithoutOverwrite, &xHigherPriorityTaskWoken ); |
|
|
|
|
|
portYIELD_FROM_ISR(); //portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|