I'm trying to blink and dim a led at the same time, while running a function that checks some info on a web page. The problem is that the download process of the data takes some time, I mean the modem has to communicate with AT commands and so on, suppose it takes 20 seconds for the full process, in the meantime I need to constantly dim (fade) a LED and blink it at the same time. I know that one way to do both things that works well is with millis() function, but the problem Im having is that I also need to run that function that connects to the web server which is "blocking" lets say.
So the process of multitasking here is becoming really hard.
Do you know if I can use any external timer to make the Blinking part?
What i meant by that is for example, connect to the web server , set up the analog write for the pwm to dim the led at 50% , and handle the on/off of the led with an externa programable timer, like a programmable 555?
Thank you for your support.
your AT command process is just on the Serial line, nothing needs to be blocking your loop there.
- issue your AT command and let the Serial connection handle sending the command to your module
- the module does its job and responds back sometimes later with a flow of data on the Serial Rx
- Read bytes one by one as they come back, in a non blocking way (you'll empty the Rx buffer very quickly)
- Once you've received the full answer, parse it and deal with it
- use millis to test if it's time to blink and fade
I would suggest to study Serial Input Basics to handle the Serial part
Thank your for your support. I see your point, I'll try to implement the things you told me.
Not sure if the code I wrote would work, can I share it with you?
So you can advice me, if I'm heading towards the solution?
You can post your code here, yes we’ll take a look (I’m on the go so only reading from my iPhone)
Let me explain in a few lines whats the idea behind.
I need to control some kind of led light, whats important is that i must be able to change the blinking rate and the dim (fade) of the light at the same time. Thats why I'm using the millis() function. Also i need to send some GPS location values with a SIM800L over HTTP. Just using GET as a String on the URL. The values end up on a SQL database, in the background a PHP script takes those values and show them on a simple web page. Using a simple submit form I take the values from a generated web page and I parse them to take actions on my Arduino Nano.
Well, hope that makes sense.
Thank you again, for your support.
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <AltSoftSerial.h>
#define rxPin 10
#define txPin 11
SoftwareSerial sim800L(rxPin,txPin);
//GPS Module RX pin to Arduino 9
//GPS Module TX pin to Arduino 8
AltSoftSerial neogps;
TinyGPSPlus gps;
unsigned long previousMillis = 0;
long interval = 60000;
int baliza= 6;
int readPin=A2;
void setup(){
pinMode(readPin,INPUT);
pinMode(baliza, OUTPUT);
//Begin serial communication with Arduino and Arduino IDE (Serial Monitor)
Serial.begin(9600);
//Begin serial communication with Arduino and SIM800L
sim800L.begin(9600);
//Begin serial communication with Arduino and SIM800L
neogps.begin(9600);
Serial.println("Initializing...");
}
void loop()
{
while(sim800L.available()){
Serial.println(sim800L.readString());
}
while(Serial.available()) {
sim800L.println(Serial.readString());
}
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
controlLedsyGPS();
}
}
void controlLedsyGPS()
{
//Can take up to 60 seconds
boolean newData = false;
for (unsigned long start = millis(); millis() - start < 2000;){
while (neogps.available()){
if (gps.encode(neogps.read())){
newData = true;
break;
}
}
}
//If newData is true
if(true){
newData = false;
int v1=0; //Lectura de voltaje en el pin A2
float voltaje1_temp=0;
v1=analogRead(readPin);
voltaje1_temp=(5./1023.)*v1 ; //el punto es porque preciso que el valor sean un float con decimales
char buffer[6]; //convertimos el float a string para ser enviado por el metodo GET
dtostrf(voltaje1_temp,6,2,buffer); //paso intermedio conviertiendo a un array de char[]
String voltaje1=String(buffer); //lo convierto a string
String latitude, longitude ;
latitude = String(gps.location.lat(), 6); // Latitude in degrees (double)
longitude = String(gps.location.lng(), 6); // Longitude in degrees (double)
Serial.print("Latitude= ");
Serial.print(latitude);
Serial.print(" Longitude= ");
Serial.println(longitude);
Serial.print(" Voltaje1= ");
Serial.println(voltaje1);
//if (latitude == 0) {return 0;}
String url,tmp;
url = "http://balizas2.000webhostapp.com/gpsdata.php?lat=";
url += latitude;
url += "&lng=";
url += longitude;
url += "&voltaje1=";
url+= voltaje1;
url += "&estado=1";
tmp = "http://balizas2.000webhostapp.com/getstate.php?color=All";
Serial.println(tmp);
delay(300);
Serial.println(url);
delay(300);
sendATcommand("AT+CBC", "OK", 2000);
sendATcommand("AT+CSQ", "OK", 2000);
sendATcommand("AT+CGATT?", "OK", 2000);
//Connection type: GPRS - bearer profile 1
sendATcommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\"", "OK", 2000);
//sets the APN settings for your network provider.
sendATcommand("AT+SAPBR=3,1,\"APN\",\"antel.lte\"", "OK", 2000);
sendATcommand("AT+SAPBR=0,1", "OK", 2000);
//enable the GPRS - enable bearer 1
sendATcommand("AT+SAPBR=1,1", "OK", 2000);
//Init HTTP service
sendATcommand("AT+HTTPINIT", "OK", 2000);
sim800L.print("AT+HTTPPARA=\"URL\",\"");
sim800L.print(tmp);
sendATcommand("\"", "OK", 1000);
//Set up the HTTP action
sendATcommand("AT+HTTPACTION=0", "0,200", 10000);
sendATcommand("AT+HTTPREAD", "OK", 300);
changeLed();
sim800L.println("");
sendATcommand("AT+HTTPTERM", "OK", 2000);
//Codigo del GPS
sendATcommand("AT+CGATT?", "OK", 2000);
//Connection type: GPRS - bearer profile 1
sendATcommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\"", "OK", 2000);
//sets the APN settings for your network provider.
sendATcommand("AT+SAPBR=3,1,\"APN\",\"antel.lte\"", "OK", 2000);
sendATcommand("AT+SAPBR=0,1", "OK", 2000);
//enable the GPRS - enable bearer 1
sendATcommand("AT+SAPBR=1,1", "OK", 2000);
//sendATcommand("AT+HTTPTERM", "OK", 1000);
sendATcommand("AT+HTTPINIT", "OK", 2000);
sim800L.print("AT+HTTPPARA=\"URL\",\"");
sim800L.print(url);
sendATcommand("\"", "OK", 1000);
//Set up the HTTP action
sendATcommand("AT+HTTPACTION=0", "0,200", 1000);
sendATcommand("AT+HTTPTERM", "OK", 1000);
}
return 1;
}
int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout){
uint8_t x=0, answer=0;
char response[100];
unsigned long previous;
//Initialice the string
memset(response, '\0', 100);
delay(100);
//Clean the input buffer
while( sim800L.available() > 0) sim800L.read();
if (ATcommand[0] != '\0'){
//Send the AT command
sim800L.println(ATcommand);
}
x = 0;
previous = millis();
//this loop waits for the answer with time out
do{
cadencia();
//if there are data in the UART input buffer, reads it and checks for the asnwer
if(sim800L.available() != 0){
response[x] = sim800L.read();
//Serial.print(response[x]);
x++;
// check if the desired answer (OK) is in the response of the module
if(strstr(response, expected_answer) != NULL){
answer = 1;
}
}
}while((answer == 0) && ((millis() - previous) < timeout));
Serial.println(response);
return answer;
}
void changeLed()
{
String content = "";
while(sim800L.available()!=0)
{
//Serial.write(sim800L.read());
content = content + String(char (sim800L.read()));
}
Serial.println(content);
if(content.substring(32,33)== "5") //reconozco el valor de la baliza, aumentos del 20%
{
digitalWrite(baliza, HIGH);
}
else if (content.substring(32,33)== "4"){
analogWrite(baliza,204);
}
else if (content.substring(32,33)== "3"){
analogWrite(baliza,200);
}
else if (content.substring(32,33)== "2"){
analogWrite(baliza,102);
}
else if (content.substring(32,33)== "1"){
analogWrite(baliza,51);
}
else if (content.substring(32,33)== "0")
{
digitalWrite(baliza, LOW);
}
content = "";
}
void cadencia(){ //how many times per second will blink
String content = "";
while(sim800L.available()!=0) {
content = content + String(char (sim800L.read()));
}
unsigned long cuenta=millis();
unsigned long precuenta=0;
int ledState=LOW;
if(content.substring(31,32)== "5"){ //maximun blinking time of 1 second
if ((cuenta-precuenta)>=1000){
precuenta=cuenta;
if(ledState==LOW){
ledState=HIGH;
}else{
ledState=LOW;
}
}
digitalWrite(baliza, HIGH);
}
else if (content.substring(31,32)== "4"){
if ((cuenta-precuenta)>=800){
precuenta=cuenta;
if(ledState==LOW){
ledState=HIGH;
}else{
ledState=LOW;
}
}
digitalWrite(baliza, HIGH);
}
else if (content.substring(31,32)== "3"){
if ((cuenta-precuenta)>=600){
precuenta=cuenta;
if(ledState==LOW){
ledState=HIGH;
}else{
ledState=LOW;
}
}
digitalWrite(baliza, HIGH);
}
else if (content.substring(31,32)== "2"){
if ((cuenta - precuenta)>=400){
precuenta=cuenta;
if(ledState==LOW){
ledState=HIGH;
}else{
ledState=LOW;
}
}
digitalWrite(baliza, HIGH);
}
else if (content.substring(31,32)== "1"){
if ((cuenta-precuenta)>=200){
precuenta=cuenta;
if(ledState==LOW){
ledState=HIGH;
}else{
ledState=LOW;
}
}
digitalWrite(baliza, HIGH);
}
else if (content.substring(31,32)== "0"){
digitalWrite(baliza, LOW);
}
}
Do you know looking at the log , what could be the cause that my code ,prints correctly the contents of the variable "content", but I get no output from the Arduino pins to turn the led on?
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <AltSoftSerial.h>
#define rxPin 10
#define txPin 11
SoftwareSerial sim800L(rxPin,txPin);
//GPS Module RX pin to Arduino 9
//GPS Module TX pin to Arduino 8
AltSoftSerial neogps;
TinyGPSPlus gps;
unsigned long previousMillis = 0;
long interval = 20000;
int readPin=A2;
int bluePin = 6; //pin our blue LED is connected to
int ledState = 0; //used to control blue LED state, we're starting with it OFF
int pwm = 250; // percentage of light intensity
unsigned long currentMillis = 0; //stores the current time
unsigned long blinkPreviousMillis = 0; //stores last time blue LED was updated
unsigned long cadencia = 1000; //interval to blink blue LED in milliseconds
void setup(){
pinMode(readPin,INPUT);
pinMode(bluePin, OUTPUT);
//Begin serial communication with Arduino and Arduino IDE (Serial Monitor)
Serial.begin(9600);
//Begin serial communication with Arduino and SIM800L
sim800L.begin(9600);
//Begin serial communication with Arduino and SIM800L
neogps.begin(9600);
Serial.println("Initializing...");
}
void loop()
{
while(sim800L.available()){
Serial.println(sim800L.readString());
}
while(Serial.available()) {
sim800L.println(Serial.readString());
}
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
controlLedsyGPS();
}
}
void controlLedsyGPS()
{
//Can take up to 60 seconds
boolean newData = false;
for (unsigned long start = millis(); millis() - start < 2000;){
while (neogps.available()){
if (gps.encode(neogps.read())){
newData = true;
break;
}
}
}
//If newData is true
if(true){
newData = false;
//Control de carga--------------------------------------------------------------------------------------------
int v1=0; //Lectura de voltaje en el pin A2
float voltaje1_temp=0;
v1=analogRead(readPin);
voltaje1_temp=(5./1023.)*v1 ; //el punto es porque preciso que el valor sean un float con decimales
char buffer[6]; //convertimos el float a string para ser enviado por el metodo GET
dtostrf(voltaje1_temp,4,2,buffer); //paso intermedio conviertiendo a un array de char[]
String voltaje1=String(buffer); //lo convierto a string
//Control de carga----------------------------------------------------------------------------------------------
String latitude, longitude ;
latitude = String(gps.location.lat(), 6); // Latitude in degrees (double)
longitude = String(gps.location.lng(), 6); // Longitude in degrees (double)
Serial.print("Latitude= ");
Serial.print(latitude);
Serial.print(" Longitude= ");
Serial.print(longitude);
Serial.print(" Voltaje1= ");
Serial.println(voltaje1);
//if (latitude == 0) {return 0;}
String url,tmp;
url = "http://balizas2.000webhostapp.com/gpsdata.php?lat=";
url += latitude;
url += "&lng=";
url += longitude;
url += "&voltaje1=";
url+= voltaje1;
url += "&estado=1";
tmp = "http://balizas2.000webhostapp.com/getstate.php?color=All";
//url = "http://ahmadssd.000webhostapp.com/gpsdata.php?lat=222&lng=222";
Serial.println(tmp);
delay(300);
Serial.println(url);
delay(300);
sendATcommand("AT+CBC", "OK", 2000);
sendATcommand("AT+CSQ", "OK", 2000);
sendATcommand("AT+CGATT?", "OK", 2000);
//Connection type: GPRS - bearer profile 1
sendATcommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\"", "OK", 2000);
//sets the APN settings for your network provider.
sendATcommand("AT+SAPBR=3,1,\"APN\",\"antel.lte\"", "OK", 2000);
sendATcommand("AT+SAPBR=0,1", "OK", 2000);
//enable the GPRS - enable bearer 1
sendATcommand("AT+SAPBR=1,1", "OK", 2000);
//Init HTTP service
sendATcommand("AT+HTTPINIT", "OK", 2000);
sim800L.print("AT+HTTPPARA=\"URL\",\"");
sim800L.print(tmp);
sendATcommand("\"", "OK", 1000);
//Set up the HTTP action
sendATcommand("AT+HTTPACTION=0", "0,200", 2000);
sendATcommand("AT+HTTPREAD", "OK", 300);
blink_and_fade();
sim800L.println("");
sendATcommand("AT+HTTPTERM", "OK", 2000);
//Codigo del GPS
sendATcommand("AT+CGATT?", "OK", 2000);
//Connection type: GPRS - bearer profile 1
sendATcommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\"", "OK", 2000);
//sets the APN settings for your network provider.
sendATcommand("AT+SAPBR=3,1,\"APN\",\"antel.lte\"", "OK", 2000);
sendATcommand("AT+SAPBR=0,1", "OK", 2000);
//enable the GPRS - enable bearer 1
sendATcommand("AT+SAPBR=1,1", "OK", 2000);
//sendATcommand("AT+HTTPTERM", "OK", 1000);
sendATcommand("AT+HTTPINIT", "OK", 2000);
sim800L.print("AT+HTTPPARA=\"URL\",\"");
sim800L.print(url);
sendATcommand("\"", "OK", 1000);
//Set up the HTTP action
sendATcommand("AT+HTTPACTION=0", "0,200", 1000);
sendATcommand("AT+HTTPTERM", "OK", 1000);
}
return 1;
}
int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout){
uint8_t x=0, answer=0;
char response[100];
unsigned long previous;
//Initialice the string
memset(response, '\0', 100);
delay(100);
//Clean the input buffer
while( sim800L.available() > 0) sim800L.read();
if (ATcommand[0] != '\0'){
//Send the AT command
sim800L.println(ATcommand);
}
x = 0;
previous = millis();
//this loop waits for the answer with time out
do{
//if there are data in the UART input buffer, reads it and checks for the asnwer
if(sim800L.available() != 0){
response[x] = sim800L.read();
//Serial.print(response[x]);
x++;
// check if the desired answer (OK) is in the response of the module
if(strstr(response, expected_answer) != NULL){
answer = 1;
}
}
}while((answer == 0) && ((millis() - previous) < timeout));
Serial.println(response);
return answer;
}
void blink_and_fade(){
String content = "";
while(sim800L.available()!=0)
{
//Serial.write(sim800L.read());
content = content + String(char (sim800L.read()));
}
Serial.println(content);
if(content.substring(28,29)== "1") //1 segundo de cadencia
{
}
if(content.substring(29,30)== "1") //1 segundo de cadencia
{
cadencia=1000;
}
if(content.substring(30,31)== "1") //reconozco el valor de la bluePin, aumentos del 20%
{
pwm=250;
}
/*if the difference between the current time and last time the LED blinked is greater than or equal to the blink period, we need to blink
* the LED*/
if (currentMillis - blinkPreviousMillis >= cadencia) {
//record the current time the blink happens to blinkPreviousMillis
blinkPreviousMillis = currentMillis;
//if the LED is off (LOW) change the LED state to on (HIGH)
if (ledState == 0) {
ledState = pwm;
}
/*if the LED is on (HIGH), turn it off (LOW)*/
else {
ledState = 0;
}
//output the state of the blue LED
analogWrite(bluePin, ledState);
}
}
I attach the log below...
not_responding_to_commands_log.txt (2.9 KB)
my experience using multiple software serial libraries with asynchronous communication is that it's not reliable
this can lock the loop for quite sometime depending on what's coming as readString needs to timeout.
if you want to print what's coming just do
while(sim800L.available()){
Serial.write(sim800L.read());
}
while(Serial.available()) {
sim800L.write(Serial.read());
}
this feels really weird
your sendATcommand()
function is full of blocking code. For example when you do (the useless)
You wait for 100ms (why?). at 9600 baud , in 1/10th of a second you can get ~100 bytes. The incoming buffer can only hold 64 and so if there is a long NMEA sentence arriving, you will loose some characters and the sentence won't be decoded correctly.
the controlLedsyGPS() function will block too for way too long.
this is not guaranteed to read the incoming buffer correctly
void cadencia() { //how many times per second will blink
String content = "";
while (sim800L.available() != 0) {
content = content + String(char (sim800L.read()));
}
you just empty the sim800L buffer into your String but reading the buffer is super fast compared to how that data arrives on the Serial port at 9600 bauds. I would suggest to study Serial Input Basics to handle this
➜ my recommendation would be to go a better arduino with more hardware driven UART (3 minimum like an Arduino Mega ou and ESP32 or a MKR) and totally rewrite the code using a state machine for each separate task so that you are never blocking the loop
(and on a small memory arduino like a Nano, using so many Strings can lead to memory challenges at run time)
if you need a small board and want to stay on AVR consider the Mega Mini
I think that you are right ,look at what I found...
I printed the output of the buffer using a known code that works (that uses delay()) ...and shows
void changeLed()
{
String content = "";
// String RedState = content.substring();
while(SIM900.available()!=0)
{
//Serial.write(SIM900.read());
content = content + String(char (SIM900.read()));
}
Serial.println(content);
Serial.println(content[1]);
for (int i = 0; i < 32; i++){
Serial.println(content[i]);
}
if(content.substring(28,29)== "1")
{
digitalWrite(BLUELed, HIGH);
}
else if (content.substring(28,29)== "0")
{
and this is what I should get...
05:32:17.558 -> AT+HTTPPARA="URL","balizas2.000webhostapp.com/getstate.php?coloAT+HTTPACTION=0
05:32:19.574 -> OK
05:32:19.574 ->
05:32:19.574 -> +HTTPACTION: 0,200,4
05:32:19.902 -> AT+HTTPREAD
05:32:19.902 -> +HTTPREAD: 4
05:32:19.949 -> 111
05:32:19.949 -> OK
05:32:19.949 ->
05:32:19.949 -> T
05:32:19.949 -> A
05:32:19.949 -> T
05:32:19.949 -> +
05:32:19.949 -> H
05:32:19.949 -> T
05:32:19.949 -> T
05:32:19.949 -> P
05:32:19.949 -> R
05:32:19.949 -> E
05:32:19.949 -> A
05:32:19.995 -> D
05:32:19.995 ->
05:32:19.995 ->
05:32:19.995 ->
05:32:19.995 ->
05:32:19.995 -> +
05:32:19.995 -> H
05:32:19.995 -> T
05:32:19.995 -> T
05:32:19.995 -> P
05:32:19.995 -> R
05:32:19.995 -> E
05:32:19.995 -> A
05:32:19.995 -> D
05:32:19.995 -> :
05:32:19.995 ->
05:32:20.042 -> 4
05:32:20.042 ->
05:32:20.042 ->
05:32:20.042 ->
05:32:20.042 -> 1
05:32:20.042 -> 1
05:32:20.042 -> 1
05:32:20.042 ->
05:32:20.089 -> SubmitHttpRequest - finished
I think that using the other code with the sendAtCommands, is doing weird things because of what you said of the read buffer speed.
If I try to print the output using the at function...
The content in "content" is just empty spaces....It's like the program rush to the next line and don't want to spend anytime filling the variable "content".
The problem is that I'm already late with this project and I need to try to find a solution, but you are 100% right that this is not the best suitable board. It has become a powerful brain challenge to make this work.
and this is with the other code....
void changeLed()
{
String content = "";
// String RedState = content.substring();
while(sim800L.available()!=0)
{
//Serial.write(sim800L.read());
content = content + String(char (sim800L.read()));
}
Serial.println(content);
for (int i = 0; i < 50; i++){
Serial.println(content[i]);
}
if(content.substring(28,29)== "1")
{
digitalWrite(REDLed, HIGH);
}
else if (content.substring(28,29)== "0")
{
and the output is...
05:44:38.076 -> AT+HTTPACTION=0
05:44:38.076 -> OK
05:44:38.076 ->
05:44:38.076 -> +HTTPACTION: 0,200
05:44:38.217 -> AT+HTTPREAD
05:44:38.264 -> +HTTPREAD: 4
05:44:38.264 -> 111
05:44:38.264 -> OK
05:44:38.264 ->
05:44:38.264 ->
05:44:38.264 ->
05:44:38.264 ->
05:44:38.264 ->
05:44:38.264 ->
So that's the problem I guess, I should find some kind of trick to wait until that buffer fills.
I'll review what you told me on the last message, study more and try to come with a solution.
By the way ,I read what you linked about Serial It's a bit confusing for me at first sight, but that doesn't mean I won't get it.
I have to leave know. Thank you for your help.
the problem is that you made choices early without looking at the full requirements and what it meant in terms of hardware needs.
I'm afraid it won't work in a reliable way unless you either change the requirements so that tasks could be sequentials or pick a better board where more things can happen in hardware (esp hardware serial ports) and you'll have to rewrite the project anyway to not block the code anyway...
while(sim800L.available()){
Serial.println(sim800L.readString());
}
while(Serial.available()) {
sim800L.println(Serial.readString());
}
That's an example of blocking code right there.
this is not guaranteed to read the incoming buffer correctly
void cadencia() { //how many times per second will blink String content = ""; while (sim800L.available() != 0) { content = content + String(char (sim800L.read())); }
you just empty the sim800L buffer into your String but reading the buffer is super fast compared to how that data arrives on the Serial port at 9600 bauds. I would suggest to study Serial Input Basics to handle this
This is the part I think I don't get....I mean I understand that you can't read faster than it fills, but looking at that while loops it seems that the iteration goes like " keep adding the characters,untill you get the terminating character,after that go out of the loop" at that time the content of the buffer should be the whole string, after that I read it...why is that the buffer is empty...Can you try to clarify that? thanks....
I tried my best to make all the changes you told me.
Now I've this simple code, but I still can't find the way to fill bit by bit the array of chars with the data coming from HTTPREAD.
Please take a look, I guess there's something on the downcast maybe that's not written correctly?
Thanks
#include <SoftwareSerial.h>
#define rxPin 10
#define txPin 11
SoftwareSerial sim800L(rxPin,txPin);
unsigned long previousMillis = 0;
long interval = 10000;
int YELLOWLed= 3;
int GREENLed= 4;
int BLUELed= 6;
void setup(){
pinMode(YELLOWLed, OUTPUT);
pinMode(GREENLed, OUTPUT);
pinMode(BLUELed, OUTPUT);
//Begin serial communication with Arduino and Arduino IDE (Serial Monitor)
Serial.begin(9600);
//Begin serial communication with Arduino and SIM800L
sim800L.begin(9600);
Serial.println("Initializing...");
}
void loop() {
while(sim800L.available()){
Serial.write(sim800L.read());
}
while(Serial.available()) {
sim800L.write(Serial.read());
}
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
controlLeds();
}
}
void controlLeds()
{
String url;
url = "http://balizas2.000webhostapp.com/getstate.php?color=All";
Serial.println(url);
sendATcommand("AT+CBC", "OK", 2000);
sendATcommand("AT+CSQ", "OK", 2000);
sendATcommand("AT+CGATT?", "OK", 2000);
//Connection type: GPRS - bearer profile 1
sendATcommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\"", "OK", 2000);
//sets the APN settings for your network provider.
sendATcommand("AT+SAPBR=3,1,\"APN\",\"antel.lte\"", "OK", 2000);
sendATcommand("AT+SAPBR=0,1", "OK", 2000);
//enable the GPRS - enable bearer 1
sendATcommand("AT+SAPBR=1,1", "OK", 2000);
//Init HTTP service
sendATcommand("AT+HTTPINIT", "OK", 2000);
sim800L.print("AT+HTTPPARA=\"URL\",\"");
sim800L.print(url);
sendATcommand("\"", "OK", 1000);
//Set up the HTTP action
sendATcommand("AT+HTTPACTION=0", "0,200", 10000);
sendATcommand("AT+HTTPREAD", "OK", 300);
changeLed();
sim800L.println("");
sendATcommand("AT+HTTPTERM", "OK", 2000);
}
int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout){
uint8_t x=0, answer=0;
char response[100];
unsigned long previous;
//Initialice the string
memset(response, '\0', 100);
//Clean the input buffer
while( sim800L.available() > 0) sim800L.read();
if (ATcommand[0] != '\0'){
//Send the AT command
sim800L.println(ATcommand);
}
x = 0;
previous = millis();
//this loop waits for the answer with time out
do{
//if there are data in the UART input buffer, reads it and checks for the asnwer
if(sim800L.available() != 0){
response[x] = sim800L.read();
//Serial.print(response[x]);
x++;
// check if the desired answer (OK) is in the response of the module
if(strstr(response, expected_answer) != NULL){
answer = 1;
}
}
}while((answer == 0) && ((millis() - previous) < timeout));
Serial.println(response);
return answer;
}
void changeLed()
{
String content = "ABCDEFGHIJKLMNOPQRSTUVXYZABC110"; // "OBVIOUSLY THIS IS NOT THE CONTENT I WANT TO SEE"; // expecting "111"
char data[]="0";
uint8_t i = 0;
while(sim800L.available()!=0)
{
//if there is data in the UART input buffer, reads it and checks for the answer
data[i] = sim800L.read(); //move bit by bit of data to the array
i++; // increse the index
content = String(char (data)); // cast to a String to work with
//content + String(char (sim800L.read()));
}
Serial.println(content);
//for (int i = 0; i < 50; i++){
//Serial.println(content[i]);
//}
if(content.substring(28,29)== "1")
{
digitalWrite(YELLOWLed, HIGH);
}
else if (content.substring(28,29)== "0")
{
digitalWrite(YELLOWLed, LOW);
}
if(content.substring(29,30)== "1")
{
digitalWrite(GREENLed, HIGH);
}
else if (content.substring(29,30)== "0")
{
digitalWrite(GREENLed, LOW);
}
if(content.substring(30,31)== "1")
{
digitalWrite(BLUELed, HIGH);
}
else if (content.substring(30,31)== "0")
{
digitalWrite(BLUELed, LOW);
}
content = "";
}
Also let me add that I changed the 100 value to 64 and I get strange characters, so I guess I can't change that number.
Do you think the code on POST #13 , is correct? I can't find why its not working, I tried to tune up the code ,but still nothing...I'm 100% positive that the problem is the buffer not filling.
Thanks.
sim800L.read()
does not block, it returns whatever is in the buffer (or -1 if there is nothing to read). so a read is super fast, it's just returning a byte from a RAM buffer (and "removing" that byte from the buffer).
imagine the sim800L has 30 characters to send and only 10 have arrived so far in the buffer when you enter the while loop
so your while loop will take just a few tens/hundreds micro-seconds to read the 10 bytes that are in the buffer.
At 9600 bauds you get 1 incoming byte every millisecond roughly so during the time you read the 10 bytes that were in the buffer, you possibly got another byte added in the buffer so the while loop will read this extra byte in a few micro-seconds and then the buffer is empty, the next byte is still in transit and so sim800L.available()
will be 0 and you exit the while loop and you'll have 11 chars in content
instead of the 30 bytes of the message.
from there on all bets are off, the next time you come read the sim800L's buffer, you'll have received the other 19 bytes and possibly the start of a new message and your parsing will just go wrong.
➜ the takeaway is that you can't second guess the timing of an asynchronous communication. You need to read the bytes when they come in, until you get some sort of end marker for the communication (or possibly a timeout to not be locked in an infinite wait if the sim800L is having issues).
The Serial Input Basics tutorial explains this and shows code for collecting an input until an end marker and dealing with this input.
I think I get it, its similar to this tutorial on youtube that explains that.
Using Serial.read() with Arduino | Part 1
I thought that I was considering that in my new code in this part...
void changeLed()
{
String content = "";
char data[]="0";
uint8_t i = 0;
while(sim800L.available()!=0)
{
//if there is data in the UART input buffer, reads it and checks for the answer
data[i] = sim800L.read(); //move byte by byte of data to the array
i++; // increase the index
content = String(char (data)); // cast to a String to work with
//content + String(char (sim800L.read()));
}
Serial.println(content); // expecting "111"
//for (int i = 0; i < 50; i++){
//Serial.println(content[i]);
//}
if(content.substring(28,29)== "1")
{
digitalWrite(YELLOWLed, HIGH);
}
as long as you'll think this is reading the whole message
your code won't be fool proof
also this won't build up the message, you are just assigning successively the received values into content.
may be you wanted +=
?
(I would advise against using the String class)
have you read the Serial Input Basics tutorial?
controlLeds.... it initializes the net connection every time? How often?
Aren't there timeouts being set in some of those AT commands?
Why isn't that done once in setup()?
Those actions are for slow, clunky code. Hope I see wrong!
I have worked around some Sim900 use before but stopped at fixing the blocking .begin() function that by the SD log kept took over 30 seconds to get linked. Since the plan was to collect every 10 minutes and update the web page once an hour there was no problem going the whole routine every time.
But for you, is it?
I managed to make it work.
I used the timer0 interrupt, and now I can blink,dimm and loop from the AT commands process. It was a nice solution. Now Im having another problem with the scope of a variable or maybe a class constructor i think...if you can take a look to this post where I try to get some help, maybe you notice what's wrong, I believe it has to be an easy fix, but I guess there's something Im not seeing.
Also in the post I have the ISR for the timer0.
Thanks.
Finally after long hour of researching and thinking I ended implementing a ISR with Timer0 , so I it doesn't conflict with AltSoftwareSerial(uses Timer1), and now the led is blinking,dimming and with no lag.
I'm having another problem, I believe its the scope of a variable inside a constructor.
Maybe you can help me.
Thanks
Here's the link...