ESP32 - Multi Tasking with while in a task - arduino

I try to build a chrono laser with two ESP32 and two LDR.
I have two ESP32:
One do a ACCESS Point with a LDR
Second connect to the AP, have the algorithm of the laser chrono and a second LDR
In the second one, i try also to have a WebServer so i can connect with my phone and restart the chrono.
I try to do multitasking but everytime my ESP32 restart :
18:10:42.625 -> E (5775) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
18:10:42.672 -> E (5775) task_wdt: - IDLE0 (CPU 0)
18:10:42.672 -> E (5775) task_wdt: Tasks currently running:
18:10:42.672 -> E (5775) task_wdt: CPU 0: Task1
18:10:42.672 -> E (5775) task_wdt: CPU 1: Task2
18:10:42.672 -> E (5775) task_wdt: Aborting.
18:10:42.672 -> abort() was called at PC 0x400d9033 on core 0
You can find my code here:
https://create.arduino.cc/editor/marcoberle/c4762636-36c6-4551-92f2-935021a001c9/preview
My code :
// Load Wi-Fi library
#include <WiFi.h>
#include <HTTPClient.h>
//Declaration of PIN
const int departReceiver = 4; // the number of the pin
const int LED_BUILTIN = 2;
// Replace with your network credentials
const char* ssid = "ESP32-ARRIVE";
const char* password = "123456789";
// Set web server port number to 80
WiFiServer server(80);
WiFiClient client = server.available();
//Your IP address or domain name with URL path
const char* serverNameArrive = "http://192.168.4.1/arrive";
// Variable to store the HTTP request
String header;
// Auxiliar variables to store the current output state
String output26State = "off";
String output27State = "off";
// Assign output variables to GPIO pins
const int output26 = 26;
const int output27 = 27;
// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0;
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;
TaskHandle_t Task1;
TaskHandle_t Task2;
void setup() {
Serial.begin(115200);
pinMode(departReceiver, INPUT);
// Initialize the output variables as outputs
pinMode(output26, OUTPUT);
pinMode(output27, OUTPUT);
// Set outputs to LOW
digitalWrite(output26, LOW);
digitalWrite(output27, LOW);
// Connect to Wi-Fi network with SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Print local IP address and start web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
client = server.available();
//create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
xTaskCreatePinnedToCore(
Task1code, /* Task function. */
"Task1", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
6, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
delay(500);
//create a task that will be executed in the Task2code() function, with priority 1 and executed on core 1
xTaskCreatePinnedToCore(
Task2code, /* Task function. */
"Task2", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
7, /* priority of the task */
&Task2, /* Task handle to keep track of created task */
1); /* pin task to core 1 */
delay(500);
}
//CHRONO VAR
unsigned int departStatus = 0;
unsigned int arriveStatus = 0;
unsigned int start_time = 0;
unsigned int stop_time = 0;
unsigned int total_time = 0;
const unsigned int OFF = 0;
const unsigned int ON = 1;
String httpGETRequest(const char* serverName) {
HTTPClient http;
// Your IP address with path or Domain name with URL path
http.begin(serverName);
// Send HTTP POST request
int httpResponseCode = http.GET();
String payload = "--";
if (httpResponseCode > 0) {
payload = http.getString();
}
else {
}
// Free resources
http.end();
return payload;
}
String ChronoLog = "";
int reset = 0;
void Chrono () {
if (reset == 0) {
reset = 1;
ChronoLog = "<p>ALGO START</p>";
Serial.println("ALGO START");
while (departStatus == OFF) {
departStatus = digitalRead(departReceiver);
}
ChronoLog += "<p>Borne de début prête</p>";
Serial.println("Borne de début prête");
while (arriveStatus == OFF) {
arriveStatus = httpGETRequest(serverNameArrive).toInt();
}
ChronoLog += "<p>Borne de fin prête</p>";
ChronoLog += "<p>En attente du courreur</p>";
Serial.println("Borne de fin prête");
Serial.println("En attente du courreur");
while (departStatus == ON) {
departStatus = digitalRead(departReceiver);
}
ChronoLog += "<p>Courreur en place</p>";
Serial.println("Courreur en place");
digitalWrite(LED_BUILTIN, HIGH);
while (departStatus == OFF) {
departStatus = digitalRead(departReceiver);
}
ChronoLog += "<p>Chrono lancé</p>";
Serial.println("Chrono lancé");
start_time = millis();
while (arriveStatus == ON) {
arriveStatus = httpGETRequest(serverNameArrive).toInt();
}
stop_time = millis();
total_time = stop_time - start_time;
ChronoLog += "<p>Courru en </p>";
float timeSe = total_time * 0.001;
//ChronoLog += "<p><b>" + String(timeSe) + "</b></p>" ;
Serial.println("Courru en");
Serial.println(timeSe);
}
}
void ResetChrono () {
reset = 0;
departStatus = 0;
arriveStatus = 0;
start_time = 0;
stop_time = 0;
total_time = 0;
}
void Webserver() {
// Listen for incoming clients
client = server.available();
if (client) { // If a new client connects,
currentTime = millis();
previousTime = currentTime;
Serial.println("New Client."); // print a message out in the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
currentTime = millis();
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
header += c;
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
//RESET CHRONO
if (header.indexOf("GET /RESET") >= 0) {
ResetChrono();
}
// turns the GPIOs on and off
if (header.indexOf("GET /26/on") >= 0) {
Serial.println("GPIO 26 on");
output26State = "on";
digitalWrite(output26, HIGH);
} else if (header.indexOf("GET /26/off") >= 0) {
Serial.println("GPIO 26 off");
output26State = "off";
digitalWrite(output26, LOW);
} else if (header.indexOf("GET /27/on") >= 0) {
Serial.println("GPIO 27 on");
output27State = "on";
digitalWrite(output27, HIGH);
} else if (header.indexOf("GET /27/off") >= 0) {
Serial.println("GPIO 27 off");
output27State = "off";
digitalWrite(output27, LOW);
}
// Display the HTML web page
client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
//Chrono(client);
client.println("<link rel=\"icon\" href=\"data:,\">");
// CSS to style the on/off buttons
// Feel free to change the background-color and font-size attributes to fit your preferences
client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
client.println(".button2 {background-color: #555555;}</style></head>");
// Web Page Heading
client.println("<body><h1>CHRONO</h1>");
client.println(ChronoLog);
client.println("<p><button class=\"button\">RESET</button></p>");
// Display current state, and ON/OFF buttons for GPIO 26
client.println("<p>GPIO 26 - State " + output26State + "</p>");
// If the output26State is off, it displays the ON button
if (output26State == "off") {
client.println("<p><button class=\"button\">ON</button></p>");
} else {
client.println("<p><button class=\"button button2\">OFF</button></p>");
}
// Display current state, and ON/OFF buttons for GPIO 27
client.println("<p>GPIO 27 - State " + output27State + "</p>");
// If the output27State is off, it displays the ON button
if (output27State == "off") {
client.println("<p><button class=\"button\">ON</button></p>");
} else {
client.println("<p><button class=\"button button2\">OFF</button></p>");
}
client.println("</body></html>");
// The HTTP response ends with another blank line
client.println();
// Break out of the while loop
break;
} else { // if you got a newline, then clear currentLine
currentLine = "";
}
} else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
}
}
// Clear the header variable
header = "";
// Close the connection
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}
//Task1code: blinks an LED every 1000 ms
void Task1code( void * pvParameters ){
Serial.print("Task1 running on core ");
Serial.println(xPortGetCoreID());
for(;;){
Chrono();
}
}
//Task2code: blinks an LED every 700 ms
void Task2code( void * Parameters ){
Serial.print("Task2 running on core ");
Serial.println(xPortGetCoreID());
for(;;){
Webserver();
}
}
void loop() {
}
Do you have any suggestion to optimize my code or a solution to not have the problem anymore ?

