diff --git a/src/main.cpp b/src/main.cpp index 06d5ac9..a64b396 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,14 +8,14 @@ * GND O O GND * 5V O O 5V * 3V3 O O 3V3 - * GND O < 36 ROTARY_BTN + * GND O < 36 * RX * * 17 * TX * < 38 ROTARY_A * RST * BUTTON < 39 ROTARY_B - * 0 * < 34 + * 0 * BUTTON < 34 * 22 * < 35 - * BME280_SDO 19 * LoRa_MISO * 32 - * BME280_CS 23 * * 33 + * BME280_SDO 19 * LoRa_MISO ? * 32 + * BME280_CS 23 * ? * 33 * 18 x LoRa_CS * 25 MAX98_DIN * BME280_SCL/SCK 5 * LoRa_SCK LoRa_IRQ * 26 * 15 * OLED_SCL LoRa_MOSI * 27 BME280_SDA/SDI @@ -25,6 +25,14 @@ * 16 * OLED_RST * 21 */ +/* Rotary Encoder + * 1 LED + * pinA A 2 LED + * GND C 3 BTN -| + * pinB B 4 LED / + * 5 Vin -| + */ + //Include Basecamp in this sketch #include #include @@ -64,7 +72,7 @@ uint32_t lastButtonPress = 0; //Variables for the sensor and the battery static const int buttonPin = 0; static const int ResetPin = 17; -static const int SensorPin = 32; +static const int SensorPin = 0; static const int BatteryPin = 34; static const int rotaryPinA = 38; static const int rotaryPinB = 39; @@ -175,7 +183,7 @@ void setup() { u8g2.setContrast(127); - rotary.registerCallback(nullptr); + rotary.registerCallback(rotation); rotary.begin(rotaryPinA, rotaryPinB, rotaryPinButton); } @@ -260,6 +268,11 @@ void suspendESP(uint16_t packetId) { } +void rotation(int i) { + Serial.println(i); + mp3.setVolume(i); +} + void loop() { diff --git a/src/main.h b/src/main.h index 67cbe65..e6302d2 100644 --- a/src/main.h +++ b/src/main.h @@ -7,3 +7,4 @@ void transmitStatus(); void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total); void suspendESP(uint16_t packetId); void loop(); +void rotation(int i); diff --git a/src/mp3.cpp b/src/mp3.cpp index 83e9fa4..4354fda 100644 --- a/src/mp3.cpp +++ b/src/mp3.cpp @@ -56,6 +56,12 @@ void MP3::start() { } } +void MP3::setVolume(int volume) { + if (playing && out) + if (volume > 0 && volume <= 100) + out->SetGain(((float)volume)/100.0); +} + void MP3::mp3_decoder_task(void *pvParameters) { strcpy(titleStr, "..."); file = new AudioFileSourceICYStream(URL); diff --git a/src/mp3.h b/src/mp3.h index 14c5958..a1abb42 100644 --- a/src/mp3.h +++ b/src/mp3.h @@ -20,6 +20,7 @@ class MP3 { //const char *URL="http://swr-swr1-bw.cast.addradio.de/swr/swr1/bw/mp3/64/stream.mp3"; void stop(void); void start(void); + void setVolume(int); bool playing = false; private: AudioGenerator *decoder; diff --git a/src/rotary.cpp b/src/rotary.cpp index d6d3970..b4291c5 100644 --- a/src/rotary.cpp +++ b/src/rotary.cpp @@ -16,8 +16,11 @@ //using namespace std; TaskHandle_t Rotary::xTaskToNotify = NULL; +Rotary* Rotary::instance = NULL; -Rotary::Rotary() {} +Rotary::Rotary() { + instance = this; +} bool Rotary::begin(uint8_t pinA, uint8_t pinB, uint8_t pinButton) { this->pinA = pinA; @@ -44,82 +47,46 @@ void Rotary::cTaskWrapper(void* parameters) { void Rotary::button_task(void *pvParameters) { xTaskToNotify = xTaskGetCurrentTaskHandle(); - attachInterrupt(digitalPinToInterrupt(pinA), doEncoderA, CHANGE); - attachInterrupt(digitalPinToInterrupt(pinB), doEncoderB, CHANGE); -// attachInterrupt(digitalPinToInterrupt(pinButton), doButton, CHANGE); + attachInterrupt(digitalPinToInterrupt(pinA), doEncoderA, RISING); + attachInterrupt(digitalPinToInterrupt(pinB), doEncoderB, RISING); +// attachInterrupt(digitalPinToInterrupt(pinButton), doButton, FALLING); uint32_t ulNotificationValue; + uint32_t ulStatusValue; while(true) { + rotating = true; // reset the debouncer - 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 + ulNotificationValue = xTaskNotifyWait(0x00, ULONG_MAX, &ulStatusValue, portMAX_DELAY ); - // Test transition, did things really change? - if ( digitalRead(pinA) != A_set ) { // debounce once more - A_set = !A_set; +// if ( rotating ) delay (1); // wait a little until the bouncing is done + if( ulStatusValue == 1 ) { // adjust counter + if A leads B - if ( A_set && !B_set ) encoderPos += 1; - + changed(); 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 ) + } else if ( ulStatusValue == 2 ) { + // adjust counter -1 if B leads A encoderPos -= 1; - - rotating = false; - changed(); - } - } else if ( ulNotificationValue == 4 ) { - delay(1); - if ( digitalRead(pinButton) != Button_set ) { - Button_set = !Button_set; + changed(); + rotating = false; // no more debouncing until loop() hits again + } else if ( ulStatusValue == 4 ) { + Button_set = digitalRead(pinButton); 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); + if (callback) callback(encoderPos); lastReportedPos = encoderPos; } - rotating = true; // reset the debouncer } bool Rotary::registerCallback(std::function callback) { @@ -132,27 +99,43 @@ void Rotary::doButton() { configASSERT( xTaskToNotify != NULL ); uint32_t intrBits = 4; - xTaskNotifyFromISR( xTaskToNotify, intrBits, eSetValueWithOverwrite, &xHigherPriorityTaskWoken ); + xTaskNotifyFromISR( xTaskToNotify, intrBits, eSetValueWithoutOverwrite, &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 ); + 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; - - configASSERT( xTaskToNotify != NULL ); - uint32_t intrBits = 2; - xTaskNotifyFromISR( xTaskToNotify, intrBits, eSetValueWithOverwrite, &xHigherPriorityTaskWoken ); - portYIELD_FROM_ISR(); //portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + 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 ); + } } diff --git a/src/rotary.h b/src/rotary.h index 242d97e..081fb46 100644 --- a/src/rotary.h +++ b/src/rotary.h @@ -19,15 +19,21 @@ class Rotary { static void IRAM_ATTR doEncoderA(void); static void IRAM_ATTR doEncoderB(void); static void IRAM_ATTR doButton(void); + static Rotary* instance; static TaskHandle_t xTaskToNotify; + uint32_t debounceA; + uint32_t debounceB; + uint32_t debounceDelay = 50; private: - volatile unsigned int encoderPos = 0; // a counter for the dial + volatile int encoderPos = 0; // a counter for the dial unsigned int lastReportedPos = 1; // change management boolean rotating = false; // debounce management // interrupt service routine vars boolean A_set = false; boolean B_set = false; boolean Button_set = false; + boolean skipA = false; + boolean skipB = false; uint8_t pinA; uint8_t pinB; uint8_t pinButton;