简体   繁体   English

如何使编码器与两个库一起工作?

[英]How to make encoder work with two libraries?

First I'd like to say I'm very new to c++, that's why I'm using the Arduino core and libraries on ESP32, and I would like to apologize for the dumpster fire you're about to see below.首先,我想说我对 C++ 非常陌生,这就是我在 ESP32 上使用 Arduino 核心和库的原因,我想为您即将在下面看到的垃圾箱火灾道歉。

Simply making a custom keyboard with buttons and encoders.只需制作带有按钮和编码器的自定义键盘。 When booted, select one of two modes: blekeyboard or ble midi control surface.启动时,选择两种模式之一:blekeyboard 或 ble midi 控制界面。

The button works in both modes but the encoder only works in whichever mode is declared last.该按钮可在两种模式下工作,但编码器仅在最后声明的模式下工作。 (so in this script order, both the encoder and button in mode 1 blekeyboard works, while only the button works in mode 2.) (因此在此脚本顺序中,模式 1 blekeyboard 中的编码器和按钮均有效,而模式 2 中只有按钮有效。)

What did I do wrong and what can I do?我做错了什么,我能做什么? Any suggestions regarding the problem or the overall script is welcome.欢迎任何有关问题或整体脚本的建议。

Thank you in advance.先感谢您。

#include <Arduino.h>

#include <BleKeyboard.h>
BleKeyboard bleKeyboard;

#define ESP32
#include <encoder.h>
#include <Control_Surface.h>
#include <MIDI_Interfaces/BluetoothMIDI_Interface.hpp>
BluetoothMIDI_Interface midi;

const int usermodebutton1 = 2;
const int usermodebutton2 = 0;
int usermode = 0;

// ---------------------- mode 2 MIDI Input Elements ------------------------ //

using namespace MIDI_Notes;
NoteButton csButton1 = {
    2,
    note(C, 4),
};
CCRotaryEncoder csEnc1 = {
    {26, 25},     // pins
    MCU::V_POT_1, // MIDI address (CC number + optional channel)
    1,            // optional multiplier if the control isn't fast enough
};

// -------------------------- mode 1 blekeyboard --------------------------- //

int kbutton1 = 2;
int kbutton1State;
int keyInterval = 400000;
Encoder kencoder1(25, 26);
int encInterval = 5000;
TickType_t currentTime;
TickType_t previousTime;
long enc1_oldPos = -999;

// ============================================================================= //

void setup()
{
    pinMode(usermodebutton1, INPUT_PULLUP);
    pinMode(usermodebutton2, INPUT_PULLUP);

    Serial.begin(115200);
    Serial.println("");
    Serial.println("select mode:");

    // ----------------------------------------------------------------------------- //

    while (true)
    {
        if (digitalRead(usermodebutton1) == LOW)
        {
            usermode = 1;
            Serial.println("mode 1 selected");
            break;
        }
        if (digitalRead(usermodebutton2) == LOW)
        {
            usermode = 2;
            Serial.println("mode 2 selected");
            break;
        }
        delay(1000);
    }

    // ----------------------------------------------------------------------------- //

    if (usermode == 1)
    {
        Serial.println("setup mode 1");
        Serial.println("Starting BLE work...");
        bleKeyboard.begin();
        pinMode(kbutton1, INPUT_PULLUP);
        previousTime = 0;
    }
    if (usermode == 2)
    {
        Serial.println("setup mode 2");
        Serial.println("Control Surface BLE starting...");
        RelativeCCSender::setMode(relativeCCmode::TWOS_COMPLEMENT);
        Control_Surface.begin(); // Initialize Control Surface
    }
}

// ============================================================================= //