You're getting watchdog timer resets. That means your code has been running for too long without resetting a timer that's used to recover from crashes and infinite loops. This timer is handled automatically by the underlying code in the Arduino Core.
Your Chrono and Webserver tasks simply won't work the way you've written them. They never yield the processor. The ESP32 does not do multitasking the way Linux or Windows does. Multitasking on the ESP32 is non-preemptive. A task runs until it says "okay, I've done enough, someone else can run now". These two tasks never do that, so the watchdog timer goes off. Even if the watchdog timer didn't go off, this wouldn't work because nothing else would get the chance to run.
At the least you need to yield the processor in each of the tasks:
for(;;){
Chrono();
}
should be:
for(;;){
Chrono();
delay(1);
}
and
for(;;){
Webserver();
}
should be
for(;;){
Webserver();
delay(1);
}
Your code also has a lot of places where you do things like this:
while (departStatus == OFF) {
departStatus = digitalRead(departReceiver);
}
If departStatus stays OFF for too long, this will trigger the watchdog timer.
Any time you have a loop like this you need to make sure that the underlying system has a change to run once in a while.
Rewrite every single while loop that you have that's like that to call delay(1); - that will give the Arduino Core a chance to reset the watchdog timer.
Like so:
while (departStatus == OFF) {
departStatus = digitalRead(departReceiver);
delay(1);
}

