Multitasking in Arduino using millis() function - function
I'm thinking of building a DIY gokart-offroad type of car from scrap vehicle parts. And as electronics, I'm planning on using my Arduino Uno for controlling basically everything. So I just made a gear display which lets me know which gear I'm currently on. And a simple parking sensor.
If I'm too close to an object the parking sensor buzzer will blink. And I can't blink with delay() functions because if I try to shift up when it's blinking, the input won't register because delay is a blocking function. So I tried to use millis instead but seems like it also doesn't register.
The concept is easy. I will have two buttons on each side of my shiftstick. And when I shift up the button gets pressed therefore the 7 segment display adds one. And another one for downshifting.
I have not added the reverse gear yet, but still when the parking sensor function is working, I still can't push the buttons for a good amount of time.
I hope you guys could understand what I'm trying to say. I just started coding in Arduino so I don't have enough experience. I'm leaving the .ino file as a code block. I tried to explain everything in the code. Hopefully someone knows the solution for this. Thanks in advance...
// Setting up the pins for 7-Segment-Display.
const int E = 13;
const int D = 12;
const int C = 11;
const int DP = 10;
const int G = 9;
const int F = 8;
const int A = 7;
const int B = 6;
// Setting up the counter for gear shifting.
int gearCount = 0;
// Setting up the button states and button pin for state-change detectors.
int buttonAddPin = 5;
int buttonAddState = 0;
int previousButtonAddState = 0;
// And this is for downshifting.
int buttonSubstractPin = 4;
int buttonSubstractState = 0;
int previousButtonSubstractState = 0;
// Adding buzzer for parking sensor.
const int buzzerPin = 3;
int buzzerTone = 0;
// Adding parking sensor.
const int trigPin = 2;
const int echoPin = 1;
long duration;
int distance;
// Adding non-delay blinker with millis for buzzer to blink when sensor detects an object.
unsigned long previousTime = 0;
/*---------------------------------- FUNCTIONS FOR SHIFTING -------------------------------------------------*/
// "zero" function is the series of commands for displayıng 0 on the 7-Segment corresponding to neutral gear.
void zero()
{
digitalWrite(A, LOW);
digitalWrite(B, LOW);
digitalWrite(C, LOW);
digitalWrite(D, LOW);
digitalWrite(E, LOW);
digitalWrite(F, LOW);
digitalWrite(G, HIGH);
digitalWrite(DP, HIGH);
}
// "one" function is the series of commands for displaying 1 on the 7-Segment-Display corresponding to 1st gear.
void one()
{
digitalWrite(A, HIGH);
digitalWrite(B, LOW);
digitalWrite(C, LOW);
digitalWrite(D, HIGH);
digitalWrite(E, HIGH);
digitalWrite(F, HIGH);
digitalWrite(G, HIGH);
digitalWrite(DP, HIGH);
}
// "two" function is the series of commands for displaying 2 on the 7-Segment-Display corresponding to 2nd gear.
void two()
{
digitalWrite(A, LOW);
digitalWrite(B, LOW);
digitalWrite(C, HIGH);
digitalWrite(D, LOW);
digitalWrite(E, LOW);
digitalWrite(F, HIGH);
digitalWrite(G, LOW);
digitalWrite(DP, HIGH);
}
// "three" function is the series of commands for displaying 3 on the 7-Segment-Display corresponding to 3rd gear.
void three()
{
digitalWrite(A, LOW);
digitalWrite(B, LOW);
digitalWrite(C, LOW);
digitalWrite(D, LOW);
digitalWrite(E, HIGH);
digitalWrite(F, HIGH);
digitalWrite(G, LOW);
digitalWrite(DP, HIGH);
}
// And now the main function that we are going to call in "void loop" to determine which gear we are on.
void gearDisplay()
{
buttonAddState = digitalRead(buttonAddPin); // And now the button state change detector for shifting up is ready. As you can see when I push the button
// program adds 1 to gearCount variable. So now gearCount is 1. Therefore the 7-Segment-Display will show
if(buttonAddState != previousButtonAddState){ // 1 on it. We will do this a bit later.
if(buttonAddState == HIGH){
gearCount++;
}
delay(50);
}
previousButtonAddState = buttonAddState;
// Now for downshifting.
buttonSubstractState = digitalRead(buttonSubstractPin);
if(buttonSubstractState != previousButtonSubstractState) {
if(buttonSubstractState == HIGH){
gearCount--;
}
delay(50);
}
previousButtonSubstractState = buttonSubstractState;
// Now we will call one of the 7-Segment-Display number functions according to the gearCount variable.
if(gearCount == 0){
zero();
}
else if(gearCount == 1){
one();
}
else if(gearCount == 2){
two();
}
else if(gearCount == 3){
three();
}
else if(gearCount > 3){ // Just making sure if we press buttons accidentally more than enough, it sets gearCount back to closest gear available.
gearCount--;
}
else if(gearCount < 0){ // Same with this one.
gearCount++;
}
}
// That was al for the gear panel. Now the hard part. The parking sensor.
/*---------------------------------------------- SHIFTING DONE ----------------------------------------------------*/
/*--------------------------------------------- PARKING SENSOR ------------------------------------------------------*/
void parkingSensor()
{
digitalWrite(trigPin, LOW); // Resetting trigPin
delayMicroseconds(2); // Delaying to prevent any issiues. ( I saw this online, most people do it like this so I also did.)
digitalWrite(trigPin, HIGH); // Creating a short soundwave.
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH); // Detecting the time that passes for the soundwave to reach back to the receiver.
distance = duration*0.034/2; // Simple math for calculating the distance between the obstacle and sensor.
unsigned long currentTime = millis(); // Store the current time for blinking the buzzers.
if((distance > 0) && (distance < 31)){ // If the distance is in between 0-31 buzz non-stop.
buzzerTone = 1000;
tone(buzzerPin, buzzerTone);
}
else if((distance > 30) && (distance < 76)){ // If the distance is between 30-76 buzz every 100 miliseconds.
if(currentTime - previousTime >= 100){
previousTime = currentTime;
if(buzzerTone == 1000){
buzzerTone = 0;
}
else {
buzzerTone = 1000;
}
tone(buzzerPin, buzzerTone);
}
}
else if((distance > 75) && (distance < 101)){ // If the distance is between 75-101 buzz every 300 miliseconds.
if(currentTime - previousTime >= 300){
previousTime = currentTime;
if(buzzerTone == 1000){
buzzerTone = 0;
}
else {
buzzerTone = 1000;
}
tone(buzzerPin, buzzerTone);
}
}
else if(distance > 100){ // If the distance is more than 100 don't buzz.
buzzerTone = 0;
tone(buzzerPin, buzzerTone);
}
}
/*------------------------------- PARKING SENSOR DONE -----------------------------------*/
// And this was, I guess, all I had to do but unfortunately it's not working...
void setup() {
pinMode(A, OUTPUT);
pinMode(B, OUTPUT);
pinMode(C, OUTPUT);
pinMode(D, OUTPUT);
pinMode(E, OUTPUT);
pinMode(F, OUTPUT);
pinMode(G, OUTPUT);
pinMode(DP, OUTPUT);
pinMode(buttonAddPin, INPUT);
pinMode(buttonSubstractPin, INPUT);
pinMode(buzzerPin, OUTPUT);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}
void loop() {
gearDisplay();
parkingSensor();
}
EDIT: Turns out that pulseIn()'s default duration is 1 second. And it's also a blocking function which blocks the buttons from registering inputs on every loop for 1 second. Changing that to smaller values, for example 10ms in my case, was enough and solved the issue. All credit goes to #CherryDT who solved this. Thanks a lot.
btw this is how the code should look like for 10ms:
pulseIn(echoPin, HIGH, 10000)
// Note that the duration in pulseIn() is in microsconds.
EDIT: Turns out that I misunderstood the question. Anyway, leaving this answer here because it answers "how to blink without blocking" which may be useful too.
The answer for the main problem would be: You are using pulseIn which also blocks until the pulse is received. The default timeout for pulseIn is one second, so if there is no object in view of your parking sensor, you are blocking for 1s every time! Since you are probably only interested in reasonably small distances anyway, you could just set a timeout of, say, 10ms (10000us):
pulseIn(echoPin, HIGH, 10000)
If this doesn't fit your requirements or is still too much of a delay though, consider writing your own code instead which measures the time without blocking, processing the button presses in the meantime. See this answer where someone had the exact same issue and solved it this way.
Basically, you could do something like this:
unsigned long pulseTimer = 0;
int lastEchoState = HIGH; // Initially HIGH so that the actual LOW triggers a "change"
void loop () {
int currentEchoState = digitalRead(echoPin);
// To set a timeout of the pulse, simulate a pulse if already waiting for too long
if (lastEchoState == LOW && micros() - pulseTimer > 1000000ul) {
currentEchoState = HIGH;
}
if (currentEchoState != lastEchoState) {
lastEchoState = currentEchoState;
if (currentEchoState == LOW) {
// Echo pulse over (or it's the initial loop iteration)
// Start counting time until echo
// We do this before sending the trigger because pulseIn would
// normally measure until the pulse is *over*, but for simplicity
// we measure until the pulse *starts*, so this implicitly shifts
// the result by our pulse duration, as trigger and echo pulse are
// usually of the same length
pulseTimer = micros();
// Send new trigger pulse
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
} else {
// Pulse came in, measure time
unsigned long pulseDelayTime = micros() - pulseTimer;
// **** DO SOMETHING WITH pulseDelayTime HERE! ****
}
}
// **** DO YOUR REGULAR BUTTON PROCESSING HERE! ****
}
You would do the blinking by setting the LED output to:
(millis() / 500) % 2
...to blink it, on every loop iteration*.
This would basically be LOW for 500ms and HIGH for 500ms, because dividing millis() by 500 (which won't have any fractional part because we are in integer world here) would give a number that increments every 500ms, and % 2 takes it modulo 2, i.e. it'd be 1 for odd and 0 for even numbers. And 1 and 0 are the same as HIGH and LOW for Arduino.
Example:
+----------+--------------+------------------+
| millis() | millis()/500 | (millis()/500)%2 |
+----------+--------------+------------------+
| ... | | |
| 1499 | 2 | 0 (LOW) |
| 1500 | 3 | 1 (HIGH) |
| 1501 | 3 | 1 (HIGH) |
| ... | | |
| 1999 | 3 | 1 (HIGH) |
| 2000 | 4 | 0 (LOW) |
| 2001 | 4 | 0 (LOW) |
| ... | | |
| 2499 | 4 | 0 (LOW) |
| 2500 | 5 | 1 (HIGH) |
| 2501 | 5 | 1 (HIGH) |
| ... | | |
+----------+--------------+------------------+
Cool project, by the way.
*: If you wanted to squeeze a bit more performance out of this, you could save the last pin state in a separate variable and do digitalWrite only when it changed. That's because digitalWrite is pretty slow actually, so you could avoid calling it every time unless an actual change is needed.
Related
How do you call a funcion inside a for loop in Arduino? [closed]
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers. This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers. Closed 9 days ago. Improve this question I am programming my Arduino Uno with an ultrasonic sensor to sense the distance from it and print that on the serial plotter / monitor, at the same time 4 LEDS are blinking. I am not having any problems with them doing their thing at the same time, but I want the ultrasonic sensor to sense more than one time after the LEDS blink once. Here is the code: const int red1 = 4; const int red2 = 5; const int yellow1 = 6; const int yellow2 = 7; const int echo = 10; const int trig = 9; const int buzzer = 11; int maxCmAway = 50; float duration_us, distance_cm; void setup() { Serial.begin (9600); pinMode(red1, OUTPUT); pinMode(red2, OUTPUT); pinMode(yellow1, OUTPUT); pinMode(yellow2, OUTPUT); pinMode(trig, OUTPUT); pinMode(echo, INPUT); } void loop() { digitalWrite(yellow1, LOW); digitalWrite(yellow2, LOW); digitalWrite(red1, HIGH); digitalWrite(red2, HIGH); for(int i=0; i<6; i++) { if (checkDist() > maxCmAway) { blip(); } else { noTone(buzzer); delay(250); } } digitalWrite(red1, LOW); digitalWrite(red2, LOW); digitalWrite(yellow1, HIGH); digitalWrite(yellow2, HIGH); for(int i=0; i<6; i++) { if (checkDist() > maxCmAway) { blip(); } else { noTone(buzzer); delay(250); } } int checkDist() { // generate 10-microsecond pulse to TRIG pin digitalWrite(trig, HIGH); delayMicroseconds(10); digitalWrite(trig, LOW); // measure duration of pulse from ECHO pin duration_us = pulseIn(echo, HIGH); // calculate the distance distance_cm = 0.017 * duration_us; // print the value to Serial Monitor if (distance_cm < maxCmAway) { Serial.print("distance: "); Serial.print(distance_cm); Serial.println(" cm"); Serial.print("real: "); Serial.print(distance_cm); Serial.println(" cma"); } else { Serial.println("distance: 0 cm"); Serial.print("real: "); Serial.print(distance_cm); Serial.println(" cma"); } return distance_cm; } int blip() { tone(buzzer, 800); delay(50); tone(buzzer, 600); delay(100); tone(buzzer, 800); delay(100); noTone(buzzer); return 1; } The code that is messing up is after all the digitalWrites in the loop() function in the for loop where it says if (checkDist() > maxCmAway). The error is " 'checkDist' was not declared in this scope " I know what this error means, but I don't know any other way to fix it besides copying and pasting the if statement 5 times. When I look this up on Google, it just shows a bunch of things about the setup() and loop() functions. And the other thing I tried is putting the word 'global' before the function I am calling, but 'global' does not look like it is a keyword. Thanks!
You are missing a closing bracket for void loop() If you look at the other error messages above "Compilation error", you should see one that says error: expected '}' at end of input. If not, you can go to preferences and enable verbose out for compilation.
UPDATED: memory leak with WiFiClientSecure (Telegram) and WiFiClient (MQTT)
The title is quite self explanatory, just like the other question I have posted at Exception 28 thrown on ESP8266-01 when connected to Adafruit MQTT and Telegram Somebody might say this is the same question, but it's actually a follow-up of it, and I deem this as worthy of a standalone question, since it might help other people as well and it is not really covered anywhere else on the internet. I am also going to post the entirety of my code (just like I did on the previous question), although StackOverflow recommends posting the bare minimum to replicate the error, since I feel like it is needed in its entirety to fully replicate it. (Private data is replaced by the word PRIVATE) #include "UniversalTelegramBot.h" #include <ESP8266WiFi.h> #include <WiFiClientSecure.h> #include <Adafruit_MQTT.h> #include <Adafruit_MQTT_Client.h> #define BOTtoken "PRIVATE" #define fanPin 2 #define myChatId "PRIVATE" #define AIO_SERVER "io.adafruit.com" #define AIO_SERVERPORT 1883 #define AIO_USERNAME "PRIVATE" #define AIO_KEY "PRIVATE" char ssid[] = "PRIVATE"; char password[] = "PRIVATE"; bool fanState; unsigned long lastTimeBotRan = 0; unsigned long checkTime = 1000; int numNewMessages; unsigned long timerStartPoint = 0; bool timerStart; String chat_id; String text; int messagesNumber; String timerString; String Request; const unsigned long rst = 300000; boolean MQTT_connect(); WiFiClientSecure telegramClient; WiFiClient MQTTClient; UniversalTelegramBot bot(BOTtoken, telegramClient); Adafruit_MQTT_Client mqtt(&MQTTClient, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY); Adafruit_MQTT_Subscribe PRIVATE = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/PRIVATE"); void checkUpdates(int numNewMessages) { for (int i = 0; i < numNewMessages; i++) { chat_id = String(bot.messages[i].chat_id); text = bot.messages[i].text; String from_name = bot.messages[i].from_name; if (chat_id != myChatId) { bot.sendMessage(chat_id, "Unauthorized user, please refrain from texting this bot again.", ""); continue; } if (text == "/start") { bot.sendMessage(chat_id, "Welcome " + from_name + "!\n" "Control your fan remotely!\n\n" "/fanon: switch the fan ON\n" "/fanoff: switch the fan OFF\n" "/state: get the current state of the fan" "/timer15: run fan for 15 minutes" "/timer30: run fan for 30 minutes" "/timer60: run fan for 1 hour" "/timer: run fan for the amount of time you specify", "Markdown"); } if (text == "/fanon") { digitalWrite(fanPin, HIGH); Serial.println("Fan on"); fanState = true; bot.sendMessage(chat_id, "Your fan is ON", ""); } if (text == "/fanoff") { fanState = false; timerStart = false; digitalWrite(fanPin, LOW); Serial.println("Fan off"); bot.sendMessage(chat_id, "Your fan is OFF", ""); } if (text == "/state") { if (digitalRead(2) == HIGH) { bot.sendMessage(chat_id, "Your fan is ON", ""); } else { bot.sendMessage(chat_id, "Your fan is OFF", ""); } } if (text == "/timer15") { timerStartPoint = millis(); digitalWrite(fanPin, HIGH); timerStart = true; Serial.print("(/timer15) Fan on at "); Serial.println(timerStartPoint); bot.sendMessage(chat_id, "Your fan will run for 15 minutes", ""); launchTimer(15); } if (text == "/timer30") { digitalWrite(fanPin, HIGH); timerStart = true; timerStartPoint = millis(); Serial.print("(/timer30) Fan on at "); Serial.println(timerStartPoint); bot.sendMessage(chat_id, "Your fan will run for 30 minutes", ""); launchTimer(30); } if (text == "/timer60") { digitalWrite(fanPin, HIGH); timerStart = true; timerStartPoint = millis(); Serial.print("(/timer60) Fan on at "); Serial.println(timerStartPoint); bot.sendMessage(chat_id, "Your fan will run for 1 hour", ""); launchTimer(60); } if (text == "/timer") { messagesNumber = bot.last_message_received + 1; bot.sendMessage(chat_id, "How long do you want the fan to run for? (in minutes)", ""); Serial.println(messagesNumber); while (messagesNumber == (bot.last_message_received + 1)) { checkUpdates(bot.getUpdates(bot.last_message_received + 1)); timerString = bot.messages[i].text; yield(); } if (messagesNumber < (bot.last_message_received + 1)) { unsigned long timer = timerString.toInt(); Serial.println(timer); digitalWrite(fanPin, HIGH); timerStart = true; timerStartPoint = millis(); Serial.print("(/timer) Fan on at "); Serial.println(timerStartPoint); bot.sendMessage(chat_id, "Your fan will run for " + timerString + " minutes", ""); launchTimer(timer); } } text = ""; } } void launchTimer(unsigned long timeInMinutes) { unsigned long timeInMillis = timeInMinutes * 60 * 1000; while (timerStart) { checkUpdates(bot.getUpdates(bot.last_message_received + 1)); if (MQTT_connect()) { Adafruit_MQTT_Subscribe *subscription_name; while ((subscription_name = mqtt.readSubscription(4000))) { if (subscription_name == &PRIVATE) { Request = ((char *)PRIVATE.lastread); if (Request == "fanon") { digitalWrite(fanPin, HIGH); Serial.println("(Control panel) Fan on"); fanState = true; bot.sendMessage(myChatId, "Fan turned on through Control Panel", ""); } if (Request == "fanoff") { fanState = false; timerStart = false; Serial.println("(Control panel) Fan off"); digitalWrite(fanPin, LOW); bot.sendMessage(myChatId, "Fan turned off through Control Panel", ""); } if (Request == "timer15") { timerStartPoint = millis(); digitalWrite(fanPin, HIGH); timerStart = true; Serial.print("(CP /timer15) Fan on at "); Serial.println(timerStartPoint); bot.sendMessage(myChatId, "Fan turned on for 15 minutes through Control Panel", ""); launchTimer(15); } if (Request == "timer30") { digitalWrite(fanPin, HIGH); timerStart = true; timerStartPoint = millis(); Serial.print("(CP /timer30) Fan on at "); Serial.println(timerStartPoint); bot.sendMessage(myChatId, "Fan turned on for 30 minutes through Control Panel", ""); launchTimer(30); } if (Request == "timer60") { digitalWrite(fanPin, HIGH); timerStart = true; timerStartPoint = millis(); Serial.print("(CP /timer60) Fan on at "); Serial.println(timerStartPoint); bot.sendMessage(myChatId, "Fan turned on for 1 hour through Control Panel", ""); launchTimer(60); } } } } if (millis() - timerStartPoint > timeInMillis) { digitalWrite(fanPin, LOW); timerStart = false; Serial.print("Timer run out at "); Serial.println(millis()); bot.sendMessage(myChatId, "Fan turned off because timer ran out", ""); } yield(); } } boolean MQTT_connect() { int8_t ret; if (mqtt.connected()) { return true; } uint8_t retries = 3; while ((ret = mqtt.connect()) != 0) { mqtt.disconnect(); delay(2000); retries--; if (retries == 0) { return false; } } return true; } void setup() { Serial.begin(115200); telegramClient.setInsecure(); WiFi.mode(WIFI_STA); WiFi.disconnect(); delay(100); Serial.print("Connecting Wifi: "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println(""); Serial.println("WiFi connected"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); pinMode(fanPin, OUTPUT); delay(10); digitalWrite(fanPin, LOW); Request = ""; mqtt.subscribe(&PRIVATE); if (MQTT_connect()) { Serial.println("mqtt connected"); } else { Serial.println("mqtt connection failed"); } } void loop() { if (millis() - lastTimeBotRan > checkTime) { numNewMessages = bot.getUpdates(bot.last_message_received + 1); while (numNewMessages) { checkUpdates(numNewMessages); numNewMessages = bot.getUpdates(bot.last_message_received + 1); } lastTimeBotRan = millis(); } delay(1000); if (MQTT_connect()) { Adafruit_MQTT_Subscribe *subscription_name; while ((subscription_name = mqtt.readSubscription(4000))) { if (subscription_name == &PRIVATE) { Request = ((char *)PRIVATE.lastread); if (Request == "fanon") { digitalWrite(fanPin, HIGH); Serial.println("(Control panel) Fan on"); fanState = true; bot.sendMessage(myChatId, "Fan turned on through Control Panel", ""); } if (Request == "fanoff") { fanState = false; timerStart = false; Serial.println("(Control panel) Fan off"); digitalWrite(fanPin, LOW); bot.sendMessage(myChatId, "Fan turned off through Control Panel", ""); } if (Request == "timer15") { timerStartPoint = millis(); digitalWrite(fanPin, HIGH); timerStart = true; Serial.print("(CP /timer15) Fan on at "); Serial.println(timerStartPoint); bot.sendMessage(myChatId, "Fan turned on for 15 minutes through Control Panel", ""); launchTimer(15); } if (Request == "timer30") { digitalWrite(fanPin, HIGH); timerStart = true; timerStartPoint = millis(); Serial.print("(CP /timer30) Fan on at "); Serial.println(timerStartPoint); bot.sendMessage(myChatId, "Fan turned on for 30 minutes through Control Panel", ""); launchTimer(30); } if (Request == "timer60") { digitalWrite(fanPin, HIGH); timerStart = true; timerStartPoint = millis(); Serial.print("(CP /timer60) Fan on at "); Serial.println(timerStartPoint); bot.sendMessage(myChatId, "Fan turned on for 1 hour through Control Panel", ""); launchTimer(60); } } } } if (!mqtt.ping()) { mqtt.disconnect(); } } Now, here is the issue: I would like to instantiate both WiFiClient (to connect to Adafruit MQTT) and WiFiClientSecure (to connect to my Telegram bot) without ending up with a crash, followed by an Exception 28 stacktrace (of which I have already posted a "normal" and decoded version in the other question at the link). I know for a fact, after hours of research, that I cannot instantiate two instances of WiFiClientSecure because it would exceed the available heap on an ESP01, and I also know that WiFiClient alone, or WiFiClientSecure alone, never happen to throw said exception. Nothing that I have found says that WiFiClient and WiFiClientSecure cannot be used together, but maybe I am missing something. Therefore my question is: is it possible to use both WiFiClient and WiFiClientSecure, for two different purposes (respectively, MQTT and Telegram), in the same code? I look forward to reading any piece of advice, since I am currently at a loss for ideas. Thanks in advance to everybody who will help. EDIT: for anybody who is interested, here are my latest findings: Overclocking the CPU of the ESP01 from 80 MHz to 160 MHz helps mitigate the crashes, in fact it only crashed once over the course of 8 hours. Going from a crash every 30 minutes to 8 hours sure is a step forward; I found out (thanks to romkey for the advice), that it WiFiClient and WiFiClientSecure are NOT incompatible, the problem was caused by the free heap. Freeing up the heap, by removing Strings and turning them to char arrays, got the program not to crash over the course of 13 whole hours. I might test this further and leave it on for even more than 24 hours, to see if it is really solved. In case, I will update. UPDATE: found the problem and changed the title. The problem lies entirely in heap use of both the libraries. Both the libraries use an enormous amount of heap space and after a while it runs out and causes exception 28, because, as far as I know, the ESP tries to read from the wrong part of its memory, causing it to crash. I will attach the Serial output of the heap throughout just 3 minutes: 41552 19448 20008 20120 20312 20200 20120 20120 20120 20312 20120 20120 20120 20312 20312 20312 20312 20312 20312 20504 20312 20312 19640 As you can see, the first instance has the heap show more than 40k, which is normal, as 51k-ish is the maximum. Then it jumps down to 20000, and later runs out, even though the ESP reclaims its own memory after a couple of minutes.
I also do use both WiFiClient and WiFiClientSecure in my ESP8266 multisensors checking and publishing project. And while my WifiClient is up all the time (for MQTT and ThingSpeak), secured connection (needed for publishing to GoogleSheets more rarely - every 30 minutes) I decided to put into the function. The whole project code is too large (there's 5570 lines), so here's a part of it with comments introducing heap usage: // heap size before call of the function: 37112 int SendGSCRPT() { showHeap(); // 35312 WiFiClientSecure GoogleClient; showHeap(); // 27512 GoogleClient.setInsecure(); if (!GoogleClient.connect("script.google.com", 443)) { GoogleClient.stop(); return 0; } showHeap(); // 9840 !!! char sGog[200]; snprintf(sGog, sizeof(sGog), "GET %s HTTP/1.1\r\nHost: script.google.com\r\nUser-Agent: PRIVATE\r\nConnection: close\r\n\r\n", "PRIVATE"); GoogleClient.print(sGog); Serial.println("request sent!"); int res = 1; GoogleClient.stop(); showHeap(); // 30104 return res; } // heap size after function releases all the memory taken: 37112 again !!!
Can I send tone() function wirelessly?
I have a simple RPM Simulator (opensource) that generates values through the tone() function. I need to send the RPM wirelessly through an nrf24l01 to a second Arduino that uses the RPM as a shiftlight, both come from chippernut. The tone() function only sends to the pin, trying to read the values did not work. How can i get the value of x (RPM) after it leaves the tone function? I have tried reading it through analogRead, digitalRead, BitRead, tried printing the value of x which stays constant, to no avail, and it updates very slowly if it reads the output pin. This is the code: float RPM_MIN = 2500; float RPM_MAX = 8000; int Accel_Rate = 20; float pulses_per_rev = 2.0; // make sure to keep the decimal boolean accel = false; float x; long previousMillis = 0; unsigned long currentMillis=0; //float RPM_PRINT; //my addition to get a value to print void setup() { Serial.begin(57600); pinMode(5, OUTPUT); RPM_MIN = (RPM_MIN / 60); RPM_MAX = (RPM_MAX / 60); x = RPM_MIN; } void loop() { while (accel==false){ currentMillis = millis(); if(currentMillis - previousMillis > Accel_Rate) { previousMillis = currentMillis; x++; tone(5,x*pulses_per_rev); if (x>RPM_MAX){accel=true;} } } while (accel==true){ currentMillis = millis(); if(currentMillis - previousMillis > Accel_Rate) { previousMillis = currentMillis; x--; tone(5,x*pulses_per_rev); if (x<RPM_MIN){accel=false;} } } //RPM_PRINT = x*pulses_per_rev; //RPM_PRINT = digitalRead(5); //RPM_PRINT = analogRead(5); //Serial.println(RPM_PRINT); } Expected Result is a Value between 2000-8000 that is constantly changing actual result is 1/0 or 81,33 or 4,1 or 900-980 updating once every few seconds. How can I solve?
charging Timer doesn't quite work?
I'm writing a game where I want the character to jump after holding the spacebar to charge their jump up for a bit and then the charge will get added into the jump afterwards. However, the code that I currently have going only works around 50% of the time, and will almost indefinitely not work if the player is holding a directional movement button down at the same time. function greenTimerHandler(e:TimerEvent){ if(spacePressed&&downBumping){ charge += 3; if(charge >= 50){ charge = 50; } } else if(!spacePressed&& downBumping) { greenSlimeJump(charge); greenSlimeTimer.stop(); } } //And the jump function function greenSlimeJump(greenCharge){ ySpeed = greenCharge * -1.5 slimeAmt -= Math.floor(greenCharge * 0.25); charge = 0; } the downBumping is just a boolean collision value based on a hitTestPoint for the bottom of the player... Is there any way that I can make it so that it actually runs the jump function more than it currently does? It will even keep the charge value for the next time it tries to jump and the slimeAmt value is never subtracted because the code just seems to completely skip the green jump function altogether. Heres the downBumping code: if(back.collisions.hitTestPoint(player.x + downBumpPoint.x, player.y + downBumpPoint.y, true)){ downBumping = true; } else { downBumping = false; } and heres the timer/ space pressed: if(e.keyCode == 32 && slimeAction){ spacePressed = true; if(slimeType == 1 && downBumping){ greenSlimeTimer.start(); } }
Which algorithms are available to solve Tic Tac Toe?
What algorithms are available to solve Tic Tac Toe? Especially with board size 4 * 4 or bigger instead of 3 * 3? I tried 4 * 4 with Minimax & alpha-beta pruning but the pc seems to hang and throws exceptions on stack overflow. I saw these source code written in javascript but I don't know which algorithm it uses, could anyone clarify it for me? http://js-x.com/page/javascripts__example.html?view=153
try to do cut-offs in certain depth... i don't think you need more than 4 or 5 of depth to make a perfect move. (java for 3*3 one-dim board with depth): int minimax(int turn, int depth) { // turn(side to move) is 1 or -1 int val = -turn; // worst value for that turn int result = NULVAL; if (wins()) return turn; // evaluate board (board is a field) if (depth == 0) return DRAW; for (int i = 0; i < 9; i++) { if (board[i] == EMPTY) { board[i] = turn; // make move result = minimax(-turn, depth - 1); board[i] = EMPTY; // delete move if (result == turn) return turn; // sees win if (result == DRAW) val = result; } } // if result keeps NULVAL: couldn't make a move (board is full) if (result == NULVAL) return DRAW; return val; }