0

我对编码完全陌生,这甚至是我在这里的第一篇文章。我尝试这样做是因为没有人出售我想要/需要的东西;-)。

我已经取得了相当大的成就,但此刻我迷失了很多东西(我在过去的 8 天里阅读了很多关于编码的内容,特别是关于 Arduino 的内容)......但让我先解释一下我的这个项目的意图是:

我想构建一个“Stomp Box”来静音Behringer X32 Rack (wireless) Channels/Mutegroups/Buses,只是静音开/关..没有别的。

这个盒子应该有 4-6 个“stompers”(按钮),每个按钮都应该有不同的静音功能。

此外,如果未静音,则通道/静音组/总线的当前状态应由 LED 指示为绿色,如果静音则为红色。
因此盒子需要评估指定通道/静音组/总线的当前状态,因为它也可能从其他远程设备更改。
然后在按下/踩踏指定按钮时切换到相反状态。

我想要有可以轻松更改按钮操作的代码,例如:

button1 = /ch/01/mix/on ,i 1

button2 = /config/mute/1 ,i 1

按钮 3 = /dca/1/on ,i 1

所以如果我需要一个不同的通道/静音组/总线来进行另一个事件,只需编辑和重新编码我的ESP32 节点套件

所以这是我已经拥有的代码:

#include "WiFi.h"
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <SPI.h>    
#include <OSCMessage.h> //https://github.com/CNMAT/OSC

#define WIFI_NETWORK "xxxxxxxxxx"    //SSID of you Wifi
#define WIFI_PASSWORD "xxxxxxxxxxx"  //Your Wifi Password
#define WIFI_TIMEOUT_MS 20000        // 20 second WiFi connection timeout
#define WIFI_RECOVER_TIME_MS 30000   // Wait 30 seconds after a failed connection attempt

int muteOn = 0;// 0=Mute
int muteOff = 1;// 1=Unmute
int input;
WiFiUDP Udp;

const IPAddress outIp (192, 168, 10, 129);  //Mixers IP
const unsigned int outPort = 10023;         //X32 Port

//variables for blinking an LED with Millis
const int led = 2; // ESP32 Pin to which onboard LED is connected
unsigned long previousMillis = 0;  // will store last time LED was updated
const long interval = 300;  // interval at which to blink (milliseconds)
int ledState = LOW;  // ledState used to set the LED

void connectToWiFi(){
  Serial.print("Zu WLAN verbinden...");
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_NETWORK, WIFI_PASSWORD);

  unsigned long startAttemptTime = millis();
  
  while(WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < WIFI_TIMEOUT_MS){
   Serial.println(".");
   delay(100);
   }
  if(WiFi.status() != WL_CONNECTED){
    Serial.println("Nicht Verbunden!");
    //optional take action
  }else{
    Serial.print("WLAN Verbunden mit ");
    Serial.println(WIFI_NETWORK);
    Serial.println(WiFi.localIP( ));
  }
}

void setup() {
    Serial.begin(115200);
    connectToWiFi();
    Udp.begin(8888);
    pinMode(led, OUTPUT);
    
  // Port defaults to 3232
  // ArduinoOTA.setPort(3232);

  // Hostname defaults to esp3232-[MAC]
  // ArduinoOTA.setHostname("myesp32");

  // No authentication by default
  // ArduinoOTA.setPassword("admin");

  // Password can be set with it's md5 value as well
  // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3
  // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");

  ArduinoOTA
    .onStart([]() {
      String type;
      if (ArduinoOTA.getCommand() == U_FLASH)
        type = "sketch";
      else // U_SPIFFS
        type = "filesystem";

      // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
      Serial.println("Start updating " + type);
    })
    .onEnd([]() {
      Serial.println("\nEnd");
    })
    .onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
    })
    .onError([](ota_error_t error) {
      Serial.printf("Error[%u]: ", error);
      if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
      else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
      else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
      else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
      else if (error == OTA_END_ERROR) Serial.println("End Failed");
    });

  ArduinoOTA.begin();

  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}


void loop(){
  ArduinoOTA.handle();
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
  // save the last time you blinked the LED
  previousMillis = currentMillis;
  // if the LED is off turn it on and vice-versa:
  ledState = not(ledState);
  // set the LED with the ledState of the variable:
  digitalWrite(led,  ledState);
  }
  
  input=Serial.read();  
        if (input=='0'){
        // welcher status hat der kanal?
        // wenn Kanal gemutet dann unmute und umgekehrt
            Serial.println("Mute!");
            delay(100);
            sendMute();  //send Mute to Mixer
            Serial.println("...");
        }
        if (input=='1'){
            Serial.println("UnMute!");
            delay(100);
            sendUnMute();
            Serial.println("...");
        }
}       

void sendMute() {
    //the message wants an OSC address as first argument
    OSCMessage msg("/ch/01/mix/on");
    msg.add(muteOn);
              
    Udp.beginPacket(outIp, outPort);
    msg.send(Udp); // send the bytes to the SLIP stream
    Udp.endPacket(); // mark the end of the OSC Packet
    msg.empty(); // free space occupied by message

    delay(20);
}