I try a method i found on the web, and it's works.
Add libraries :
#include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h"
Create a method:
void feedthedog () {
TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
TIMERG0.wdt_feed = 1;
TIMERG0.wdt_wprotect = 0;
}
Add execution of the method in every while
while (departStatus == OFF) {
feedthedog();
departStatus = digitalRead(departReceiver);
}
I can wait, refresh page on the webserver, i don't get error :
19:38:40.321 -> Task1 running on core 0
19:38:40.321 -> ALGO START
19:39:20.937 -> Borne de début prête
19:39:39.093 -> Borne de fin prête
19:39:39.093 -> En attente du courreur
19:39:39.140 -> Courreur en place
19:39:51.840 -> Chrono lancé
19:39:58.804 -> Courru en
19:39:58.804 -> 6.99
19:39:58.804 -> Tâche fini
I put my update code here:
https://create.arduino.cc/editor/marcoberle/cb88dff8-d56c-422d-9f2e-4011ea2b80f4/preview

Related

Send and read the button state via CAN bus using Arduino

I'm intending to read the change of button input using 2 separate Arduino that connected via CAN bus (MP2515). The transmitter will connect to button with internal pulldown resistor, that pin will act as external interrupt. My reference is coming from here. By not assign any value to data frame (canMsg1 and canMsg2 in the code below), is that enough for the receiver to understand the input pin state?
The origin code using digitalRead(pin) to read and later write state of the button by single Arduino.
transmitter of CAN massage
#include <SPI.h>
#include <mcp2515.h>
struct can_frame canMsg1;
struct can_frame canMsg2;
MCP2515 mcp2515(10);
int incPin(2);
int decPin(3);
unsigned long current_time = 0;
unsigned long previous_time = 0;
void setup() {
Serial.begin(9600);
SPI.begin();
mcp2515.reset();
mcp2515.setBitrate(CAN_500KBPS, MCP_8MHZ);
mcp2515.setNormalMode();
canMsg1.can_id = 0xAA;
canMsg1.can_dlc = 1;
canMsg2.can_id = 0xBB
canMsg2.can_dlc = 1;
pinMode(incPin, INPUT_PULLUP);
pinMode(decnPin, INPUT_PULLUP);
attachInterrupt(incpPin, inc, FALLING);
attachInterrupt(decPin, dec, FALLING);
}
void loop() {}
void inc() {
current_time = millis();
if (current_time - previous_time > 200) { //debouncing for 0.2s
mcp2515.sendMessage(&canMsg1);
}
previous_time = current_time;
}
void dec() {
current_time = millis();
if (current_time - previous_time > 200) { //debouncing for 0.2s
mcp2515.sendMessage(&canMsg2);
}
previous_time = current_time;
}
receiver/reader of CAN massage
#include <SPI.h>
#include <mcp2515.h>
struct can_frame canMsg1;
struct can_frame canMsg2;
MCP2515 mcp2515(10);
int pos = 0;
int up;
int down;
void setup() {
Serial.begin(9600);
SPI.begin();
mcp2515.reset();
mcp2515.setBitrate(CAN_500KBPS, MCP_8MHZ);
mcp2515.setNormalMode();
}
void loop() {
if (mcp2515.readMessage(&canMsg1) == MCP2515::ERROR_OK) { //read CAN increment button message
if (canMsg1.can_id==0xAA) {
up = canMsg1.data[0];
if (up == LOW) {
pos++;
} else {}
}
}
if (mcp2515.readMessage(&canMsg2) == MCP2515::ERROR_OK) { //read CAN decrement button message
if (canMsg2.can_id==0xBB) {
down = canMsg2.data[0];
if (down == LOW) {
pos--;
} else {}
}
}
}
You are right, your CAN events do not require any data. But then, why do you set can_dlc to 1? No data is 0 bytes.
You can try this:
Get rid of:
struct can_frame canMsg1; // these only hog global memory for no practical use.
struct can_frame canMsg2;
Change your interrupt routines to:
void inc() {
current_time = millis();
if (current_time - previous_time > 200) { //debouncing for 0.2s
mcp2515.beginPacket(0xAA);
mcp2515.endPacket();
}
previous_time = current_time;
}
void dec() {
current_time = millis();
if (current_time - previous_time > 200) { //debouncing for 0.2s
mcp2515.beginPacket(0xBB);
mcp2515.endPacket();
}
previous_time = current_time;
}
I could not figure out what canMsg7 and canMsg8 were. Nor why you'd need several message structures in global memory to receive one CAN message at a time... I really don't think that's necessary. Since your packets have no data, receiving gets streamlined as well:
int loop() {
if (mcp2515.parsePacket() != 0) { // != 0 => we have fully received a packet.
switch (mcp2515.packetId()) {
case 0xAA:
// inc switch was pressed
// ...
break;
case 0xBB:
// dec switch was pressed
// ...
break;
}
}
}

C++ how to query value outside the callback arduino