void loop()
{
    while (usermode == 1)
    {
        while (bleKeyboard.isConnected())
        {
            // mode 1 encoders
            long enc1_newPos = kencoder1.read();
            currentTime = esp_timer_get_time();

            if (enc1_newPos < enc1_oldPos && currentTime - previousTime > encInterval)
            {
                enc1_oldPos = enc1_newPos;
                previousTime = currentTime;
                // bleKeyboard.write(KEY_MEDIA_VOLUME_DOWN);
                Serial.print("enc1: ");
                Serial.println(enc1_newPos);
            }
            if (enc1_newPos > enc1_oldPos && currentTime - previousTime > encInterval)
            {
                enc1_oldPos = enc1_newPos;
                previousTime = currentTime;
                // bleKeyboard.write(KEY_MEDIA_VOLUME_UP);
                Serial.print("enc1: ");
                Serial.println(enc1_newPos);
            }

            // mode 1 keys
            kbutton1State = digitalRead(kbutton1);
            if (kbutton1State == LOW && currentTime - previousTime > keyInterval)
            {
                previousTime = currentTime;
                Serial.println("button 1 pressed");
                bleKeyboard.print("1");
            }
        }
    }
    while (usermode == 2)
    {
        Control_Surface.loop(); // Refresh all elements
    }
}

First of all, your code needs general tidying up.首先,您的代码需要进行一般整理。 Do not instantiate an object after the #include or #define section.不要在#include 或#define 部分之后实例化对象。

Avoid doing this:避免这样做:

#include <BleKeyboard.h>
BleKeyboard bleKeyboard;

#include <MIDI_Interfaces/BluetoothMIDI_Interface.hpp>
BluetoothMIDI_Interface midi;

I generally organise my code as:我通常将我的代码组织为:

// Include libraries
#include <lib1.h>
#include <lib2.h>
...

// Macros
#define SOMETHING_FUNNY value  // see the Macro name in capitals?
#define SOMETHING_USEFUL anothervalue
...

/*
* Variables Section.
* Also, I usually categorize my variables section by type: floats, integers, chars, etc. If I ever use booleans I pack them in a section called 'flags'. Also, if a boolean is used inside an interrupt it should be volatile
*/

Type var_name1 = initial_value;    // the initaliztion is optional
AnotherType var_name2;
...

// Object instantiation
ClassName object1;
AnotherClassName object2 = new AnotherClassName(constructor_parameters);
...

//Setup Function

void setup(){
// Serial Port initialization goes first
Serial.begin(baudrate);

// Initialization routines --> use functions! 

}

void loop(){
// Check for states of your FSM and call the respective function 
}

// Functions definitions

output type myFunction1(args){
// Routine
}

...

Second, your code shouts to me 'Finite-States Machines', which is basically what you are implementing but not in a conventional way.其次,您的代码对我大喊“有限状态机”,这基本上是您正在实现的,但不是以传统方式实现的。 Please read Nick Gammon's amazing tutorial on FSMs.请阅读 Nick Gammon 关于 FSM 的精彩教程 This way, you will enumerate your states and trigger actions or events depending on the user's selection or hardware inputs without blocking the flow of the code.这样,您将根据用户的选择或硬件输入枚举您的状态并触发操作或事件,而不会阻塞代码流。

Now, I assume that you have read both the .cpp files from your two libraries and checked if there are no conflicts between them?现在,我假设您已经从两个库中读取了 .cpp 文件并检查了它们之间是否没有冲突? Also, which encoder.h library are you using?另外,您使用的是哪个encoder.h库? It looks like Paul Stoffregen's library , is it?看起来像 Paul Stoffregen 的图书馆,是吗? I ask because his library is heavily based on interrupts and it was coded with some ASM blocks that might be not optimized for the ESP32, but please don't quote me on that.我问是因为他的库在很大程度上基于中断,并且它是用一些 ASM 块编码的,这些块可能没有针对 ESP32 进行优化,但请不要引用我的话。 As enhzflep said:正如 enhzflep 所说:

I'd suspect there to be a problem with clashing interrupts.我怀疑冲突中断有问题。

and I could not agree more on that.我对此完全同意。 If you are using that library, there is a Macro that could save your life:如果您正在使用该库,则有一个宏可以挽救您的生命:

#define ENCODER_DO_NOT_USE_INTERRUPTS

used in this example from the library's repo这个例子中使用来自图书馆的 repo

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM