Combining wifi shield code with flowmeter code is creating problems...

Hey friends,

I'm using the Sparkfun CC3000 WiFi shield along with this flowmeter.

My project involves measuring the flow using the flowmeter and posting the measurements on the IoT platform Thingspeak. While I've been able to use separate code to show the flowmeter works as well as being able to post something onto thingspeak, when I put those two together, it wasn't working again.

In the code for the flowmeter, these are the lines in the loop:

NbTopsFan = 0;
sei();
delay(1000);
cli();
Cal = (NbTopsFan * 60 / 7.5);

Description of the problem: In the beginning, it connects to the network and begins giving values in one second intervals (as it should). But once it reaches the time interval to get the time again (it polls for the time every 15 seconds), it stops working and doesn't actually do that.

I realized that the problem has to do with the sei() and cli() commands. When I add them, it stops working, but when they aren't there, it works again.

Can anyone help?
Thank you very much!

Here's the full code:

#include <Wire.h>

#include <Time.h>
#include <Adafruit_CC3000.h>
#include <ccspi.h>
#include <SPI.h>

// These are the interrupt and control pins
#define ADAFRUIT_CC3000_IRQ   2  // MUST be an interrupt pin!
// These can be any two pins
#define ADAFRUIT_CC3000_VBAT  7
#define ADAFRUIT_CC3000_CS    10
// Use hardware SPI for the remaining pins
// On an UNO, SCK = 13, MISO = 12, and MOSI = 11
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
                                         SPI_CLOCK_DIVIDER); // you can change this clock speed but DI

#define WLAN_SSID       "IFH Lounge"        // cannot be longer than 32 characters!
#define WLAN_PASS       "ifhJanuary"
// Security can be WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
#define WLAN_SECURITY   WLAN_SEC_WPA2
char server[]= "api.thingspeak.com"; 
String writeAPIKey = "4JRIMA3GJF3PIQKE"; // API key for Thingspeak
const int updateThingSpeakInterval = 15 * 1000; // time interval between updates

volatile int NbTopsFan;
int Calc;
int hallsensor = 3;

long lastConnectionTime = 0;
boolean lastConnected = false;
int failedCounter = 0;
int test = 0; //THIS IS THE VALUE BEING LOGGED. 
long y = 0;

Adafruit_CC3000_Client client;

const unsigned long
  connectTimeout  = 15L * 1000L, // Max time to wait for server connection
  responseTimeout = 15L * 1000L; // Max time to wait for data from server
int
  countdown       = 0;  // loop() iterations until next time server query
unsigned long
  lastPolledTime  = 0L, // Last value retrieved from time server
  sketchTime      = 0L; // CPU milliseconds since last server query

void rpm(){
  NbTopsFan++;
}

void setup(void)
{
  pinMode(hallsensor, INPUT);
  attachInterrupt(1, rpm, RISING);
  Serial.begin(115200);
  Serial.println(F("Hello, CC3000!\n")); 
  
  Serial.println(F("\nInitialising the CC3000 ..."));
  if (!cc3000.begin()) {
    Serial.println(F("Unable to initialise the CC3000! Check your wiring?"));
    for(;;);
  }
  
  Serial.println(F("\nDeleting old connection profiles"));
  if (!cc3000.deleteProfiles()) {
    Serial.println(F("Failed!"));
    while(1);
  }

  /* Attempt to connect to an access point */
  char *ssid = WLAN_SSID;             /* Max 32 chars */
  Serial.print(F("\nAttempting to connect to ")); Serial.println(ssid);
  
  /* NOTE: Secure connections are not available in 'Tiny' mode! */
  if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
    Serial.println(F("Failed!"));
    while(1);
  }
   
  Serial.println(F("Connected!"));
  
  /* Wait for DHCP to complete */
  Serial.println(F("Request DHCP"));
  while (!cc3000.checkDHCP()) {
    delay(100); // ToDo: Insert a DHCP timeout!
  }
  
}