I want that the measurement interval and MQTT server settings can be changed from cellphone by BLE. I use LightBlue as a mobile application.
Here is my BLE code that works well with my mobile application
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = pCharacteristic->getValue();
if (value.length() > 0) {
Serial.println("*********");
Serial.print("New value: ");
for (int i = 0; i < value.length(); i++)
Serial.print(value[i]);
Serial.println();
Serial.println("*********");
}
}
};
void setup() {
Serial.begin(115200);
Serial.println("1- Download and install an BLE scanner app in your phone");
Serial.println("2- Scan for BLE devices in the app");
Serial.println("3- Connect to MyESP32");
Serial.println("4- Go to CUSTOM CHARACTERISTIC in CUSTOM SERVICE and write something");
Serial.println("5- See the magic =)");
BLEDevice::init("MyESP32");
BLEServer *pServer = BLEDevice::createServer();
BLEService *pService = pServer->createService(SERVICE_UUID);
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setCallbacks(new MyCallbacks());
pCharacteristic->setValue("Hello World");
pService->start();
BLEAdvertising *pAdvertising = pServer->getAdvertising();
pAdvertising->start();
}
void loop() {
// put your main code here, to run repeatedly:
delay(2000);
}
This is MQTT code :
void loop() {
unsigned long currentMillis = millis();
// Every X number of seconds (interval = 10 seconds)
// it publishes a new MQTT message
if (currentMillis - previousMillis >= interval) {
// Save the last time a new reading was published
previousMillis = currentMillis;
// New DHT sensor readings
hum = dht.readHumidity();
// Read temperature as Celsius (the default)
temp = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
//temp = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(temp) || isnan(hum)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
// Publish an MQTT message on topic esp32/dht/temperature
uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB_TEMP, 1, true, String(temp).c_str());
Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP, packetIdPub1);
Serial.printf("Message: %.2f \n", temp);
// Publish an MQTT message on topic esp32/dht/humidity
uint16_t packetIdPub2 = mqttClient.publish(MQTT_PUB_HUM, 1, true, String(hum).c_str());
Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_HUM, packetIdPub2);
Serial.printf("Message: %.2f \n", hum);
}
}
Please how I can set the interval to whichever variable from the BLE code instead of 10000.
long interval = 10000;
You need to declare your variable interval as global variable to access it from everywhere in your file. A global variable can be declared outside of functions.
The value you receive is of type std::string and you want to use it as long. You can use toInt() to convert the variable from String to Long.
Try something like this:
long interval = 10000; // Set default value
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string value = pCharacteristic->getValue();
if (value.length() > 0) {
Serial.println("*********");
Serial.print("New value: ");
for (int i = 0; i < value.length(); i++)
Serial.print(value[i]);
Serial.println();
Serial.println("*********");
interval = value.toInt(); // <-- Set received value
}
}
};

ESP32 handle webserver and neopixels (with delay) in two cores

