Electronics > Microcontrollers

ESP32 combining two scripts

(1/4) > >>

PSR B1257:
Hello all  :)
I am trying to combine two functions for an ESP32 into one program, which turned out to be not as easy, as one would think.

Function 1 is a PWM-generator with a slider interface.
Function 2 are multiple buttons for a binary output.

Independently these programs work, but combined the ESP32 does not even establish a WiFi connection.
This is the code in question (using the Arduino IDE):

--- Code: ---#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>

//WiFi stuff censored ;-)

const int pwm_pin = 15;
String slider_value = "25";

const int frequency = 1000;
const int pwm_channel = 0;
const int resolution = 8;

const char* input_parameter = "value";
const char* PARAM_INPUT_1 = "output";
const char* PARAM_INPUT_2 = "state";

AsyncWebServer server(80);

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>ESP32 Control</title>
  <style>
    html {font-family: Times New Roman; display: inline-block; text-align: center;}
    h2 {font-size: 2.3rem;}
    p {font-size: 1.9rem;}
    body {max-width: 400px; margin:0px auto; padding-bottom: 25px;}
    .slider { -webkit-appearance: none; margin: 14px; width: 360px; height: 25px; background: #38c0ff  ;
    outline: none; -webkit-transition: .2s; transition: opacity .2s;}
    .slider::-webkit-slider-thumb {-webkit-appearance: none; appearance: none; width: 35px; height: 35px; background:#01070a; cursor: pointer;}
    .slider::-moz-range-thumb { width: 35px; height: 35px; background: #01070a; cursor: pointer; }

   
  </style>
</head>
<body>
  <h2>ESP32 Control</h2>
  <p><span id="textslider_value">%SLIDERVALUE%</span></p>
  <p><input type="range" onchange="updateSliderPWM(this)" id="pwmSlider" min="0" max="255" value="%SLIDERVALUE%" step="1" class="slider"></p>
  %BUTTONPLACEHOLDER%
<script>
function updateSliderPWM(element) {
  var slider_value = document.getElementById("pwmSlider").value;
  document.getElementById("textslider_value").innerHTML = slider_value;
  console.log(slider_value);
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "/slider?value=" slider_value, true);
  xhr.send();
}
function toggleCheckbox(element) {
  var xhr = new XMLHttpRequest();
  if(element.checked){ xhr.open("GET", "/update?output=" element.id "&state=1", true); }
  else { xhr.open("GET", "/update?output=" element.id "&state=0", true); }
  xhr.send();
}
</script>
</body>
</html>
)rawliteral";

String processor(const String& var){
  if (var == "SLIDERVALUE"){
    return slider_value;
  }

  //Serial.println(var);
  if(var == "BUTTONPLACEHOLDER"){
    String buttons = "";
    buttons  = "<h4>Output - GPIO 6</h4><label class="switch"><input type="checkbox" onchange="toggleCheckbox(this)" id="6" "   outputState(6)   "><span class="slider"></span></label>";
    buttons  = "<h4>Output - GPIO 7</h4><label class="switch"><input type="checkbox" onchange="toggleCheckbox(this)" id="7" "   outputState(7)   "><span class="slider"></span></label>";
    buttons  = "<h4>Output - GPIO 8</h4><label class="switch"><input type="checkbox" onchange="toggleCheckbox(this)" id="8" "   outputState(8)   "><span class="slider"></span></label>";
    return buttons;
  }
  return String();
}
String outputState(int output){
  if(digitalRead(output)){
    return "checked";
  }
  else {
    return "";
  }
}

void setup(){
  Serial.begin(115200);

  ledcSetup(pwm_channel, frequency, resolution);
  ledcAttachPin(pwm_pin, pwm_channel);
  ledcWrite(pwm_channel, slider_value.toInt());

  pinMode(6, OUTPUT);
  digitalWrite(6, LOW);
  pinMode(7, OUTPUT);
  digitalWrite(7, LOW);
  pinMode(8, OUTPUT);
  digitalWrite(8, LOW);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting...");
  }

  Serial.println(WiFi.localIP());

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  server.on("/slider", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String message;
    if (request->hasParam(input_parameter)) {
      message = request->getParam(input_parameter)->value();
      slider_value = message;
      ledcWrite(pwm_channel, slider_value.toInt());
    }
    else {
      message = "No message sent";
    }
    Serial.println(message);
    request->send(200, "text/plain", "OK");
  });
 
  server.begin();
}
 
