Go Down

Topic: Ultrasonic sensor has long delay on LCD screen (Read 275 times) previous topic - next topic

A range sensor is reading distances. Just with the serial monitor, it works great. Although, now I need to have it output readings on an LCD screen. (There is a slide switch that enables this function.)

It wasn't outputting a display for the LCD screen. So I tried putting a delay with millis() in there:


Code: [Select]
#include <LiquidCrystal.h>
#include <TimeLib.h>

/*  LCD/menu  */
#define ENCODER_INTERRUPT_PIN 2 // MUST keep pin 2.
#define ENCODER_B_PIN A0
#define BUTTON_PIN A1
#define LCD_ENABLE_PIN 13
#define LCD_RS_PIN 12
#define HEART_BEAT_PIN A15
#define LCD_D1 5    // New ↓
#define LCD_D2 4
#define LCD_D3 3
#define LCD_D4 7
unsigned long timeoutTime = 0;  // this is set and compared to millis to see when the user last did something.
const int menuTimeout = 10000; // time to timeout in a menu when user doesn't do anything.
const int contrast = 20;    // min. PWM value

unsigned long startMillis;
unsigned long currentMillis;
unsigned long currentMillisA;
unsigned long currentMillisD;
unsigned long currentMillis1;
const unsigned long period = 1000;
const byte txPin3 = 14;
const byte rxPin3 = 15;
const byte txPin2 = 16;
const byte rxPin2 = 17;
const byte pinAnalog = 42;    // If high, reads voltage from A7.
const byte pinDigital = 44;   // Reads and displays range.
const byte pinOneWire = 46;   // Displays temp.
const byte oneWireBus = 31;
const byte pinAnalogW = 22;    //
const byte pinDigitalW = 24;   //
const byte pinOneWireW = 26;   //                        ----------------
const byte doAnalogW = 28;    // Sweeps voltage 0-5V to datalogger.
const byte doDigitalW = 30;   // Emulates range.
const byte doOneWireW = 32;   // Emulates temp.
volatile int diffFromParagon = 0;
volatile int inch = 0;
volatile int current_range_reading = -99;
volatile int incomingByte = 0;   // for incoming serial data
// volatile https://forum.arduino.cc/index.php?topic=418692.0

LiquidCrystal lcd( 12, 13, 5, 4, 3, 7); // Arduino pins. Creates object.
    // LCD:GND,5V(RS=2 en=3 11 12 13 14) 16=GND


void setup() {
  startMillis = millis();  // Initial start time
  Serial.begin(115200); // IMPORTANT: Set your serial monitor to this.
  Serial1.begin(9600);  // This is the baud rate needed for MaxBotics TTL sonar.
                        // RX1 pin 19
// LCD code:
  pinMode(8,HIGH);  // LCD pin 15: backlight (anode)
//  pinMode(11,OUTPUT);
//  analogWrite(11,700);
  analogWrite(6,contrast); // PWM~ pins: 3,5,(6),9,10,11
  lcd.begin(20, 4);  // Creates LCD object.

// pinMode not needed for INPUT (default) operator
  pinMode(doAnalogW, OUTPUT);
  pinMode(doDigitalW, OUTPUT);
  pinMode(doOneWireW, OUTPUT);
  pinMode(15, OUTPUT);
  pinMode(2, OUTPUT);

  pinMode(pinAnalog, INPUT_PULLUP);
  pinMode(pinDigital, INPUT_PULLUP);
  pinMode(pinOneWire, INPUT_PULLUP);
  pinMode(pinAnalogW, INPUT_PULLUP);
  pinMode(pinDigitalW, INPUT_PULLUP);
  pinMode(pinOneWireW, INPUT_PULLUP);

  delay(1500);          // For LCD screen to boot up.
  lcd.setCursor(0, 0);
  lcd.print("Welcome.");
  lcd.setCursor(0, 1);
  lcd.print("Ready, make choice");
  lcd.setCursor(0, 2);
  lcd.print("by flipping switch.");
  lcd.setCursor(0, 3);
  lcd.print("Flip back when done."); 
}

