element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Arduino
  • Products
  • More
Arduino
Arduino Forum Not able to multitask due to blocking code - can it be rewritten?
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Arduino to participate - click to join for free!
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • State Not Answered
  • Replies 0 replies
  • Subscribers 390 subscribers
  • Views 225 views
  • Users 0 members are here
  • arduino uno
  • multitasking
Related

Not able to multitask due to blocking code - can it be rewritten?

donfrankrice
donfrankrice over 8 years ago

Hi everyone,

 

I am a programming/Arduino novice, and am working on a project that would benefit from your expertise.

 

I am using An Arduino Uno, an Ethernet Shield 2, a magnetic window sensor, and an SR04 ultrasonic sensor.  The premise is that the window opens and the SR04 sends out a ping to determine the distance.  The distance will determine if the window was opened from inside the room or outside.  If outside, an IP camera is accessed and a still image is saved to the SD card on the Ethernet shield.  Immediately after saving the file, an email is sent out with a copy of the image attached.

 

Thanks to Koepel, I was able to solve some hefty memory issues and get this sketch to work fairly well.  Now I want to add a second control item with a PIR sensor and a lamp attached to a PowerSwitch Tail, and this is where I am having some trouble.  I have everything separated out into separate functions, but I am still being stymied by the fact that I cannot perform an action with one element and still check on the other.  I have seen references to multitasking, and everything usually points to the same BlinkWithoutDelay example sketch.  While this is helpful in terms of being able to see how to light up several LEDs in different sequences without using delay(), I am having trouble translating that into my own situation.

 

For example, even though the image file that I am saving is only 6K, it takes 12 seconds to save it to the SD card, and an additional 14 seconds to encode and attach to the email.  The piece of code for saving the image looks like this:

 

  // from the server, read them and print them:
  while (client.available()) {
    char c = client.read();
    if (c == '\n' && currentLineIsBlank) {
      // end of HTTP header, now save requested file
      while (client.connected()) {
        // stay in this loop until the file has been received
        if (client.available()) {
          c = client.read();  // get file byte
          Serial.print(c);
          theFile.print(c);   // save file byte
        }
      }
    }
    // detect the end of the incoming HTTP header
    if (c == '\n') {
      // starting a new line
      currentLineIsBlank = true;
    }
    else if (c != '\r') {
      // got a character on the current line
      currentLineIsBlank = false;
    }
  }

 

Note the "stay in this loop until the file has been received" comment.  As long as this is taking place, I can wave my hand in front of the PIR sensor all I want and nothing happens.  I understand that this is correct, but I want to know if there is any way of performing this image save, for example, and still react to the PIR sensor?  I am suspecting that I may need to re-imagine how to use the PIR - perhaps have the opening of the window turn on the lamp via the PowerSwitch Tail, and then work with the PIR in cases where the window is not open.

 

Here's my entire code:

 

#include <SPI.h>
#include <SD.h>
#include <Ethernet2.h>
#include <NewPing.h>




// Arduino pin tied to trigger pin on the ultrasonic sensor.
#define TRIGGER_PIN  8  


// Arduino pin tied to echo pin on the ultrasonic sensor.
#define ECHO_PIN     7  


// Maximum distance we want to ping for (in centimeters). Maximum sensor 
//distance is rated at 400-500cm.
#define MAX_DISTANCE 200 


// window sensor pin
#define WindowPin  6 


//variable to hold the distance to the "window"
int distance;


// NewPing setup of pins and maximum distance.
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); 


byte mac[] = { 0x90, 0xA2, 0xDA, 0x10, 0x7A, 0x87 };
IPAddress server(192, 168, 1, 27);
IPAddress ip(192, 168, 1, 100);


char mailServer[] = "mail.smtp2go.com";


EthernetClient client;


boolean currentLineIsBlank = true;
boolean needPicture = true;
File theFile;
File sendFile;


//variable to use for encoding process
static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";


char buffer[80];


void setup() 
{
  Serial.begin(9600);
  Serial.println(F("Starting the serial monitor"));
  pinMode(WindowPin, INPUT_PULLUP);
  
  //****************************************
  //new on 8/31
  // disable Ethernet chip
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);
  
  Serial.print(F("Initializing SD card..."));


  if (!SD.begin(4)) 
  {
    Serial.println(F(" initialization failed!"));
    return;
  }
  Serial.println(F(" initialization done."));
  
  //*****************************************
  
  
  // start the Ethernet connection:
  if (Ethernet.begin(mac) == 0) 
  {
    Serial.println(F("Failed to configure Ethernet using DHCP"));
    // no point in carrying on, so do nothing forevermore:
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip);
  }
  // give the Ethernet shield a second to initialize:
  delay(1000);


  // print your local IP address:
  Serial.println(Ethernet.localIP());  


}