void sendUnMute() {
    //the message wants an OSC address as first argument
    OSCMessage msg("/ch/01/mix/on");
    msg.add(muteOff);
              
    Udp.beginPacket(outIp, outPort);
    msg.send(Udp); // send the bytes to the SLIP stream
    Udp.endPacket(); // mark the end of the OSC Packet
    msg.empty(); // free space occupied by message

    delay(20);
}  

因此,我通过串行监视器对此进行了测试,当我输入“0”并单击发送时,混音器将通道 1 静音,并且在输入“1”时,通道 1 变为未静音,到目前为止一切都很好(OSCMessage msg("/ch/01/mix/on");......部分。

特别困扰我的是,我不得不硬编码命令“/ch/01/mix/on”,因为我无法声明变量?对于这个字符串?我已经很困惑了,我什至不知道我是否有正确的条款:-(

顺便说一句:有很多解决方案如何使用 MIDI 来实现,但 MIDI 不是无线的,我认为我的项目有点矫枉过正。我还在github.com/CNMAT/OSC上做了一些研究,但我不明白......(哭泣)......我在这里
也找到了一个帖子,但这也没有帮助...... :-(

关于如何实现目标的任何建议?-

任何帮助都非常受欢迎......即使是德语(我的母语......)

PS:是的,我是初学者,我承认。但至少在过去的 8 天里,我设法通过 OTA 连接和刷写这个东西,所以请放轻松。

4

2 回答 2

0

您可以使用 sprintf 创建命令字符串。例如:

#define CHANNELON "on"
#define CHANNELOFF "off"
  
int channel;
int mute;
char messageString[100]; 
      
// some code that calculates the channel number and the mute state:
channel = 1;
mute = 1;
      
// then check the mute state and create the command string:
if (mute)
{
  // to turn off a channel:
  sprintf(messageString,"/ch/%02d/mix/%s",channel,CHANNELOFF);
}
else
{
  // to turn on a channel:
  sprintf(messageString,"/ch/%02d/mix/%s",channel,CHANNELON);
}

// send the command:
OSCMessage msg(messageString);

%02d 将用前面的零替换一个整数,如果它小于 10 并且总是 2 个字符长。所以如果通道是 1,结果将是 01

于 2021-03-02T07:17:41.057 回答
0

不想硬编码你的命令是一种很好的直觉。

Arduino 语言是 C++,它(大部分)是 C 的超集。C 和 C++ 使用预处理器,它允许您定义常量并测试它们的存在。

例如,你可以写:

#define CHAN01_MIX_ON_COMMAND "/ch/01/mix/on"

然后CHAN01_MIX_ON_COMMAND在您想使用该常量的任何地方使用,如下所示:

void sendMute() {
    //the message wants an OSC address as first argument
    OSCMessage msg(CHAN01_MIX_ON_COMMAND);

然后,如果您需要更改字符串"/ch/01/mix/on",您可以在一个位置更改它,而不必担心在代码中找到它的每个实例。

在语句中编写名称#define是人们通常遵循的惯例,以便更清楚地表明它们是常量。

您必须#define在使用您定义的常量之前编写该行,因此将它放在文件的开头(在任何#include行之后和您的第一个函数之前)是一个好习惯。或者,如果您有几个,您可以将它们全部放在自己的文件中,称为commands.h.h手段header文件),然后将其包含在任何需要它的文件的开头,如下所示:

#include "commands.h"

#include语句会将文件的内容插入commands.h到该语句所在的文件中。

当您有多个#define语句时,将它们全部放在一个位置(无论是在文件顶部还是在它们自己的文件中)也是一种很好的做法,这样您就可以在一个中心位置找到它们并在需要时更新它们.

有些人会将字符串常量分配给一个变量,如下所示:

char *channel01_mix_on_cmd = "/ch/01/mix/on";

这里char的意思是“一个字符”——比如一个字母、数字或符号。表示指向的*指针,它允许您使用字符数组。C 和 C++ 中的简单字符串只是字符数组(或指向第一个字符的指针),末尾有一个特殊的隐藏字符设置为数值 0(不是字符'0')。C++ 也有一个名为的字符串数据类型std::string,而 Arduino 程序也有String,但它们在这里都过大了。它们都可以让您使用字符串;String比使用起来容易得多,char *但两者都有优点和缺点。

与 一样#define,您也可以将其放在文件开头附近的函数之外。它定义了一个全局变量,任何引用它的函数都可以使用该变量。

您还可以在他们想要字符串的任何地方使用该变量。这与 using 的想法相同#define,只是略有不同。例如:

void sendMute() {
    //the message wants an OSC address as first argument
    OSCMessage msg(channel01_mix_on_cmd);

在这里使用变量是试图通过不具有多个字符串副本来节省存储空间。这不是必需的; C/C++ 编译器很长一段时间都检测到了这一点,并且只存储了一个字符串的副本。如果您的代码被拆分为多个文件,它可能会节省空间。

在 ESP32 和 ESP8266 等 CPU 上节省空间很重要,因为它们的内存太少了。#define在这里很好,因为编译器会自动为您完成。

于 2021-03-02T01:10:25.447 回答