void loop(){
 
  byte digitalSelection = digitalRead(pinDigital); // 44
  currentMillis = millis();
 
  if(digitalSelection == HIGH)
    digitalR();
}

void digitalR(){
 lcd.clear();
 
 if (Serial1.available() > 5)  // Then at least one complete range, 6 characters long, is stored in the RX buffer.
  {
    int inByte = Serial1.read(); // Examine the first stored character and decide what to do.

    if(inByte == 'R')
    {
      int thousands = (Serial1.read() - '0') * 1000; // Take and convert each range digit to human-readable integer format.
      int hundreds = (Serial1.read() - '0') * 100;
      int tens = (Serial1.read() - '0') * 10;
      int units = (Serial1.read() - '0') * 1;
      int cr = Serial1.read(); // Don't do anything with this, just clear it out of the buffer with the rest.
     
      // Assemble the digits into the range integer.
      current_range_reading = thousands + hundreds + tens + units;
      if(current_range_reading <= 300) //This is the minimum reading for the HRXL MaxSonar WR 7380, not the actual distance
      {
        while(millis() < currentMillis + 500)
        {       
        Serial.println("too close!");
        lcd.print("too close!");
        }       
      }
      else if(current_range_reading >= 5000) //This is the max reading for the HRXL MaxSonar WR 7380, not the actual distance
      {
        while(millis() < currentMillis + 500)
        {
        Serial.println("too close!");
        lcd.print("too close!");
        }
      }
      else
      {
        while(millis() < currentMillis + 500)
        {
        Serial.print("Range (mm): ");
        Serial.println(current_range_reading);

        lcd.print("Range (mm): ");
        lcd.println(current_range_reading);
        }       
      }
    }
  }
}


Attached is a text document that includes the Serial Monitor's output. I had it run regularly (reading a good 764 mm) for two seconds. Then put my hand under the sensor (should have read "too close!") for two seconds. Then I took my hand away, and just got garbage readings for the next ten seconds. (So the text document is 14 seconds of reading.)

For a time, it says it's reading 3407 mm, 1040 mm and 3403 mm. Although, that's impossible; 764 mm is the max I have set up.

I think it's an issue with timing (using millis). But I don't know what to fix!

So it looks like I wasn't clear.

The Serial Monitor alone works. It takes readings correctly.

When I put the timing delay in, it doesn't appear to be reading correctly: there are widely inaccurate readings occurring. And there is a big long delay.

I would like to eventually just use the LCD screen, but it didn't work when I switched Serial.println() to lcd.println() anyway. So I'm just trying to get the Serial Monitor working first (even though it's only a means to a different goal).

PaulS

Code: [Select]
    int inByte = Serial1.read();
Why are you using a type in the name of a variable, when the type in the name is not the type OF the variable? Have you no imagination? There are billions of names you could have used...

Code: [Select]
        while(millis() < currentMillis + 500)
        {       
        Serial.println("too close!");
        lcd.print("too close!");
        } 

Where did you assign a value to currentMillis? Nowhere near this code, so it can't be all that current...

Why do you need to send the serial port and the LCD the same info over and over and over.?

It looks to me like you are using millis() to implement your own version of delay. That is NOT how it is meant to be used.
The art of getting good answers lies in asking good questions.

It looks to me like you are using millis() to implement your own version of delay. That is NOT how it is meant to be used.
I read that delay() stops everything else (besides the delay). And I can't have that happen. If not millis(), then how do I take less frequent readings?

PaulS

You take readings when the time between now and the last time you took one exceeds the time between readings, just like the blink without delay example shows.
The art of getting good answers lies in asking good questions.

So I do need to use millis(). It sounded like you were saying I wasn't supposed to use it.

Also, your tone is insulting. I understand the concept one trying to help another person. But you don't have to be rude about it.

Go Up