void loop() 
{
  checkWindowSensor();
}


void checkWindowSensor()
{
  //take a read of the WindowPin.  If it reads HIGH, the window is open,
  //and a message can be displayed as such
  if(digitalRead(WindowPin) == HIGH)
  {
    Serial.println(F("The window is open."));
    
    measureDistance();


  //delay for 2 seconds, to avoid incessant scrolling
    delay(2000);
  }
  
  //If the sensor reads LOW, the window is closed, and a message can be
  //displayed as such.  No need to involve the ultrasonic sensor
  else
  {
    Serial.println(F("Window is closed."));
    
    //this window is closed, so we will need a picture if it opens again
    needPicture = true;
    
    //delay for 2 seconds, to avoid incessant scrolling
    delay(2000);
  }
}


void measureDistance()
{
      // Wait 50ms between pings (about 20 pings/sec). 29ms should be the 
    //shortest delay between pings.
    delay(50);                     
    Serial.print(F("Ping: "));
    
    // Send ping, get distance in cm and print result (0 = outside set distance range)
    distance = sonar.ping_cm();
    Serial.print(distance); 
    Serial.print(F("cm"));
    
    //if the distance to the "window" is less than 15cm, indicate that it was
    //opened from inside. Otherwise, insicate that it was opened from outside
    if(distance <15)
    {
      Serial.println(F(" --opened from inside"));
    }
    else
    {
      Serial.println(F(" --opened from outside"));
      
      //this window was previously closed, so we need a picture
      if (needPicture == true)
        takePicture();
  
    }
}


void takePicture()
{
      Serial.println(F("Taking picture"));
      
      //prevent repeat picture while window stays open
      needPicture = false;
     
      Serial.println(F("connecting to camera..."));
      
      // if you get a connection, report back via serial:
      if (client.connect(server, 80)) 
      {
        Serial.println(F("connected"));
        // Make a HTTP request:
        
        strcpy_P(buffer, PSTR("GET /image.jpg\r\n"));
        client.write(buffer);
          
        strcpy_P(buffer, PSTR("Authorization: Basic YWRtaW46YXVndXN0MTA=\r\n"));
        client.write(buffer);
          
        strcpy_P(buffer, PSTR("Host: 192.168.1.27\r\n"));
        client.write(buffer);
          
        //client.println("Connection: close");
        client.println();
        delay(1000);
      }
      else 
      {
        // if you didn't get a connection to the server:
        Serial.println(F("connection failed"));
      }
        
     // open the file for writing
    Serial.println(F("Creating file."));
  theFile = SD.open("pic.jpg", FILE_WRITE);  // change file name to write to here
  if (!theFile) {
    Serial.println(F("Could not create file"));
    while (1);
  }
  // from the server, read them and print them:
  while (client.available()) {
    char c = client.read();
    if (c == '\n' && currentLineIsBlank) {
      // end of HTTP header, now save requested file
      while (client.connected()) {
        // stay in this loop until the file has been received
        if (client.available()) {
          c = client.read();  // get file byte
          Serial.print(c);
          theFile.print(c);   // save file byte
        }
      }
    }
    // detect the end of the incoming HTTP header
    if (c == '\n') {
      // starting a new line
      currentLineIsBlank = true;
    }
    else if (c != '\r') {
      // got a character on the current line
      currentLineIsBlank = false;
    }
  }


  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println(F("disconnecting."));
    client.stop();
    theFile.close();
    Serial.println(F("Finished writing to file"));
    
    if(sendEmail()) Serial.println(F("Email Sent"));
      else Serial.println(F("Email Failed"));
    
    //while(true);
    
    // do nothing forevermore:
    //while (true);
  }
   
  


  }