I'm searching the answer for a while but haven't found how to fix this problem. I have a lot of neopixel animations (currently 50 of them), these are written with delays which keeps the animations simple and readable. disadvantage is the delays as you all know. 50 animations to rewrite is a hell of a job so I want to avoid this. What I did is bought an ESP32 with two cores, so I thought I could run the animations on one core and the webserver on one core. previously I wanted to do I with an interrupt on a ESP8266 but I red and tested that I was not possible to do communication things or run a webserver in an interrupt for example. Is it possible to do that with two cores on an ESP32 or am I running in to the same problem as earlier? current output of the program: My webserver starts and the neopixel animation is showed when pushing the button, however my webserver continuously restarts over and over again. Any help appreciated, thanks in advance!
ps: In the worst case scenario I have to rewrite my animations, anyone an idea how to replace 3 for loops in to non blocking code?
code running on ESP32:
TaskHandle_t Task1;
TaskHandle_t Task2;
#include <Adafruit_NeoPixel.h>
#define PIN 6
#define NUM_LEDS 24
// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);
void colorWipe(byte red, byte green, byte blue, int SpeedDelay) {
for(uint16_t i=0; i<NUM_LEDS; i++) {
setPixel(i, red, green, blue);
showStrip();
delay(SpeedDelay);
}
}
// *** REPLACE TO HERE ***
void showStrip() {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.show();
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
FastLED.show();
#endif
}
void setPixel(int Pixel, byte red, byte green, byte blue) {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.setPixelColor(Pixel, strip.Color(red, green, blue));
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
leds[Pixel].r = red;
leds[Pixel].g = green;
leds[Pixel].b = blue;
#endif
}
void setAll(byte red, byte green, byte blue) {
for(int i = 0; i < NUM_LEDS; i++ ) {
setPixel(i, red, green, blue);
}
showStrip();
}
#include <WiFi.h>
const char* WIFI_NAME= "xxxxxxxxxx";
const char* WIFI_PASSWORD = "xxxxxxxxxx";
WiFiServer server(80);
String header;
// Auxiliary variables to store the current output state
String output5State = "off";
String output4State = "off";
// Assign output variables to GPIO pins
const int output5 = 2;
const int output4 = 4;
// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0;
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;
String ledState = "off";
void setup() {
//create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
xTaskCreatePinnedToCore(
Task1code, /* Task function. */
"Task1", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
delay(500);
//create a task that will be executed in the Task2code() function, with priority 1 and executed on core 1
xTaskCreatePinnedToCore(
Task2code, /* Task function. */
"Task2", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task2, /* Task handle to keep track of created task */
1); /* pin task to core 1 */
delay(500);
Serial.begin(115200);
// Initialize the output variables as outputs
pinMode(output5, OUTPUT);
pinMode(output4, OUTPUT);
// Set outputs to LOW
digitalWrite(output5, LOW);
digitalWrite(output4, LOW);
}
//Task1code: blinks an LED every 1000 ms
void Task1code( void * pvParameters ){
Serial.print("Task1 running on core ");
Serial.println(xPortGetCoreID());
strip.begin();
strip.show(); // Initialize all pixels to 'off'
for(;;){
/*
digitalWrite(output5, HIGH);
delay(1000);
digitalWrite(output5, LOW);
delay(1000);*/
//Serial.print("state:" + ledState);
if(ledState == "on") {
//digitalWrite(output4, HIGH);
colorWipe(0x00,0xff,0x00, 50);
colorWipe(0x00,0x00,0x00, 50);
} else {
strip.clear();
strip.show();
}
}
}
//Task2code: blinks an LED every 700 ms
void Task2code( void * pvParameters ){
Serial.print("Connecting to ");
Serial.println(WIFI_NAME);
WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print("Trying to connect to Wifi Network");
}
Serial.println("");
Serial.println("Successfully connected to WiFi network");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();
for(;;){
WiFiClient client = server.available();
if (client) {
Serial.println("New Client."); // print a message out in the serial port
String currentLine = ""; // make a String to hold incoming data from the client
currentTime = millis();
previousTime = currentTime;
while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
currentTime = millis();
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
header += c;
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
// turns the GPIOs on and off
if (header.indexOf("GET /5/on") >= 0) {
Serial.println("GPIO 5 on");
output5State = "on";
//digitalWrite(output5, HIGH);
} else if (header.indexOf("GET /5/off") >= 0) {
Serial.println("GPIO 5 off");
output5State = "off";
//digitalWrite(output5, LOW);
} else if (header.indexOf("GET /4/on") >= 0) {
Serial.println("GPIO 4 on");
output4State = "on";
ledState = "on";
//digitalWrite(output4, HIGH);
} else if (header.indexOf("GET /4/off") >= 0) {
Serial.println("GPIO 4 off");
output4State = "off";
ledState = "off";
//digitalWrite(output4, LOW);
}
// Display the HTML web page
client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<link rel=\"icon\" href=\"data:,\">");
// CSS to style the on/off buttons
// Feel free to change the background-color and font-size attributes to fit your preferences
client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
client.println(".button2 {background-color: #77878A;}</style></head>");
// Web Page Heading
client.println("<body><h1>ESP8266 Web Server</h1>");
// Display current state, and ON/OFF buttons for GPIO 5
client.println("<p>GPIO 5 - State " + output5State + "</p>");
// If the output5State is off, it displays the ON button
if (output5State=="off") {
client.println("<p><button class=\"button\">ON</button></p>");
} else {
client.println("<p><button class=\"button button2\">OFF</button></p>");
}
// Display current state, and ON/OFF buttons for GPIO 4
client.println("<p>GPIO 4 - State " + output4State + "</p>");
// If the output4State is off, it displays the ON button
if (output4State=="off") {
client.println("<p><button class=\"button\">ON</button></p>");
} else {
client.println("<p><button class=\"button button2\">OFF</button></p>");
}
client.println("</body></html>");
// The HTTP response ends with another blank line
client.println();
// Break out of the while loop
break;
} else { // if you got a newline, then clear currentLine
currentLine = "";
}
} else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
}
}
// Clear the header variable
header = "";
// Close the connection
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}
}
void loop(){
}
animation with three for loops:
void theaterChaseRainbow(int SpeedDelay) { /* for wheel watch higher in the code */
byte *c;
for (int j=0; j < 256; j++) { // cycle all 256 colors in the wheel
for (int q=0; q < 3; q++) {
for (int i=0; i < NUM_LEDS; i=i+3) {
c = Wheels( (i+j) % 255);
setPixel(i+q, *c, *(c+1), *(c+2)); //turn every third pixel on
}
showStrip();
delay(SpeedDelay);
for (int i=0; i < NUM_LEDS; i=i+3) {
setPixel(i+q, 0,0,0); //turn every third pixel off
}
}
}
}
You're 95% of the way there. ESP32 runs FreeRTOS with preemptive multi-threading. Your code is quite reasonably divided into two threads (Task1 and Task2) which run on different cores. In fact, the number of cores doesn't really matter much as long as you're not running out of CPU cycles or violating the real-time deadlines of your animations. You could probably run both tasks concurrently on a single core without the ESP32 breaking a sweat.
As for the HTTP server restarting - that's the intended behaviour of your code, is it not? The (rather horribly indented) function Task2code runs a never-ending loop which starts the HTTP server, serves a page and the stops. Is this loop really necessary?