void loop() {
 
}
--- End code ---

Any ideas are welcome. I have now idea how to troubleshoot those kind of things.

CountChocula:
Hiya! The only obvious problem that jumps out at me is that you're trying to write to GPIOs 6, 7, and 8 — on some ESP32 chips (like the WROOM, for example), these pins are connected to the onboard Flash interface, and if you try writing to them you will cause the CPU to crash. If I take this code out:


--- Code: ---  pinMode(6, OUTPUT);
  digitalWrite(6, LOW);
  pinMode(7, OUTPUT);
  digitalWrite(7, LOW);
  pinMode(8, OUTPUT);
  digitalWrite(8, LOW);
--- End code ---

The script compiles and connects to WiFi without problem. I can open up the web page and it seems to work fine, and the PWM is running as expected (on other pins).

I also had to change the processor() function so that it compiles the output string properly:


--- Code: ---String processor(const String& var){
  if (var == "SLIDERVALUE"){
    return slider_value;
  }

  //Serial.println(var);
  if(var == "BUTTONPLACEHOLDER"){
    String buttons = "";
    buttons  = "<h4>Output - GPIO 6</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"6\" ";   
    buttons += outputState(6);
    buttons += "><span class=\"slider\"></span></label>";
    buttons += "<h4>Output - GPIO 7</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"7\" ";   
    buttons += outputState(7);
    buttons += "><span class=\"slider\"></span></label>";
    buttons += "<h4>Output - GPIO 8</h4><label class=\"switch\"><input type=\"checkbox\" onchange=\"toggleCheckbox(this)\" id=\"8\" ";   
    buttons += outputState(8);
    buttons += "><span class=\"slider\"></span></label>";

    return buttons;
  }
  return String();
}

--- End code ---

Without these changes, the script doesn't compile, but that might just be because I don't use the Arduino IDE.


—CC

PSR B1257:
Jeeeeesus...I would have never thought of that  :-+
Thanks a lot.
I saw, that these pins (it's a ESP32 DevKitC V4 by the way) also share the Flash-functionality (but so do all pins share different functionalities).

tooki:
The “available but not really” pins on many ESP32 models is one of the bigger “traps for young players” with the ESP32. The pins for flash memory are one, the pins for external PSRAM on WROVER models is another, and another are the bootstrapping pins, which control the boot process and are usable after startup, but are tricky to use if your circuit pulls them high or low. That’s GPIOs 0, 2, 4, 5, 12, and 15, though usually only 0 and 2 are critical. Another common trap is that ADC2 is somehow involved in wifi, so if you enable wifi, you cannot use the second ADC.

This is a good overview of the pin restrictions: https://randomnerdtutorials.com/esp32-pinout-reference-gpios/

Some, but not all, of these limitations are addressed in the newer ESP32 models like the S3 (which I need to try out more).

I HIGHLY suggest creating an IO assignment spreadsheet for any ESP32 project that needs more pins than the few that are totally unencumbered. Paste an image of the ESP32 in the middle and scale it to match the cell sizes. (Basically, make a diagram similar to the one at the top of the link above, then add a column or two for your own signal names.)

Believe it or not, though, the ESP32’s pin assignment capability is otherwise quite flexible, more so than many MCUs. (On many, especially older ones, many things like SPI, I2C, and UART cannot be moved at all.)

P.S. Pro tip: add a 1-10uF capacitor from the EN pin to ground. This will ensure it enters firmware programming mode reliably. I don’t know why sometimes it’s needed and sometimes it’s not (sometimes it even appears to depend on what code is running on the ESP32 already!), so when designing anything with an ESP32, I just add it as a matter of course since it costs peanuts. (The cap’s function is to ensure the ESP32 is held in reset long enough for GPIO0 to be pulled low before it tries to boot. The cap takes time to charge, extending the time the EN pin is held at a voltage considered “low”.)

PSR B1257:

--- Quote ---This is a good overview of the pin restrictions:
--- End quote ---
Indeed, it is. Thank you too.
I've changed the output pins to 0,2,4 and everything works fine. 'Funny business' at boot up (as it occurs at GPIO 0) is not an issue for the particular application.

Now I only have to figure out a proper HTML-layout. Luckily, there are HTML-previewer available  :)

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod