I’m pretty new to Arduino so pardon my lack of knowledge. I am in the process of building a temp alarm that will send me an SMS when the temp falls below a certain temp. That part is working however I am going to use a smaller portion of code here to work through my next scenario. Now I’m trying to build the ability to send a text to the Arduino with a message like “Tempsetpoint 50” and have it set a variable to 50 that will be used in the other code that I have to alert on any temp below 50. I am building it all into 1 major sketch but building smaller sketch's for testing portions as I go. Below is the start of some code that I have worked up that turns an led on if an SMS with a1 is received and turns the led off if a0 is received.
First problem is how do I replaced ‘a’ with a string of characters like “Tempsetpoint” or maybe I can make it 1 step easier and leave ‘a’ as a single integer and then just have 2 digits for the temp setpoint after ‘a’ set the variables value? Can anyone give me some advice on how to change it from a single digit to a string of 2 digits for the second value and then set a variable?
I am using an Arduino Uno with a Geeetech GSM shield.
#include <SoftwareSerial.h>
SoftwareSerial mySerial(7, 8);
char inchar = 0;
int led1 = 4;
void setup()
{
pinMode(led1, OUTPUT);
Serial.begin(19200); // for serial monitor
mySerial.begin(19200); // for GSM shield
SIM900power(); // turn on shield
delay(10000); // give time to log on to network.
mySerial.print("AT+CMGF=1\r"); // set SMS mode to text
delay(100);
mySerial.print("AT+CNMI=2,2,0,0,0\r");
// blurt out contents of new SMS upon receipt to the GSM shield's serial out
delay(100);
}
void loop()
{
//If a character comes in from the mySerialular module...
if (mySerial.available() > 0)
{
delay(10);
inchar = mySerial.read();
if (inchar == 'a')
{
delay(10);
inchar = mySerial.read();
if (inchar == '0')
{
digitalWrite(led1, LOW);
}
else if (inchar == '1')
{
digitalWrite(led1, HIGH);
}
delay(10);
}
}
}
void SIM900power()
// Powers on the GSM card
{
pinMode(9, OUTPUT);
digitalWrite(9, LOW);
delay(1000);
digitalWrite(9, HIGH);
delay(2000);
digitalWrite(9, LOW);
delay(3000);
}
The way forward would probably to insert the individual characters your receive into a null terminated character array (string), then compare with a known value. Don't be tempted to use the String class, it can cause problems with fragmentation of memory (amongst other things).
Alternatively, save the SMS to memory instead of 'blurting it out', then you can access the whole message in one go.
First problem is how do I replaced 'a' with a string of characters like "Tempsetpoint"
You capture the characters into a string of characters that can be evaluated. If the SMS message has some end of text marker, then you probably could use a character capture setup like below.
//zoomkat 3-5-12 simple delimited ',' string
//from serial port input (via serial monitor)
//and print result out serial port
String readString;
void setup() {
Serial.begin(9600);
Serial.println("serial delimit test 1.0"); // so I can keep track of what is loaded
}
void loop() {
//expect a string like wer,qwe rty,123 456,hyre kjhg,
//or like hello world,who are you?,bye!,
if (Serial.available()) {
char c = Serial.read(); //gets one byte from serial buffer
if (c == ',') {
//do stuff
Serial.println(readString); //prints string to serial port out
readString=""; //clears variable for new input
}
else {
readString += c; //makes the string readString
}
}
}
Zoomkat, I'll just be sending the SMS messages to the Arduino from my cell so they can be formatted anyway.
With the code that I posted above. Is their any easy way to get it so it will accept an SMS something like a50 and have it run that section of code if a comes in and then set a variable if 50 comes in. Even if I had to write if statements for each value after a that I want to expect for 50 such as 50, 55, 60, 65, 70, etc.
Something something like:
if (inchar == 'a')
{
delay(10);
inchar = mySerial.read();
if (inchar == '50')
{
variable = 50
}
if (inchar == '55')
{
variable = 55
}
if (inchar == '60')
{
variable = 60
}
I get an error with having 2 characters in the if (inchar == '60') even if I change it to if (inchar == "60").
SMS something like a50 and have it run that section of code if a comes in and then set a variable if 50 comes in.
Below is some servo control code. The data packet consist of a numeric position value, a servo identifier, and an end of packet marker. This may be similar to what you want to do.
//zoomkat 11-22-12 simple delimited ',' string parse
//from serial port input (via serial monitor)
//and print result out serial port
//multi servos added
// Powering a servo from the arduino usually *DOES NOT WORK*.
String readString;
#include <Servo.h>
Servo myservoa, myservob, myservoc, myservod; // create servo object to control a servo
void setup() {
Serial.begin(9600);
//myservoa.writeMicroseconds(1500); //set initial servo position if desired
myservoa.attach(6); //the pin for the servoa control
myservob.attach(7); //the pin for the servob control
myservoc.attach(8); //the pin for the servoc control
myservod.attach(9); //the pin for the servod control
Serial.println("multi-servo-delimit-test-dual-input-11-22-12"); // so I can keep track of what is loaded
}
void loop() {
//expect single strings like 700a, or 1500c, or 2000d,
//or like 30c, or 90a, or 180d,
//or combined like 30c,180b,70a,120d,
if (Serial.available()) {
char c = Serial.read(); //gets one byte from serial buffer
if (c == ',') {
if (readString.length() >1) {
Serial.println(readString); //prints string to serial port out
int n = readString.toInt(); //convert readString into a number
// auto select appropriate value, copied from someone elses code.
if(n >= 500)
{
Serial.print("writing Microseconds: ");
Serial.println(n);
if(readString.indexOf('a') >0) myservoa.writeMicroseconds(n);
if(readString.indexOf('b') >0) myservob.writeMicroseconds(n);
if(readString.indexOf('c') >0) myservoc.writeMicroseconds(n);
if(readString.indexOf('d') >0) myservod.writeMicroseconds(n);
}
else
{
Serial.print("writing Angle: ");
Serial.println(n);
if(readString.indexOf('a') >0) myservoa.write(n);
if(readString.indexOf('b') >0) myservob.write(n);
if(readString.indexOf('c') >0) myservoc.write(n);
if(readString.indexOf('d') >0) myservod.write(n);
}
readString=""; //clears variable for new input
}
}
else {
readString += c; //makes the string readString
}
}
}
A simple example demonstrating the capture and compare concept.
// zoomkat 8-6-10 serial I/O string test
// type on or off in serial monitor. then send or enter
// for IDE 0019 and later
int ledPin = 13;
String readString;
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
Serial.println("serial on/off test 0021"); // so I can keep track
}
void loop() {
while (Serial.available()) {
delay(3);
char c = Serial.read();
readString += c;
}
if (readString.length() >0) {
Serial.println(readString);
if (readString == "on")
{
digitalWrite(ledPin, HIGH);
Serial.println("LED ON");
}
if (readString == "off")
{
digitalWrite(ledPin, LOW);
Serial.println("LED OFF");
}
readString="";
}
}
I'm now trying to use the string to check if a GSM shield with a SIM900 on it is powered up and responding to AT commands. I'm wanting to send the command AT to the shield and have it return OK and then turn an LED on if it receives OK else turn on a different LED if it doesn't receive OK. Long term the goal would be to send the commands to the GSM shield to power up if an OK isn't returned.
Using the sketch below if I send a "p" through the serial monitor it then runs the GSMCheckpower function and send AT to the GSM card and returns an OK to the serial monitor. When it receives OK back on serial it isn't acting on the OK that it receives and instead completes the else statement and turns on ledPin2 because OK wasn't meet. Any idea what I am missing so it catch's the OK and turn on the ledPin when the GSM shield is on instead of always using the else statement?
#include <SoftwareSerial.h>
#include <String.h>
SoftwareSerial mySerial(52, 53);
String readString;
int ledPin = 41; //Green LED
int ledPin2 = 43; //Red LED
void setup()
{
pinMode(ledPin, OUTPUT);
pinMode(ledPin2, OUTPUT);
mySerial.begin(19200); // the GPRS baud rate
Serial.begin(19200); // the GPRS baud rate
delay(500);
mySerial.print("AT+CMGF=1\r"); //Because we want to recieve the SMS in text mode
}
void loop()
{
if (Serial.available())
switch (Serial.read())
{
case 'p':
GSMCheckpower();
break;
}
if (mySerial.available())
Serial.write(mySerial.read());
}
//--------------Check Power Status---------------
void GSMCheckpower()
{
mySerial.print("AT"); //AT Status
delay(100);
mySerial.println();
while (mySerial.available())
{
delay(3);
char c = mySerial.read();
readString += c;
}
if (readString.length() > 0)
{
mySerial.println(readString);
if (readString == "OK")
{
digitalWrite(ledPin, HIGH); //Green LED
delay(3000);
digitalWrite(ledPin, HIGH); //Green LED
}
else
{
digitalWrite(ledPin2, HIGH); //Red LED
delay(3000);
digitalWrite(ledPin2, LOW); //Red LED
}
readString = "";
}
}
Paul I removed mySerial.println(readString); from the sketch however it didnt have any effect on the correction of the sketch.
Below is the working sketch. I change the == to = in "if (readString = "OK")". I also moved an } up before the else statement so the else statement would run correctly. The Green LED now turns on if the GSM Shield is on and responding the AT commands and the Red LED turns on if it the shield is off or doesn't respond.
#include <SoftwareSerial.h>
#include <String.h>
SoftwareSerial mySerial(52, 53);
String readString;
int ledPin = 41; //Green LED
int ledPin2 = 43; //Red LED
void setup()
{
pinMode(ledPin, OUTPUT);
pinMode(ledPin2, OUTPUT);
mySerial.begin(19200); // the GPRS baud rate
Serial.begin(19200); // the GPRS baud rate
delay(500);
mySerial.print("AT+CMGF=1\r"); //Because we want to receive the SMS in text mode
}
void loop()
{
if (Serial.available())
switch (Serial.read())
{
case 'p':
GSMCheckpower();
break;
}
if (mySerial.available())
Serial.write(mySerial.read());
}
//--------------Check Power Status---------------
void GSMCheckpower()
{
mySerial.print("AT"); //AT Status
delay(100);
mySerial.println();
while (mySerial.available())
{
delay(3);
char c = mySerial.read();
readString += c;
}
if (readString.length() > 0)
{
if (readString = "OK")
{
digitalWrite(ledPin, HIGH); //Green LED
delay(3000);
digitalWrite(ledPin, LOW); //Green LED
}
}
else
{
digitalWrite(ledPin2, HIGH); //Red LED
delay(3000);
digitalWrite(ledPin2, LOW); //Red LED
}
readString = "";
}
PaulS:
Why do you need to use SoftwareSerial on a device with 4 hardware serial ports?
The reason for Software Serial is I'm going to be using the end result on my UNO. I'm just testing this sketch on my Mega because I'm testing another sketch on my UNO at the time being. Post #1 was on the UNO.
PaulS:
String readString;
You do NOT need to piss away resources on the String class.
Can bark but offer no alternatives? We're on the forum for help not just to be criticized for our lack of knowledge. I have done a lot of searching for my own fixes and only turn to opening a new thread if I cant find what I need.
PaulS:
while (mySerial.available())
{
delay(3);
char c = mySerial.read();
readString += c;
}
The delay() is the worst possible way to read serial data. ASSuming that 3 milliseconds is enough is foolish.
Your right 3ms isn't time to do anything. I'm using zoomkat's sketch in post #9 as the base.
By the way thanks zoomkat. Thanks for the input and offering up examples and alternatives to a guy(ME) that's not a programmer by trait and has only been learning Arduino and C++ for just over 2 months.
I'm sure after I have been doing this for a while I'll also look back at the sketch's I have built so far and think what was I thinking. But having only been working and learning this stuff for just over 2 months and having a combined sketch that sends SMS messages if my house gets below a certain temp or motion is detected or power goes out(Yes I built a battery backup into this thing) and to receive SMS messages that can turn the temp detection, power detection or motion detection portions of the sketch on or off, and also the ability to send an SMS to the device to change the temp threshold. The sketch that I have been working with in this thread works consistently checking and verifying the shield is on and responding and turning the shield on if its off or not responding.
If the data being sent has an end of data marker included, then use it. If it doesn't ave an end of data marker, then a delay may be the only way to capture the data. Always start with simple code first to verify the hardware is working, then refine the code.