byte sendEmail(){
  byte thisByte = 0;
  byte respCode;
  
  if(client.connect(mailServer, 80) == 1){
    Serial.println(F("Connected"));
  }
  else {
    Serial.println(F("Connection Failed"));
    return 0;
  }
  if(!eRcv()) return 0;


  Serial.println(F("Sending Hello"));
//replace 1.2.3.4 with your Arduino's ip**************************
  strcpy_P(buffer, PSTR("EHLO\r\n"));
  client.write(buffer);
  if(!eRcv()) return 0;


  Serial.println(F("Sending authorizes login"));
  strcpy_P(buffer, PSTR("auth login\r\n"));
  client.write(buffer);
  if(!eRcv()) return 0;


  Serial.println(F("Sending User"));
//Change to your base64 encoded user**************************
  strcpy_P(buffer, PSTR("Y29tcDQ0NC5kb25mcmFua3JpY2U=\r\n"));
  client.write(buffer);
  if(!eRcv()) return 0;


  Serial.println(F("Sending Password"));
//change to your base64 encoded password**************************
  strcpy_P(buffer, PSTR("YXJkdWlub1J1bGVzIQ==\r\n"));
  client.write(buffer);
  if(!eRcv()) return 0;


//change to your email address (sender)**************************
  Serial.println(F("Sending From"));
  strcpy_P(buffer, PSTR("MAIL From: <donny.frankrice@gmail.com>\r\n"));
  client.write(buffer);
  if(!eRcv()) return 0;


//change to recipient address**************************
  Serial.println(F("Sending To"));
  strcpy_P(buffer, PSTR("RCPT To: <comp444.donfrankrice@gmail.com>\r\n"));
  client.write(buffer);
  if(!eRcv()) return 0;
  
  Serial.println(F("Sending DATA"));
  strcpy_P(buffer, PSTR("DATA\r\n"));
  client.write(buffer);
  if(!eRcv()) return 0;
  
  Serial.println(F("Sending email"));
  //change to recipient address**************************
  strcpy_P(buffer, PSTR("To: Donny <comp444.donfrankrice@gmail.com>\r\n"));
  client.write(buffer);


  //change to your address**************************
  strcpy_P(buffer, PSTR("From: Donny's Arduino <donny.frankrice@gmail.com>\r\n"));
  client.write(buffer);
  
  strcpy_P(buffer, PSTR("Subject: Alert! Possible Intruder!\r\n"));
  client.write(buffer);
  
//****************************************************
//Start of Attach File
  sendFile =SD.open("pic.jpg",FILE_READ);
  
  strcpy_P(buffer, PSTR("Content-Type: image/jpg; name=\"pic.jpg\"\r\n"));
  client.write(buffer);
  
  client.write("Content-Disposition: attachment; filename=pic.jpg\r\n");
  
  strcpy_P(buffer, PSTR("Content-Transfer-Encoding: base64\r\n\r\n"));
  client.write(buffer);
  
  encode();
  sendFile.close();
//End of Attach File
//****************************************************
  client.print("\r\n.\r\nQUIT\n");
  if(!eRcv()) return 0;
  client.stop();
  Serial.println(F("disconnected"));
  
  //remove picture file in preparation for any future image capture
  SD.remove("pic.jpg");
  return 1;
}


byte eRcv(){
  byte respCode;
  byte thisByte;
  int loopCount = 0;
  while(!client.available()){
    delay(1);
    loopCount++;
    // if nothing received for 10 seconds, timeout
    if(loopCount > 10000) {
      client.stop();
      Serial.println(F("\r\nTimeout"));
      return 0;
    }
  }
  respCode = client.peek();
  while(client.available()){ 
    thisByte = client.read();   
    Serial.write(thisByte);
  }
  if(respCode >= '4'){
    efail();
    return 0; 
  }
  return 1;
}


void efail(){
  byte thisByte = 0;
  int loopCount = 0;
  
  strcpy_P(buffer, PSTR("QUIT\r\n"));
  client.write(buffer);
  
  while(!client.available()) {
    delay(1);
    loopCount++;
    // if nothing received for 10 seconds, timeout
    if(loopCount > 10000) {
      client.stop();
      Serial.println(F("\r\nTimeout"));
      return;
    }
  }
  while(client.available()){ 
    thisByte = client.read();   
    Serial.write(thisByte);
  }
  client.stop();
  Serial.println(F("isconnected"));
}


void encodeblock(unsigned char in[3],unsigned char out[4],int len) {
  out[0]=cb64[in[0]>>2]; out[1]=cb64[((in[0]&0x03)<<4)|((in[1]&0xF0)>>4)];
  out[2]=(unsigned char) (len>1 ? cb64[((in[1]&0x0F)<<2)|((in[2]&0xC0)>>6)] : '=');
  out[3]=(unsigned char) (len>2 ? cb64[in[2]&0x3F] : '=');
}


void encode() {
  unsigned char in[3],out[4];
  int i,len,blocksout=0;
  while (sendFile.available()!=0) {
    len=0;
    for (i=0;i<3;i++){
      in[i]=(unsigned char) sendFile.read();
      if (sendFile.available()!=0) len++;
      else in[i]=0;
    }
    if (len){
      encodeblock(in,out,len);
      for(i=0;i<4;i++) client.write(out[i]);
        blocksout++;
    }
    if (blocksout>=19||sendFile.available()==0){
      if (blocksout) client.print("\r\n");  blocksout=0;
    }
  }
}

 

Thanks for your time!  I welcome your advice!

 

Donny

  • Sign in to reply
  • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube