You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

159 lines
4.6 KiB

/* 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
*/
#include "rotary.h"
//using namespace std;
TaskHandle_t Rotary::xTaskToNotify = NULL;
Rotary::Rotary() {}
bool Rotary::begin(uint8_t pinA, uint8_t pinB, uint8_t pinButton) {
this->pinA = pinA;
this->pinB = pinB;
this->pinButton = pinButton;
pinMode(pinA, INPUT_PULLUP);
pinMode(pinB, INPUT_PULLUP);
pinMode(pinButton, INPUT_PULLUP);
xTaskCreate(
&cTaskWrapper, /* Task function. */
"buttonTask", /* String with name of task. */
2048, /* Stack size in words. */
this, /* Parameter passed as input of the task */
tskIDLE_PRIORITY+2, /* Priority of the task. */
&buttonTaskHandle); /* Task handle. */
return true;
}
void Rotary::cTaskWrapper(void* parameters) {
static_cast<Rotary*>(parameters)->button_task(NULL);
}
void Rotary::button_task(void *pvParameters) {
xTaskToNotify = xTaskGetCurrentTaskHandle();
attachInterrupt(digitalPinToInterrupt(pinA), doEncoderA, CHANGE);
attachInterrupt(digitalPinToInterrupt(pinB), doEncoderB, CHANGE);
// attachInterrupt(digitalPinToInterrupt(pinButton), doButton, CHANGE);
uint32_t ulNotificationValue;
while(true) {
ulNotificationValue = xTaskNotifyWait(0x00, ULONG_MAX, &ulNotificationValue, portMAX_DELAY );
Serial.printf("interrupt %d, rotating: %d\n", ulNotificationValue, rotating);
if( ulNotificationValue == 1 ) {
// debounce
if ( rotating ) delay (1); // wait a little until the bouncing is done
// Test transition, did things really change?
if ( digitalRead(pinA) != A_set ) { // debounce once more
A_set = !A_set;
// adjust counter + if A leads B
if ( A_set && !B_set )
encoderPos += 1;
rotating = false; // no more debouncing until loop() hits again
changed();
}
} else if ( ulNotificationValue == 2 ) {
if ( rotating ) delay (1);
if ( digitalRead(pinB) != B_set ) {
B_set = !B_set;
// adjust counter - 1 if B leads A
if ( B_set && !A_set )
encoderPos -= 1;
rotating = false;
changed();
}
} else if ( ulNotificationValue == 4 ) {
delay(1);
if ( digitalRead(pinButton) != Button_set ) {
Button_set = !Button_set;
if (! Button_set ) {
encoderPos = 0;
}
}
}
}
}
/*
// main loop, work is done by interrupt service routines, this one only prints stuff
void loop() {
rotating = true; // reset the debouncer
if (lastReportedPos != encoderPos) {
Serial.print("Index:");
Serial.println(encoderPos, DEC);
lastReportedPos = encoderPos;
}
if (digitalRead(clearButton) == LOW ) {
encoderPos = 0;
}
}
*/
void Rotary::changed() {
if (lastReportedPos != encoderPos) {
Serial.print("encoder: ");
Serial.println(encoderPos);
// if (callback) callback(encoderPos);
lastReportedPos = encoderPos;
}
rotating = true; // reset the debouncer
}
bool Rotary::registerCallback(std::function<void(int)> callback) {
this->callback = callback;
return true;
}
void Rotary::doButton() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
configASSERT( xTaskToNotify != NULL );
uint32_t intrBits = 4;
xTaskNotifyFromISR( xTaskToNotify, intrBits, eSetValueWithOverwrite, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR(); //portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
// Interrupt on A changing state
void Rotary::doEncoderA() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
configASSERT( xTaskToNotify != NULL );
uint32_t intrBits = 1;
xTaskNotifyFromISR( xTaskToNotify, intrBits, eSetValueWithOverwrite, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR(); //portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
// Interrupt on B changing state, same as A above
void Rotary::doEncoderB() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
configASSERT( xTaskToNotify != NULL );
uint32_t intrBits = 2;
xTaskNotifyFromISR( xTaskToNotify, intrBits, eSetValueWithOverwrite, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR(); //portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}