// To reduce load on NTP servers, time is polled once per roughly 24 hour period.
// Otherwise use millis() to estimate time since last query.  Plenty accurate.
void loop(void) {  
  if(millis()-y >= 15000) {            // Time's up?
    unsigned long t  = getTime(); // Query time server
    if(t) {                       // Success?
      lastPolledTime = t;         // Save time
      sketchTime = millis();
    }
    y = millis();
    Serial.println(y);
  }  
  NbTopsFan = 0;
  sei();
  delay(1000);
  cli();
  //Calc = (NbTopsFan * 60 / 7.5);

  test = 1;
  unsigned long currentTime = lastPolledTime + (millis()-sketchTime) / 1000;
  setTime(currentTime - 18000);
  Serial.print(hour());
  Serial.print(":");
  Serial.print(minute());
  Serial.print(":");
  Serial.println(second());
  Serial.print(Calc, DEC);
  Serial.print("L/hour\r\n");
  
  if (!client.connected() && lastConnected){
    Serial.println("...disconnected");
    Serial.println();

    client.stop();
  }
  if (!client.connected() && millis() - lastConnectionTime > updateThingSpeakInterval){
    updateThingSpeak("field1="+ String(test, DEC));
  }

  if (failedCounter > 3){
    cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY);
  }

  lastConnected = client.connected();
}
// Minimalist time server query; adapted from Adafruit Gutenbird sketch,
// which in turn has roots in Arduino UdpNTPClient tutorial.
unsigned long getTime(void) {

  uint8_t       buf[48];
  unsigned long ip, startTime, t = 0L;

  Serial.print(F("Locating time server..."));

  // Hostname to IP lookup; use NTP pool (rotates through servers)
  if(cc3000.getHostByName("pool.ntp.org", &ip)) {
    static const char PROGMEM
      timeReqA[] = { 227,  0,  6, 236 },
      timeReqB[] = {  49, 78, 49,  52 };

    Serial.println(F("\r\nAttempting connection..."));
    startTime = millis();
    do {
      client = cc3000.connectUDP(ip, 123);
    } while((!client.connected()) &&
            ((millis() - startTime) < connectTimeout));

    if(client.connected()) {
      Serial.print(F("connected!\r\nIssuing request..."));

      // Assemble and issue request packet
      memset(buf, 0, sizeof(buf));
      memcpy_P( buf    , timeReqA, sizeof(timeReqA));
      memcpy_P(&buf[12], timeReqB, sizeof(timeReqB));
      client.write(buf, sizeof(buf));

      Serial.print(F("\r\nAwaiting response..."));
      memset(buf, 0, sizeof(buf));
      startTime = millis();
      while((!client.available()) &&
            ((millis() - startTime) < responseTimeout));
      if(client.available()) {
        client.read(buf, sizeof(buf));
        t = (((unsigned long)buf[40] << 24) |
             ((unsigned long)buf[41] << 16) |
             ((unsigned long)buf[42] <<  8) |
              (unsigned long)buf[43]) - 2208988800UL;
        Serial.print(F("OK\r\n"));
      }
      client.close();
    }
  }
  if(!t) Serial.println(F("error"));
  return t;
}

void updateThingSpeak(String tsData){ //this block of lines basically accesses the Thingspeak channel in the required format
  if (client.connect(server, 80)){
    client.print("POST /update HTTP/1.1\n");
    client.print("Host: api.thingspeak.com\n");
    client.print("Connection: close\n");
    client.print("X-THINGSPEAKAPIKEY: "+writeAPIKey+ "\n");
    client.print("Content-Type: application/x-www-form-urlencoded\n");
    client.print("Content-Length: ");
    client.print(tsData.length());
    client.print("\n\n");

    client.print(tsData);

    lastConnectionTime = millis();

    if (client.connected()){
      Serial.println("Connected to Thingspeak...");
      Serial.println();
      failedCounter = 0;
    }

    else{
      failedCounter++;

      Serial.println("Connection to ThingSpeak failed ("+String(failedCounter, DEC)+")");
      Serial.println();
    }
   }
   else{
    failedCounter++;

    Serial.println("Connection to ThingSpeak failed ("+String(failedCounter, DEC)+")");
    Serial.println();

    lastConnectionTime = millis();
   }
  }

I think I was able to narrow down the problem. I'm using a getTime function in the code to get a time stamp (used for another purpose within the project). When I removed all the associated lines within the loop of that, the code seemed to work well.
Associated code being:

 if(millis()-y >= 15000) {            // Time's up?
    unsigned long t  = getTime(); // Query time server
    if(t) {                       // Success?
      lastPolledTime = t;         // Save time
      sketchTime = millis();
    }

I realized that the problem has to do with the sei() and cli() commands.

Yes, for most of the time in your sketch, interrupts are disabled and both millis() and Serial.print() functions rely upon interrupts being enabled.

NbTopsFan = 0;
sei();
delay(1000);
cli();
Cal = (NbTopsFan * 60 / 7.5);

Rather than using this interrupt managment and then collecting interrupt counts during a delay period it is better to use the architecture of "blink without delay" and to only disable interrupts to make a "protected" copy when reading the data out of the ISR. See Nick Gammon's excellent tutorial on how to use interrupts

Here's an example of how to read counts every second.

volatile unsigned long  count = 0;

unsigned long copyCount = 0;

unsigned long lastRead = 0;

unsigned long interval = 1000;

void setup()
{
  Serial.begin(115200);
  Serial.println("start...");

 pinMode(3,INPUT_PULLUP);
 attachInterrupt(1, isrCount, RISING);
}

void loop()
{
  if (millis() - lastRead >=interval) //read interrupt count every second
  {
    lastRead  += interval; //millis();
    // disable interrupts,make copy of count,reenable interrupts
    noInterrupts();
    copyCount = count;
    count = 0;
   interrupts(); 

   Serial.println(copyCount);
  }
}

void isrCount()
{
  count++;
}