the IF command cant continue to else for turn off motor dc

I’ve a project for control a robot in arduino via android.
the trouble is when I press a button for pin 6 (Maju), its turn ON.
But when I press it again its always ON, cant turn OFF.
Here's my code:
int kananMaju;
int kiriMundur;
int kananMundur;
int kiriMaju;
#define Kanan A4
#define Kiri 13
#define Maju 6
#define Mundur A5
#define STBY 12
#define PWMA 11 //left
#define PWMB 10 //right
#define AIN2 8
#define AIN1 7
#define BIN1 3
#define BIN2 2
#include <SoftwareSerial.h>
#define DEBUG true
SoftwareSerial esp8266(4,5); // make RX Arduino line is pin 2, make TX Arduino line is pin 3.
// This means that you need to connect the TX line from the esp to the Arduino's pin 2
// and the RX line from the esp to the Arduino's pin 3
void setup()
{
Serial.begin(9600);
esp8266.begin(9600); // your esp's baud rate might be different
pinMode(STBY,OUTPUT);
pinMode(BIN2,OUTPUT);
pinMode(BIN1,OUTPUT);
pinMode(AIN2,OUTPUT);
pinMode(AIN1,OUTPUT);
pinMode(PWMB,OUTPUT);
pinMode(PWMA,OUTPUT);
digitalWrite(STBY, HIGH); //standby
digitalWrite(BIN1, HIGH);
digitalWrite(BIN2, HIGH);
digitalWrite(AIN1, HIGH);
digitalWrite(AIN2, HIGH);
analogWrite(PWMB, 100); //490 Hz
analogWrite(PWMA, 100); //490 Hz
pinMode(Maju,OUTPUT);
digitalWrite(Maju,LOW);
sendCommand("AT+RST\r\n",2000,DEBUG); // reset module
sendCommand("AT+CWMODE=1\r\n",1000,DEBUG); // configure as access point
sendCommand("AT+CWJAP=\"PanduGanteng\",\"akhirpekan666\"\r\n",3000,DEBUG);
delay(10000);
sendCommand("AT+CIFSR\r\n",1000,DEBUG); // get ip address
sendCommand("AT+CIPMUX=1\r\n",1000,DEBUG); // configure for multiple connections
sendCommand("AT+CIPSERVER=1,8080\r\n",1000,DEBUG); // turn on server on port 80
Serial.println("Server Ready");
}
void loop()
{
if(esp8266.available()) // check if the esp is sending a message
{
if(esp8266.find("+IPD,"))
{
delay(1000); // wait for the serial buffer to fill up (read all the serial data)
// get the connection id so that we can then disconnect
int connectionId = esp8266.read()-48; // subtract 48 because the read() function returns
// the ASCII decimal value and 0 (the first decimal number) starts at 48
esp8266.find("pin="); // advance cursor to "pin="
int pinNumber = (esp8266.read()-48); // get first number i.e. if the pin 13 then the 1st number is 1
int secondNumber = (esp8266.read()-48);
if(secondNumber>=0 && secondNumber<=9)
{
pinNumber*=10;
pinNumber +=secondNumber; // get second number, i.e. if the pin number is 13 then the 2nd number is 3, then add to the first number
}
digitalWrite(pinNumber, !digitalRead(pinNumber)); // toggle pin
// build string that is send back to device that is requesting pin toggle
String content;
content = "Pin ";
content += pinNumber;
content += " is ";
if(digitalRead(Maju))
{
content += "ON";
kiriMaju;{
digitalWrite(STBY,HIGH);
analogWrite(PWMA, 100);
digitalWrite(AIN1,HIGH);
digitalWrite(AIN2,LOW);
}
kananMaju;{
digitalWrite(STBY,HIGH);
analogWrite(PWMB, 100);
digitalWrite(BIN1, LOW);
digitalWrite(BIN2, HIGH);
}
}
else
{
content += "OFF";
}
sendHTTPResponse(connectionId,content);
// make close command
String closeCommand = "AT+CIPCLOSE=";
closeCommand+=connectionId; // append connection id
closeCommand+="\r\n";
sendCommand(closeCommand,1000,DEBUG); // close connection
}
}
}
/*
* Name: sendData
* Description: Function used to send data to ESP8266.
* Params: command - the data/command to send; timeout - the time to wait for a response; debug - print to Serial window?(true = yes, false = no)
* Returns: The response from the esp8266 (if there is a reponse)
*/
String sendData(String command, const int timeout, boolean debug)
{
String response = "";
int dataSize = command.length();
char data[dataSize];
command.toCharArray(data,dataSize);
esp8266.write(data,dataSize); // send the read character to the esp8266
if(debug)
{
Serial.println("\r\n====== HTTP Response From Arduino ======");
Serial.write(data,dataSize);
Serial.println("\r\n========================================");
}
long int time = millis();
while( (time+timeout) > millis())
{
while(esp8266.available())
{
// The esp has data so display its output to the serial window
char c = esp8266.read(); // read the next character.
response+=c;
}
}
if(debug)
{
Serial.print(response);
}
return response;
}
/*
* Name: sendHTTPResponse
* Description: Function that sends HTTP 200, HTML UTF-8 response
*/
void sendHTTPResponse(int connectionId, String content)
{
// build HTTP response
String httpResponse;
String httpHeader;
// HTTP Header
httpHeader = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n";
httpHeader += "Content-Length: ";
httpHeader += content.length();
httpHeader += "\r\n";
httpHeader +="Connection: close\r\n\r\n";
httpResponse = httpHeader + content + " "; // There is a bug in this code: the last character of "content" is not sent, I cheated by adding this extra space
sendCIPData(connectionId,httpResponse);
}
/*
* Name: sendCIPDATA
* Description: sends a CIPSEND=<connectionId>,<data> command
*
*/
void sendCIPData(int connectionId, String data)
{
String cipSend = "AT+CIPSEND=";
cipSend += connectionId;
cipSend += ",";
cipSend +=data.length();
cipSend +="\r\n";
sendCommand(cipSend,1000,DEBUG);
sendData(data,1000,DEBUG);
}
/*
* Name: sendCommand
* Description: Function used to send data to ESP8266.
* Params: command - the data/command to send; timeout - the time to wait for a response; debug - print to Serial window?(true = yes, false = no)
* Returns: The response from the esp8266 (if there is a reponse)
*/
String sendCommand(String command, const int timeout, boolean debug)
{
String response = "";
esp8266.print(command); // send the read character to the esp8266
long int time = millis();
while( (time+timeout) > millis())
{
while(esp8266.available())
{
// The esp has data so display its output to the serial window
char c = esp8266.read(); // read the next character.
response+=c;
}
}
if(debug)
{
Serial.print(response);
}
return response;
}
I want to when I press button for pin 6 is ON, and when I press it again its OFF. But it's always turned ON, where's my fault?
Maju should be an input not an output
And you need to toggle a state
pinMode(Maju,INPUT);
static boolean function get_state()
{
static boolean previous = LOW;
static boolean state = LOW;
boolean current = digitalRead(Maju);
if (current == HIGH && current != previous) {
state = (state == LOW) ? HIGH : LOW;
}
previous = current;
return state;
}

