A place users can post their projects. If you have a small project and would like your own dedicated place to post and have others chat about it then this is your spot.

User avatar
By pi-xel
#6117 Hi folks,

playing arround with the ESP8266, I set up a small web-server on an chipkit UNO32.
Why UNO32. So it's more powerfull than the Arduino (80MHz, more RAM etc) at nearly the same price.
However, the development suit for the UNO32 based on the Arduino stuff.

I decided to implement a Finite State Machine (FSM).
The program has three parts:
Block #01: Reading from the ESP via serial.
Block #02: Check for key words and set the state.
Block #03: The FMS

My ESP comes with the firmware 0018000902-AI03.
There are some differences to the 0018000902 (e.g. AT+RST has response "[System ready .....]", AI03 sends "ready" at the end).
So, if you have 0018000902 you have tho change the keywords in #02.

To have a first use case, I connected a Ultrasonic ranging module HC-SR04 to measure the distance to an object.
There are a lot of descriptions of the modul available, so I will not explain it here. Just search for HC-SR04.

The hardware connections are as follows:
UNO32 ESP
pin0/RX TX
pin1/TX RX
GND GND
3,3V 3,3V
pin3 CH_PD


UNO32 RS232
pin6/soft RX Terminal/TX
pin7/soft TX Terminal/RX

UNO32 HC-SR04
pin12 HC-SR04 Trigger
pin13 HC-SR04 Echo
GND HC-SR04 GND
+5V HC-SR04 Vcc

Code: Select all// *** ESP8266 with UNO32 and ultrasonic ranging modul - small web server
// For ESP Firmware 0018000902-AI03
// Server with state machine due to AT commands
// (c) THI 2015-02-01
// Program has three blocks:
// #01 receiving data from ESP serial
// #02 evaluating data comming from ESP and setting states
// #03 FSM to step through the commands you want to send and wait for right response (#01 will be still executed)
//     and send feedback e.g. to "GET / "
// Known bugs ore incomplete stuff:
// (1) +CIPCLOSE will not be executed correctly with 0018000902-AI03, sometimes ESP reboots,
//     00180001902 seems to be more stable. But I didn't explore this further.
// (2) Handling for multible connctions not propperly implemented.
// (3) Buffer overflow is not handled.
// (4) Getting a request from a browser (e.g. /favicon.ico) is not handled.
//     At the moment, connection will be closed without sending 404 or something else.

   
    #include <SoftwareSerial.h>
   
// Hardware settings for ESP8266
    #define rxPin 6
    #define txPin 7
    SoftwareSerial dbgTerminal(rxPin, txPin); // RX, TX
    HardwareSerial & espSerial = Serial;

    // set pin numbers:
    // the number of the LED pin
    const int ledPin =  43;
    const int ESP8266_CHPD = 3;
// End of hardware settings   

