So I have come to a problem where I can not get out of a loop after I'm in it. My project is to have two functions, one for manual and another for automatic which will run forever, but I want that when I am in automatic, I will be able to get out by clicking the manual button on my phone. I don't know if that makes sense, but I really need help.
//Program to control LED (ON/OFF) from ESP32 using Serial Bluetooth
#include <Arduino.h>
#include <BluetoothSerial.h> //Header File for Serial Bluetooth, will be added by default into Arduino
BluetoothSerial ESP_BT; //Object for Bluetooth
int incoming;
int yellow_led = 13;
void setup() {
Serial.begin(9600); //Start Serial monitor in 9600
ESP_BT.begin("ESP32_LED_Control"); //Name of your Bluetooth Signal
Serial.println("Bluetooth Device is Ready to Pair");
pinMode (yellow_led, OUTPUT);//Specify that LED pin is output
}
void automatic()
{
while (incoming != 51)
{
digitalWrite(yellow_led, HIGH);
ESP_BT.println("LED turned ON");
delay(1000);
digitalWrite(yellow_led, LOW);
ESP_BT.println("LED turned OFF");
delay(1000);
}
}
void manual()
{
if (incoming == 49)
{
digitalWrite(yellow_led, HIGH);
ESP_BT.println("LED turned ON");
}
else if(incoming == 48)
{
digitalWrite(yellow_led, LOW);
ESP_BT.println("LED turned OFF");
}
}
void loop() {
if (ESP_BT.available()) //Check if we receive anything from Bluetooth
{
incoming = ESP_BT.read(); //Read what we recevive
Serial.print("Received:"); Serial.println(incoming);
if (incoming == 51) //#3
{
ESP_BT.println("In Manual Mode");
manual();
}
else if (incoming == 52) //#4
{
ESP_BT.println("In Automatic Mode");
automatic();
}
}
delay(20);
}
The while loop in the automatic function is unnecessary. You're already looping infinitely within loop() so that should be enough. Adding another loop, even though at first may seem like it will break, turns out to be an infinite loop. I'll get to that in a second.
So all you need to do is get rid of the while loop and it should work. However, this works only if you are guaranteed to have an incoming value for each time in the loop, which is what seems like from your code.
Another problem I see here is that if you enter say manual(), there is nothing really that changes the value of incoming, you're bound to have 51 as you're reusing the previous value and nothing no desired code path will be triggered.
Same also applies to automatic(), I hope you can see how that loop becomes infinite because of this.
So you also need something on the following lines.
void manual()
{
if (!ESP_BT.available())
return;
incoming = ESP_BT.read();
if (incoming == 49)
{
digitalWrite(yellow_led, HIGH);
ESP_BT.println("LED turned ON");
}
else if(incoming == 48)
{
digitalWrite(yellow_led, LOW);
ESP_BT.println("LED turned OFF");
}
}
Lastly, need help lol, please and thank you may not be descriptive enough for anybody to help with your problem, please go through, how to ask a good question for the next time you're posting.
Related
So, me and my friend were assigned a task:
When 'A' is given as input to serial monitor, the led must blink once.
When 'B' is given a input, the led must blink continuously.
And we successfully finished the task using the code attached.
char a;
void setup()
{
pinMode(13, OUTPUT);
Serial.begin(9600);
}
void loop()
{
if(Serial.available())
{
a= Serial.read();
if(a == 'A')
{
digitalWrite(13, HIGH);
delay(1000); // Wait for 1000 millisecond(s)
digitalWrite(13, LOW);
delay(1000); // Wait for 1000 millisecond(s)
}
}
if(a=='B')
{
digitalWrite(13,HIGH);
delay(500);
digitalWrite(13,LOW);
delay(500);
}
}
But then we have a doubt to be clarified.
Both the conditions are given inside loop , but the one inside the if(Serial.available()) condition makes the led blink once while the condition outside the if(Serial.available()) makes the led blink continuously. Why??
Note that the code is the same for if(a=='A') and if(a=='B').
I really need an explanation for this question.
if(a=='B') will be executed continuously since it stays true until new input is received and it is in loop that is being called repeatedly.
if(a == 'A') is only evaluated once after a new character is received. If there is no character it is never checked again.
loop is called repeatedly regardless of whether there is new input available. variable a have global scope so it will not change between calls. It will contain the last received input.
In your code, the character held by a is only changed when Serial.available() returns a non-zero value, which only happens when you press a key. In the API Reference, we can see that Serial.available() actually returns the number of characters available, so the recommended usage is if (Serial.available() > 0).
To get the intended behavior (if I've understood your problem correctly) you should move the if 'B' part to within the if available() part. Something like this
void loop()
{
if (Serial.available() > 0)
{
a = Serial.read();
if (a == 'A')
{
digitalWrite(13, HIGH);
delay(1000); // Wait for 1000 millisecond(s)
digitalWrite(13, LOW);
delay(1000); // Wait for 1000 millisecond(s)
}
else if (a == 'B')
{
digitalWrite(13,HIGH);
delay(500);
digitalWrite(13,LOW);
delay(500);
}
}
}
When you enter something in the Serial Monitor and press enter, then Serial.available() returns a true, Then you read the buffer, in this case it is either A or B, and then you assign the variable a to the character that is read.
You should note that Serial.available() returns true only when you press enter, so when yo press enter to submit your input, the code under the if condition is executed, and that's why the led blinks only once, because after that Serial.available() returns false.
Since you are assigned the variable c under the Serial.available() condition, it remains whatever is read in the serial monitor. that's why when you enter B, c == 'B' is always true and the led blinks continuously.
I am trying to control a LED from Thingspeak server by using the GSM module.
The data received is successfully being printed on serial monitor(which is '1' as last updated) but when I am trying to assign that data to a variable so as to control the inbuilt LED of Arduino, nothing happens.
#include <SoftwareSerial.h>
SoftwareSerial SIM900A(10, 11);
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
SIM900A.begin(9600);
Serial.begin(9600);
while (!Serial)
;
Serial.println("Arduino is ready");
SIM900A.begin(9600);
Serial.println("SIM900A started at 9600");
delay(1000);
Serial.println("Setup Complete");
}
void loop()
{
SIM900A.println("AT");
delay(1000);
ShowSerialData();
SIM900A.println("AT+CIPSHUT");
delay(2000);
ShowSerialData();
SIM900A.println("AT+CIPMUX=0");
delay(2000);
ShowSerialData();
SIM900A.println("AT+CGATT=1");
delay(5000);
SIM900A.println("AT+CSTT=\"INTERNET\",\"\",\"\"");
delay(4000);
SIM900A.println("AT+CIICR");
delay(3000);
ShowSerialData();
SIM900A.println("AT+CIFSR");
delay(5000);
ShowSerialData();
SIM900A.println("AT+CIPSTART=\"TCP\",\"184.106.153.149\",\"80\"");
delay(4000);
ShowSerialData();
SIM900A.println("AT+CIPSEND");
delay(4000);
SIM900A.print("GET /channels/798173/fields/1/last");
SIM900A.print("\r\n\x1A");
ShowSerialData();
char led = SIM900A.read();
Serial.print(led);
if (led == '1')
{
digitalWrite(LED_BUILTIN, HIGH);
}
else if (led == '0')
{
digitalWrite(LED_BUILTIN, LOW);
}
delay(8000);
}
void ShowSerialData()
{
while (SIM900A.available() != 0)
Serial.print(char(SIM900A.read()));
}
Last portion of the output from the serial monitor:
CONNECT OK
AT+CIPSEND
> ⸮GET /channels/798173/fields/1/last
SEND OK
1
As pointed out by #Saurabh P Bhandari, you cannot read the same data from the serial twice, thus you'd need to read the data in a variable in the first place if you wish to use it.
String getSerialData(){
String buffer="";
while (SIM900A.available() ){
char c = SIM900A.read();
buffer+=c;
}
return buffer;
}
Then you can use String led = getSerialData() to populate led with the buffer.
Here, you need to beware that the function getSerialData would return anything present on the buffer and would look something like:
GET /channels/798173/fields/1/last
SEND
HTTP RESPONSE
It appears that you're only interested in HTTP RESPONSE, thus you can update your conditionals to be
if(led.endsWith("1"))
...
else if(led.endsWith("0"))
From what I have understood so far, in this snippet
SIM900A.print("GET /channels/798173/fields/1/last");
SIM900A.print("\r\n\x1A");
ShowSerialData();
ShowSerialData() is printing the output which is '1'. Then immediately your are reading data into the variable led. Since, the actual data received is being printed already from ShowSerialData(), the next time you call SIM900A.read() will return either nothing or next set of data being sent by your module.
You are likely getting rate limited because you are hitting ThingSpeak servers too frequently. You can only update a channel once every 15s with a free account. Obviously, it makes no sense to ask for a value faster than it can be updated, i.e., once every 15s with a free account.
Consider putting some required delays in your code to ensure your device is not blacklisted for abuse of terms.
I have an Arduino UNO R3 that reads a specific value from my Web Page.
I have an LED attached to the PIN 13 & GND of my Arduino.
When the Arduino reads 1 from my Web Page, it should turn the LED ON. When it reads 0, it should turn it off.
Following is the code for that:
#include "SIM900.h"
#include <SoftwareSerial.h>
#include "inetGSM.h"
InetGSM inet;
#define ledPin 13
char msg[165];
char store[2];
char a;
char b;
char* disp;
boolean started=false;
void setup()
{
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
//Serial connection.
Serial.begin(9600);
Serial.println("GSM Shield testing.");
//Start configuration of shield with baudrate.
//For http uses is raccomanded to use 4800 or slower.
if (gsm.begin(2400)) {
Serial.println("\nstatus=READY");
started=true;
} else Serial.println("\nstatus=IDLE");
if(started)
{
//GPRS attach, put in order APN, username and password.
//If no needed auth let them blank.
if (inet.attachGPRS("TATA.DOCOMO.INTERNET", "", ""))
Serial.println("status=ATTACHED");
else Serial.println("status=ERROR");
delay(1000);
//TCP Client GET, send a GET request to the server and
//save the reply.
//Print the results.
}
}
void loop()
{
inet.httpGET("www.boat.esy.es", 80, "/retrieve.php", msg, 165);
disp = strstr(msg,"\r\n\r\n");
disp = disp+4;
a = disp[0];
b = disp[1];
Serial.println(b);
if(b=='1')
{
digitalWrite(ledPin, HIGH);
}
if(b=='0');
{
digitalWrite(ledPin, LOW);
}
}
Problem here is, when I disable the digitalWrite(ledPin,LOW), that is when I comment it out, the LED turns on & stays that way.
But the moment I enable it & load the code on my Arduino, it won't even turn on.
I'm wondering if it's a logical error or something else. Because the turning on & off of the LED depends completely on the conditions being satisfied. And for now, my Web Page returns only 1, hence the LED should stay on. But when I include both digitalWrite(ledPin, HIGH) and digitalWrite(ledPin, LOW) in the same code and run it, it doesn't work. I can see the Serial printing out the messages associated with the LED ON, but I don't see the LED turning ON.
Thank You for your time!!
First of all you have a semicolon that I think should not be in your second if-statement?
if(b=='0'); <--
{
digitalWrite(ledPin, LOW);
}
Start by trying to remove that and see if there is a difference.
I am working on simple project, arduino relay controled via mobile phone. I am trying to create a loop, which makes the relay switch between HIGH and LOW only with sending 1 to pin 7. I tried multiple variations but it never works, I am unable to find a mistake. Here´s the code, thanks in advance.`
int relay = 7;
int prev; //previous value
int val; //actual value
void setup()
{
pinMode(relay, OUTPUT);
Serial.begin(9600);
}
void loop()
{
if(Serial.available()>0) //send data when recieved
{
val = Serial.read(); //read value
}
if (val == '1')
{
if (prev == '1')
{
digitalWrite(relay, LOW);
prev=val;
}
else
{
digitalWrite(relay, HIGH);
prev=val;
}
}
else if (val == '0');
{
if (prev == '0')
{
digitalWrite(relay, HIGH);
prev=val;
}
else
{
digitalWrite(relay, LOW);
prev=val;
}
}
}
Current code attempts to read the serial port, and if has something to read sets it into variable val.
In the case of where it has read a value, but doesnt have another value, val is still set to the same value as before.
So it then probally starts toggling the high/low transition as fast as the loop can go.
Instead, you could move the logic code to within the if(Serial.available()>0) statement so that it only gets called when the key is pressed.
I'm wondering if there are any reasons not to loop inside the loop() function.
To illustrate my question, let's say I want to make a LED blink a thousand times.
Here are two ways to do it with the Arduino.
In the following one, I make sure not to "lock" the loop() function :
const int PIN_LED = 2;
const int BLINKING_LIMIT = 1000;
int blinkCount = 0;
void setup() {
// initialize serial:
pinMode(PIN_LED, OUTPUT);
}
// Here, I make sure not to "lock" the loop() function
void loop() {
blinkCount++;
if (blinkCount < BLINKING_LIMIT) {
digitalWrite(PIN_LED, HIGH);
delay(200);
digitalWrite(PIN_LED, LOW);
delay(200);
}
}
In the second one, there is a long loop (which could last even longer) in the loop() function. The Arduino is "locked" inside the for loop :
// Here, I make sure not to "lock" the loop() function
void loop() {
for (int i = 0; i < BLINKING_LIMIT; i++) {
digitalWrite(PIN_LED, HIGH);
delay(200);
digitalWrite(PIN_LED, LOW);
delay(200);
}
}
What is the best practice ? Should I care not to "lock" the loop() function, or can I just don't care ? Would an infinite loop inside the loop() function be acceptable ?
loop() and setup() are just 2 functions defined for Arduino. It will be compiled with the main code for your board.
The code of the Arduino board will be something like:
void main()
{
setup();
for(;;) {
loop();
}
}
And you just have the possibility to write the code for setup and loop.
It is like #Piglet said. It is your code and you can write it how you want.
You can not "lock" the loop, since it is not an interrupt and there is no OperatingSystem behind your loop.
Once the loop is terminated, it is called automatically again. So you can also write:
void loop()
{
for(;;) {
// your code
}
}
If you like it, so the loop will never terminate and you can write it like on a 8051 processor ;)
Just don't care. Nesting loops is super common practice in programming. Many problems cannot be solved efficiently without it.
It is your program. You may stay within a loop as long as you wish. Your Arduino won't timeout or anything.
Personally, I would use the second code. It's precise and short. Who wants to make the code long and boring. Loop will stop when you want to stop just add a condition, so don't care until and unless your code works perfectly.
If you just want to make a LED blink, it's not important but if you want to add something to your code, the behavior will be different:
void loop() {
blinkCount++;
if (blinkCount < BLINKING_LIMIT) {
digitalWrite(PIN_LED, HIGH);
delay(200);
digitalWrite(PIN_LED, LOW);
delay(200);
}
//ANYTHING ELSE
}
In this part, your LED will blink and the rest of your code will be executed in each 400ms about.
void loop() {
for (int i = 0; i < BLINKING_LIMIT; i++) {
digitalWrite(PIN_LED, HIGH);
delay(200);
digitalWrite(PIN_LED, LOW);
delay(200);
}
//ANYTHING ELSE
}
In this part, your LED will blink "BLINKING_LIMIT" times and only after, the rest of your code will be executed.
Just be careful if you want to add something.