Alarm.alarmRepeat repeats only twice then stops working

I'm using an arduino uno with a CC3000 WiFi Shield. The ardunio counts people using a light barrier and then reports the countings to the xievly site. It seems to work fine for an hour or two but then nothing happens. Any ideas?
// Libraries
#include <Adafruit_CC3000.h>
#include <SPI.h>
#include <Time.h>
#include <TimeAlarms.h>
// Define CC3000 chip pins
#define ADAFRUIT_CC3000_IRQ 3
#define ADAFRUIT_CC3000_VBAT 5
#define ADAFRUIT_CC3000_CS 10
// Create CC3000 instances
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
SPI_CLOCK_DIV2); // you can change this clock speed
// WLAN parameters
#define WLAN_SSID "XX"
#define WLAN_PASS "XX"
#define WLAN_SECURITY WLAN_SEC_WPA2
// Xively parameters
#define WEBSITE "https://xively.com/feeds/XX"
#define API_key "XXX"
#define feedID "XXXX``"
uint32_t ip;
Adafruit_CC3000_Client client;
const unsigned long
connectTimeout = 15L * 1000L, // Max time to wait for server connection
responseTimeout = 15L * 1000L; // Max time to wait for data from server
// Visitor Counter
int anzahl =0;
int lastState=LOW;
const int inputPin = 2;
void setup()
{
// Initialize
attachInterrupt(0, count, RISING);
Serial.begin(115200);
if (!cc3000.begin())
{
while(1);
}
// Connect to WiFi network
cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY);
/* Wait for DHCP to complete */
while (!cc3000.checkDHCP())
{
delay(100);
}
unsigned long t = getTime();
cc3000.disconnect();
setTime(hour(t)+2,minute(t),second(t),month(t),day(t),year(t));
Alarm.alarmRepeat(9,59,59, Messung);
Alarm.alarmRepeat(10,59,59, Messung);
Alarm.alarmRepeat(11,59,59, Messung);
Alarm.alarmRepeat(12,59,59, Messung);
Alarm.alarmRepeat(13,59,59, Messung);
Alarm.alarmRepeat(14,59,59, Messung);
Alarm.alarmRepeat(15,59,59, Messung);
Alarm.alarmRepeat(16,59,59, Messung);
Alarm.alarmRepeat(17,59,59, Messung);
Alarm.alarmRepeat(18,59,59, Messung);
Alarm.alarmRepeat(19,59,59, Messung);
Alarm.alarmRepeat(22,59,59, Zeitkorrektur);
}
void count()
{
delay(10);
int val = digitalRead(inputPin);
if (val == HIGH && lastState==LOW)
{
anzahl++;
lastState=val;
}
else
{
lastState=val;
}
}
void Zeitkorrektur()
{
getTime();
}
void Messung()
{
datalog();
}
void loop()
{
Alarm.delay(1000);
}
// Minimalist time server query; adapted from Adafruit Gutenbird sketch,
// which in turn has roots in Arduino UdpNTPClient tutorial.
unsigned long getTime()
{
uint8_t buf[48];
unsigned long ip, startTime, t = 0L;
// Hostname to IP lookup; use NTP pool (rotates through servers)
if(cc3000.getHostByName("pool.ntp.org", &ip)) {
static const char PROGMEM
timeReqA[] = { 227, 0, 6, 236 },
timeReqB[] = { 49, 78, 49, 52 };
Serial.println(F("\r\nAttempting connection..."));
startTime = millis();
do {
client = cc3000.connectUDP(ip, 123);
} while((!client.connected()) &&
((millis() - startTime) < connectTimeout));
if(client.connected()) {
Serial.print(F("connected!\r\nIssuing request..."));
// Assemble and issue request packet
memset(buf, 0, sizeof(buf));
memcpy_P( buf , timeReqA, sizeof(timeReqA));
memcpy_P(&buf[12], timeReqB, sizeof(timeReqB));
client.write(buf, sizeof(buf));
Serial.print(F("\r\nAwaiting response..."));
memset(buf, 0, sizeof(buf));
startTime = millis();
while((!client.available()) &&
((millis() - startTime) < responseTimeout));
if(client.available()) {
client.read(buf, sizeof(buf));
t = (((unsigned long)buf[40] << 24) |
((unsigned long)buf[41] << 16) |
((unsigned long)buf[42] << 8) |
(unsigned long)buf[43]) - 2208988800UL;
Serial.print(F("OK\r\n"));
}
client.close();
}
}
if(!t) Serial.println(F("error"));
return t;
}
void datalog()
{
//noInterrupts();
// Connect to WiFi network
cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY);
/* Wait for DHCP to complete */
while (!cc3000.checkDHCP())
{
delay(100);
}
// Set the website IP
uint32_t ip = cc3000.IP2U32(216,52,233,120);
cc3000.printIPdotsRev(ip);
// Get data & transform to integers
int visitors = (int) anzahl/2; //Visitors going in and out therefore divided by 2
// Prepare JSON for Xively & get length
int length = 0;
String data = "";
data = data + "\n" + "{\"version\":\"1.0.0\",\"datastreams\" : [ {\"id\" : \"Visitors\",\"current_value\" : \"" + String(visitors) + "\"}]}";
length = data.length();
// Send request
Adafruit_CC3000_Client client = cc3000.connectTCP(ip, 80);
if (client.connected()) {
Serial.println("Connected!");
client.println("PUT /v2/feeds/" + String(feedID) + ".json HTTP/1.0");
client.println("Host: api.xively.com");
client.println("X-ApiKey: " + String(API_key));
client.println("Content-Length: " + String(length));
client.print("Connection: close");
client.println();
client.print(data);
client.println();
} else {
Serial.println(F("Connection failed"));
return;
}
Serial.println(F("-------------------------------------"));
while (client.connected()) {
while (client.available()) {
char c = client.read();
Serial.print(c);
}
}
client.close();
Serial.println(F("-------------------------------------"));
Serial.println(F("\n\nDisconnecting"));
cc3000.disconnect();
anzahl =0;
//interrupts();
}
In setup() you configured interrupt with RISING. That means that it fires when the pin goes from low state to high state. But in interrupt handler - count() you have strange logic which looks excessive since you already configured interrupt to fire only once on event.
Let's see what happens in count(). val will always be HIGH (well, considering only normal case, not glitches).. When the first interrupt comes lastState is LOW as initial value and we increment, but all successive calls will not because lastState is HIGH and never becomes LOW again.
So, to fix problem, we simply need to drop lastState because it's not needed
void count()
{
delay(10);
// avoiding glitches - check if it's still high
int val = digitalRead(inputPin);
if (val == HIGH)
anzahl++;
}

Resources