// Settings for SR04
// Digital 12 -> HC-SR04 Trigger
// Digital 13 -> HC-SR04 Echo
// GND -> HC-SR04 GND
// +5V -> HC-SR04 Vcc
    int pingPin = 12;  // Digital 13 -> HC-SR04 Trigger
    int inPin = 13;  // Digital 12 -> HC-SR04 Echo
   
    // timeout couter
    long lmillis;
    long loldmillis;
    int iticks = 0;

    // Variables will change:
    int ledState = HIGH;             // ledState used to set the LED

    // vars for loop
    int bLen = 0;
    int idatastop = 0;
    char c;
    char charVal[2];
   
    // definition of states for #01 and #02
    #define LINENOTCOMPLETE 0
    #define LINEAVAILABLE 1
    #define LINEPROCESSED 2
    byte readstate = LINENOTCOMPLETE;
    int iLinkCounter = 0;
   
    // States for state machine #02
    enum R_State {R_Data, R_OK, R_DATAOK, R_Link, R_Unlink, R_nochange, R_busy, R_ERROR, R_ready, R_none, R_processed, R_linkisnot};
    enum W_State {W_WaitForDataOK, W_none};
   
    // current state of state machine #03
    // starting with 0
    // Initial state can not be set here -> using the struct outside of a function fails (-> namespace)
    int oldbState = 255;
   
    typedef struct {
      int bState; // Status for switch/case #03
      int oldbState;
      R_State rState; // Receive status für #02
      W_State wState; // WaitState in case of data received, now wait for appropriate OK in #02 and #03
      int ch_id; // current channel id of data received
    } Statusstruct;
   
    // Stack for multible connections / messages received
    Statusstruct S_Stack[3];
    int pPointerS = 0;
   
    // my network parameters
    String NetworkSSID = "yourSSID";
    String NetworkPASS = "yourPASS";

    #define BUFFER_SIZE 512
    // buffer for AT communication
    char buffer[BUFFER_SIZE];
    // buffer for received data via +IPD
    char databuffer[BUFFER_SIZE];

    void setup() {
      pinMode(rxPin, INPUT);
      pinMode(txPin, OUTPUT);
      pinMode(ledPin, OUTPUT);
      pinMode(ESP8266_CHPD, OUTPUT);

      dbgTerminal.begin(19200); // Serial monitor
      espSerial.begin(9600); // ESP8266

      // Chip wake up
      digitalWrite(ESP8266_CHPD, HIGH); // set CH_PD HIGH
      delay(200);

      //while (!dbgTerminal) {
      // ; // wait for serial port to connect. Needed for Leonardo only
      //}

      dbgTerminal.println("ESP8266 Server.");

      //hardReset();
      //delay(2000);

      clearSerialBuffer();

      // Initialize status stack adn first state
      S_Stack[0].bState = 0;
      S_Stack[0].oldbState = 255;
      S_Stack[0].rState = R_none; // Receive status für #02
      S_Stack[0].wState = W_none; // WaitState in case of data received, now wait for appropriate OK in #02 and #03
      S_Stack[0].ch_id = 0; // current channel id of data received

      // digitalWrite(ledPin,ledState);
    }

    // main loop
    void loop() {
      int ch_id, packet_len;
      char *pb;
     
     
      // #01: read from ESP
      if (espSerial.available() >0 )  {
        c = espSerial.read();
        buffer[bLen] = c;
        // sprintf(charVal, "%02X", buffer[bLen]);
        // dbgTerminal.print(charVal);
        bLen++;
       
        // Read until 0x0A is received
        // todo: avoid buffer overflow       
        if ((c == 0x0A))
        {
          buffer[bLen] = 0;
          dbgTerminal.print(buffer);
          idatastop = bLen;
          bLen = 0;
          readstate = LINEAVAILABLE;
        }
      }
 
      // #02: check for keyword received
      if (readstate == LINEAVAILABLE) {

        char* cchecked;
        int imessLen, ireadLen;
        int idatawrite = 0;

        if(cchecked = strstr(buffer, "+IPD,")) {
        // "+IPD," -----------------------------------------------------
          // request: +IPD,ch,len:data
          sscanf(cchecked+5, "%d,%d", &ch_id, &packet_len);

          // S_Stack[pPointerS].ch_id = ch_id;

          // read rest of message
          // calculate length of rest
          cchecked = strstr(buffer, ":");
          cchecked++;
          imessLen = strlen(cchecked);

          ireadLen = packet_len - imessLen;
         
          // copy data into data buffer
          while (idatawrite < imessLen) {
            databuffer[idatawrite] = cchecked[idatawrite];
            idatawrite++;
          }

          // read rest of data received
          // todo: avoid buffer overflow
          while (ireadLen > 0)  {
            if (espSerial.available() >0 )  {
              c = espSerial.read();
              databuffer[idatawrite] = c;
              ireadLen--;
              idatawrite++;
            }
          }
          databuffer[idatawrite] = 0;
          dbgTerminal.println("--- start of data received ---");
          // dbgTerminal.print(buffer);
          dbgTerminal.print(databuffer);
          dbgTerminal.println("--- end of data received ---");
         
          // Increment status stack if we are not waiting for data (state 170)
          // this means that the ESP got one more connection         
          if ( S_Stack[pPointerS].bState != 170) {
            pPointerS++;
            S_Stack[pPointerS].oldbState = S_Stack[pPointerS-1].bState;
            S_Stack[pPointerS].rState = R_Data;
            S_Stack[pPointerS].wState = W_none;
            S_Stack[pPointerS].ch_id = ch_id;
            S_Stack[pPointerS].bState = 170;           
           
          } else {
            S_Stack[pPointerS].rState = R_Data;
            S_Stack[pPointerS].ch_id = ch_id;           
          }
         
          dbgTerminal.print("SPointer: ");
          dbgTerminal.println(pPointerS);
       
       
        } else if ((cchecked = strstr(buffer, "OK")) && (strlen(buffer) == 4)) {
          // "OK" ------------------------------------------------------
          if (S_Stack[pPointerS].wState == W_WaitForDataOK)
            S_Stack[pPointerS].rState = R_DATAOK; // marks if OK comes from received data via session
          else
            S_Stack[pPointerS].rState = R_OK;
         
        } else if ((cchecked = strstr(buffer, "SEND OK")) && (strlen(buffer) == 9)) {
          // "OK" ------------------------------------------------------
          S_Stack[pPointerS].rState = R_OK;
         
        } else if ((cchecked = strstr(buffer, "link is not")) && (strlen(buffer) == 13)) {
          // "OK" ------------------------------------------------------
          S_Stack[pPointerS].rState = R_linkisnot;
         
        } else if (cchecked = strstr(buffer, "Link")) {
          // "Link" ------------------------------------------------------
          S_Stack[pPointerS].rState = R_Link;
          iLinkCounter++;
         
        } else if (cchecked = strstr(buffer, "Unlink")) {
          // "Unlink" ------------------------------------------------------
          S_Stack[pPointerS].rState = R_Unlink;
          iLinkCounter--;
         
        } else if (cchecked = strstr(buffer, "ERROR")) {
          // "ERROR" ------------------------------------------------------
          S_Stack[pPointerS].rState = R_ERROR;
         
        } else if (cchecked = strstr(buffer, "ready")) {
          // "ready" ------------------------------------------------------
          S_Stack[pPointerS].rState = R_ready;
          // S_Stack[pPointerS].bState = 1;
         
        } else if (cchecked = strstr(buffer, "busy")) {
          // "busy" ------------------------------------------------------
          S_Stack[pPointerS].rState = R_busy;
         
        } else if (cchecked = strstr(buffer, "no change")) {
          // "no change" ------------------------------------------------------
          S_Stack[pPointerS].rState = R_nochange;
         
        } else {
          S_Stack[pPointerS].rState = R_none;
         
        }
       
       
        readstate = LINEPROCESSED;
      };


      // #03: state machine
      lmillis = millis();
      if (loldmillis > lmillis) { // overflow
        loldmillis = lmillis; 
      }
      if (lmillis > loldmillis + 1000) {
        iticks++;
        loldmillis = lmillis;
        digitalWrite(ledPin, ledState); // show lifesign
        ledState = !ledState;
      }
     
      if (oldbState != S_Stack[pPointerS].bState) {
        dbgTerminal.print("new state: ");
        dbgTerminal.println((int) S_Stack[pPointerS].bState);
        oldbState = S_Stack[pPointerS].bState;
       
       // prepare timeout
       iticks = 0;;
      }
      switch (S_Stack[pPointerS].bState) {
        // panic
        case 0:
            espSerial.println("AT+RST");
            S_Stack[pPointerS].bState = 1;
            S_Stack[pPointerS].rState = R_processed;
          break;
        // wait for response
        case 1:
          if (S_Stack[pPointerS].rState == R_ready) {
            dbgTerminal.println("Reset done");
            S_Stack[pPointerS].bState = 10;
            S_Stack[pPointerS].rState = R_none;
          } // todo: case of error e.g. goto state 0
        break;       
        // show version info
        case 10:
            espSerial.println("AT+GMR");
            S_Stack[pPointerS].bState = 11;
            S_Stack[pPointerS].rState = R_processed;
          break;
        // wait for response
        case 11:
          if (S_Stack[pPointerS].rState == R_OK) {
            S_Stack[pPointerS].bState = 12;
            S_Stack[pPointerS].rState = R_none;
          } // todo: case of error e.g. goto state 0
        break;       
        // allow multible connections, must be set before start of server
        case 12:
            espSerial.println("AT+CIPMUX=1");
            S_Stack[pPointerS].bState = 13;
            S_Stack[pPointerS].rState = R_processed;
          break;
        // wait for response
        case 13:
          if (S_Stack[pPointerS].rState == R_OK) {
            S_Stack[pPointerS].bState = 14;
            S_Stack[pPointerS].rState = R_none;
          } // todo: case of error e.g. goto state 0
        break;       
        // activate client mode, muist be set before start of server
        case 14:
            espSerial.println("AT+CWMODE=1");
            S_Stack[pPointerS].bState = 15;
            S_Stack[pPointerS].rState = R_processed;
          break;
        // wait for response
        case 15:
          if ((S_Stack[pPointerS].rState == R_OK) || (S_Stack[pPointerS].rState == R_nochange)){
            S_Stack[pPointerS].bState = 90;
            S_Stack[pPointerS].rState = R_none;
          } // todo: case of error e.g. goto state 0
        break;       
        // connect to router
        case 90:       
          if (S_Stack[pPointerS].rState == R_none) {
            String cmd = "AT+CWJAP=\"";
            cmd += NetworkSSID;
            cmd += "\",\"";
            cmd += NetworkPASS;
            cmd += "\"";
            // cmd = "AT+CWJAP";
            espSerial.println(cmd);
            S_Stack[pPointerS].bState = 91;
            S_Stack[pPointerS].rState = R_processed;
          }
          break;
        // wait for response
        case 91:
          if (S_Stack[pPointerS].rState == R_OK) {
            S_Stack[pPointerS].bState = 100;
            S_Stack[pPointerS].rState = R_processed;
          } // todo: case of error e.g. goto state 0
        break;       
        // send AT - just for fun
        case 100:       
          if (S_Stack[pPointerS].rState == R_processed) {
            espSerial.println("AT");
            S_Stack[pPointerS].bState = 101;
            S_Stack[pPointerS].rState = R_processed;
          }
          break;
        // wait for response
        case 101:
          if (S_Stack[pPointerS].rState == R_OK) {
            S_Stack[pPointerS].bState = 110;
            S_Stack[pPointerS].rState = R_processed;
          } // todo: case of error e.g. goto state 0
        break;       
        // ask for baud rate
        case 110:       
          if ((S_Stack[pPointerS].rState == R_processed) || (S_Stack[pPointerS].rState == R_none)) {
            espSerial.println("AT+CIOBAUD?");
            S_Stack[pPointerS].bState = 111;
            S_Stack[pPointerS].rState = R_processed;
          }
          break;
        // wait for response
        case 111:
          if (S_Stack[pPointerS].rState == R_OK) {
            S_Stack[pPointerS].bState = 140;
            S_Stack[pPointerS].rState = R_processed;
          } // todo: case of error e.g. goto state 0
        break;       
        // not used
        case 120:       
          break;
        // wait for response
        case 121:
        break;       
        // not used
        case 130:       
          break;
        // wait for response
        case 131:
        break;       
        case 140:
          // start server       
          if ((S_Stack[pPointerS].rState == R_processed) || (S_Stack[pPointerS].rState == R_none)) {
            espSerial.println("AT+CIPSERVER=1,8888");
            S_Stack[pPointerS].bState = 141;
            S_Stack[pPointerS].rState = R_processed;
          }
          break;
        // wait for response
        case 141:
          if (S_Stack[pPointerS].rState == R_OK) {
            S_Stack[pPointerS].bState = 150;
            S_Stack[pPointerS].rState = R_processed;
          } // todo: case of error e.g. goto state 0
        break;       
        case 150:
           // set timeout for server       
          if ((S_Stack[pPointerS].rState == R_processed) || (S_Stack[pPointerS].rState == R_none)) {
            espSerial.println("AT+CIPSTO=15");
            S_Stack[pPointerS].bState = 151;
            S_Stack[pPointerS].rState = R_processed;
          }
          break;
        // wait for response
        case 151:
          if (S_Stack[pPointerS].rState == R_OK) {
            S_Stack[pPointerS].bState = 160;
            S_Stack[pPointerS].rState = R_processed;
          } // todo: case of error e.g. goto state 0
        break;       
        case 160:
           // request ip address       
          if ((S_Stack[pPointerS].rState == R_processed) || (S_Stack[pPointerS].rState == R_none)) {
            espSerial.println("AT+CIFSR");
            S_Stack[pPointerS].bState = 161;
            S_Stack[pPointerS].rState = R_processed;
          }
          break;
        // wait for response
        case 161:
          if ((S_Stack[pPointerS].rState == R_OK)|| (iticks > 10)) {
            S_Stack[pPointerS].bState = 170;
            S_Stack[pPointerS].rState = R_processed;
            dbgTerminal.println("Server online");
          } // todo: case of error e.g. goto state 0
        break;       
        case 170:
           // server ready - waiting for requests
          if (S_Stack[pPointerS].rState == R_Data) {
            // read data from request
            // todo: request is complete if empty line has been received
            if (strstr(databuffer,"GET / ")) {
              // change state if "GET / " request has been detected
              S_Stack[pPointerS].bState = 171;
            } else {
              // request is not valid - wait for end of request - then close session
              S_Stack[pPointerS].bState = 175;
            }
            S_Stack[pPointerS].rState = R_processed;
            S_Stack[pPointerS].wState = W_WaitForDataOK;
          }
          break;
        // wait for response
        case 171:
          if ((S_Stack[pPointerS].rState == R_DATAOK) || (iticks > 10)) {
            S_Stack[pPointerS].bState = 172;
            S_Stack[pPointerS].rState = R_processed;
            S_Stack[pPointerS].wState = W_none;
           
            // if we have received an intermediate data packet recover status stack
            if (pPointerS > 0)
              pPointerS--;
          } // todo: case of error e.g. goto state 0
          break;
        case 172:
           // send data
          if (S_Stack[pPointerS].rState == R_processed) {
            String Header, Content;
            gethomepage(&Header, &Content);
            // todo: request is complete if empty line has been received
            espSerial.print("AT+CIPSEND=");
            espSerial.print(S_Stack[pPointerS].ch_id);
            espSerial.print(",");
            espSerial.println(Header.length()+Content.length());

            if (espSerial.find(">")) {
              // todo: if we send more bytes than buffer length, then we have to read from ESP
              // because data sent will be echoed to buffer via serial
              espSerial.print(Header);
              espSerial.print(Content);
              S_Stack[pPointerS].bState = 173;
              S_Stack[pPointerS].rState = R_processed;
            }

          }
          break;
        // wait for response
        case 173:
          if ((S_Stack[pPointerS].rState == R_OK) || (iticks > 10)){
            S_Stack[pPointerS].bState = 170;
            S_Stack[pPointerS].rState = R_processed;
          } // todo: case of error e.g. goto state 0
        break;       
        // wait for response but then close session because request will not be handled
        case 175:
          if ((S_Stack[pPointerS].rState == R_DATAOK) || (iticks > 10)){
            S_Stack[pPointerS].bState = 180;
            S_Stack[pPointerS].rState = R_processed;
            S_Stack[pPointerS].wState = W_none;
            // if (pPointerS > 0)
              // pPointerS--;

          } // todo: case of error e.g. goto state 0
          break;
        // close session
        // todo: until now, not used, because ESP crashes if our response contain "Connection: close"
        // and we want to close the session. Firefox closes then automatically.
        case 180:
          if (S_Stack[pPointerS].rState == R_processed) {
            S_Stack[pPointerS].bState = 181;
            S_Stack[pPointerS].rState = R_processed;
            espSerial.print("AT+CIPCLOSE="); // close all - but it is still unstable
            // espSerial.println("AT+CIPSTATUS");
            espSerial.println(S_Stack[pPointerS].ch_id);
            // dbgTerminal.println("Command finished");
          } // todo: case of error e.g. goto state 0
        break;       
        // wait for response
        case 181:
          if ((S_Stack[pPointerS].rState == R_OK) || (S_Stack[pPointerS].rState == R_linkisnot) || (iticks > 10)) {
            S_Stack[pPointerS].bState = 170;
            S_Stack[pPointerS].rState = R_processed;
            // if we have received an intermediate data packet recover status stack
            if (pPointerS > 0)
              pPointerS--;
          } // todo: case of error e.g. goto state 0
        break;       
         
        default:
        ;
      } // end of switch #03
     
    } // end of loop()

    // create response for valid request
    void gethomepage(String* Header, String* Content) {

      char outputString[25];  // for result of supersonic modul
      readdistance(outputString);

      *Header =  "HTTP/1.1 200 OK\r\n";
      *Header += "Content-Type: text/html\r\n";
      *Header += "Connection: close\r\n";
      //Header += "Refresh: 5\r\n";

      *Content = "<html>\r\n<body>\r\n";
      *Content += "Distance:\r\n";
      // *Content += String(ledState);
      *Content += outputString;
      *Content += "\r\n</body>\r\n</html>\r\n";

      *Header += "Content-Length: ";
      *Header += (int)((*Content).length());
      *Header += "\r\n\r\n";

    }

    // create response for not valid request
    void geterrorresponse(String* Header, String* Content) {

      *Header =  "HTTP/1.1 404 Not Found\r\n";
      *Header += "Content-Type: text/html\r\n";
      *Header += "Connection: close\r\n";
      //Header += "Refresh: 5\r\n";

      *Content = "<html>\r\n<body>\r\n";
      *Content += "\r\n</body>\r\n</html>\r\n";

      *Header += "Content-Length: ";
      *Header += (int)((*Content).length());
      *Header += "\r\n\r\n";

    }

    // hardware reset of ESP
    boolean hardReset() {
      String tmpData;

      digitalWrite(ESP8266_CHPD,LOW);
      delay(100);
      digitalWrite(ESP8266_CHPD,HIGH);
      delay(1000);

      while ( espSerial.available() > 0 ) {
        char c = espSerial.read();
        tmpData +=c;
        espSerial.write(c);
        if ( tmpData.indexOf("ready") > -1 ) {
          clearBuffer();
          return 1;
        }
      }
    }

    // clear serial from ESP
    void clearSerialBuffer(void) {
      while ( espSerial.available() > 0 ) {
        espSerial.read();
      }
    }

    // clear serial buffer
    void clearBuffer(void) {
      for (int i =0;i<BUFFER_SIZE;i++ ) {
        buffer[i]=0;
      }
    }

  void readdistance(char sResult[]) {
    // establish variables for duration of the ping,
    // and the distance result in inches and centimeters:
    long duration;
    long inches, cm;

    // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
    // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
    pinMode(pingPin, OUTPUT);
    digitalWrite(pingPin, LOW);
    delayMicroseconds(2);
    digitalWrite(pingPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(pingPin, LOW);
 
    // The same pin is used to read the signal from the PING))): a HIGH
    // pulse whose duration is the time (in microseconds) from the sending
    // of the ping to the reception of its echo off of an object.
    pinMode(inPin, INPUT);
    duration = pulseIn(inPin, HIGH);

    // convert the time into a distance
    inches = microsecondsToInches(duration);
    cm = microsecondsToCentimeters(duration);

    // Serial.println(cm, DEC);
    sprintf(sResult,"%04i cm",cm);
 
  }

  long microsecondsToInches(long microseconds)
  {
    // According to Parallax's datasheet for the PING))), there are
    // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
    // second).  This gives the distance travelled by the ping, outbound
    // and return, so we divide by 2 to get the distance of the obstacle.
    return microseconds / 74 / 2;
  }
 
  long microsecondsToCentimeters(long microseconds)
  {
    // The speed of sound is 340 m/s or 29 microseconds per centimeter.
    // The ping travels out and back, so to find the distance of the
    // object we take half of the distance travelled.
    return microseconds / 29 / 2;
  }


Attention:
Before using HardwareSerial.find of the UNO32 you have to patch
the pic32 library code pic32/cores/pic32/Stream.cpp as follows:
Code: Select all   
// find returns true if the target string is found
bool  Stream::find(char *target)
   {
        // THI return findUntil(target, NULL);
        return findUntil(target, strlen(target), NULL, 0);
   }




May be next steps are
- reconnect if connection to network has been interrupted
- FSM driven by a table
- handle other HTTP-requests (e.g. 404)

So, have fun playing with it and feel free to make changes.
Last edited by pi-xel on Tue Jan 13, 2015 5:39 pm, edited 1 time in total.
User avatar
By pi-xel
#6356 Hi Folks,

the first readings of the SR04 module are not accurate.
So the first readings should be discarded.

Here are the changes for the function readdistance:
Code: Select all   
    int iCount = 3;
    while (iCount > 0) {
      // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
      // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
      pinMode(pingPin, OUTPUT);
      digitalWrite(pingPin, LOW);
      delayMicroseconds(2);
      digitalWrite(pingPin, HIGH);
      delayMicroseconds(10);
      digitalWrite(pingPin, LOW);
 
      // The same pin is used to read the signal from the PING))): a HIGH
      // pulse whose duration is the time (in microseconds) from the sending
      // of the ping to the reception of its echo off of an object.
      pinMode(inPin, INPUT);
      duration = pulseIn(inPin, HIGH);
      delay(100);
      iCount--;
    }


Now, I'm using the hardware to read the water line of my cistern.

Regards
pi-xel