UltraSonic Sensor with LCD and Motor if statement

So, I am making a project where there is an UltraSonic sensor that detects how far away the object it is looking at is. then displays it on an LCD for nice visual appeal. Also, I want to turn on a motor if the object the sensor detects is within a range of 3 cm or so. I got the first part down, but I need help with the motor bit. When I write the code in a separate file, everything works fine, but when I incorporate it into my LCD script, nothing happens. The motor processor blinks with its lights, but the motor doesn’t spin. I think it’s because of the delays not corresponding. Any idea on how to incorporate the components? Thanks.

Motor Model: 28BYJ-48

SensorTest.ino (2.93 KB)

please post code, wiring diagram, and motor model

what software is there for the wiring diagram? I'm a noob

You can draw it out on a piece of paper, take a picture of the paper, then post it here, following this guide:

Can you change the echo pin to pin 2 or 3?

If so try this out.

#include <LiquidCrystal.h>


LiquidCrystal lcd(1, 2, 4, 5, 6, 7); // Creates an LCD object. Parameters: (rs, enable, d4, d5, d6, d7)

int Pin1 = 11;
int Pin2 = 12;
int Pin3 = 13;
int Pin4 = 14;
int _step = 0;
boolean dir = true;// false=clockwise, true=counter clockwise
int count = 0;

const int trigPin = 9;
const int echoPin = 10;
unsigned long duration;
int distanceCm, distanceInch;

void turn() {

  switch (_step) {
    case 0:
      digitalWrite(Pin1, LOW);
      digitalWrite(Pin2, LOW);
      digitalWrite(Pin3, LOW);
      digitalWrite(Pin4, HIGH);
      break;
    case 1:
      digitalWrite(Pin1, LOW);
      digitalWrite(Pin2, LOW);
      digitalWrite(Pin3, HIGH);
      digitalWrite(Pin4, HIGH);
      break;
    case 2:
      digitalWrite(Pin1, LOW);
      digitalWrite(Pin2, LOW);
      digitalWrite(Pin3, HIGH);
      digitalWrite(Pin4, LOW);
      break;
    case 3:
      digitalWrite(Pin1, LOW);
      digitalWrite(Pin2, HIGH);
      digitalWrite(Pin3, HIGH);
      digitalWrite(Pin4, LOW);
      break;
    case 4:
      digitalWrite(Pin1, LOW);
      digitalWrite(Pin2, HIGH);
      digitalWrite(Pin3, LOW);
      digitalWrite(Pin4, LOW);
      break;
    case 5:
      digitalWrite(Pin1, HIGH);
      digitalWrite(Pin2, HIGH);
      digitalWrite(Pin3, LOW);
      digitalWrite(Pin4, LOW);
      break;
    case 6:
      digitalWrite(Pin1, HIGH);
      digitalWrite(Pin2, LOW);
      digitalWrite(Pin3, LOW);
      digitalWrite(Pin4, LOW);
      break;
    case 7:
      digitalWrite(Pin1, HIGH);
      digitalWrite(Pin2, LOW);
      digitalWrite(Pin3, LOW);
      digitalWrite(Pin4, HIGH);
      break;
    default:
      digitalWrite(Pin1, LOW);
      digitalWrite(Pin2, LOW);
      digitalWrite(Pin3, LOW);
      digitalWrite(Pin4, LOW);
      break;
  }
  if (dir) {
    _step++;
  }
  else {
    _step--;
  }
  if (_step > 7) {
    _step = 0;
  }
  if (_step < 0) {
    _step = 7;
  }
  delay(1);

}

volatile unsigned long PingTime; // Pins 0 and 1 are ignored we are wasting 2 longs of memory
volatile int GotData;
void PingItPin2() {
  PingIT(2);
}
void PingItPin3() {
  PingIT(3);
}

// This function fills an array of 10 Ping readings for up to 2 Ping Sensors
// The array is filled with First in First out. FIFO buffer which we will add and divide by 10
void PingIT(int PingPin) {
  static unsigned long EdgeTime;
  unsigned long cTime = micros();
  if (digitalRead(PingPin)) {
    EdgeTime = cTime; //Pulse went HIGH store the start time
  } else {                         // Pulse Went low calculate the duratoin
    PingTime = cTime - EdgeTime; // Calculate the change in time
    GotData++;
  }
}

void setup() {

  pinMode(Pin1, OUTPUT);
  pinMode(Pin2, OUTPUT);
  pinMode(Pin3, OUTPUT);
  pinMode(Pin4, OUTPUT);
  lcd.begin(16, 2); // Initializes the interface to the LCD screen, and specifies the dimensions (width and height) of the display
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(2), PingItPin2, CHANGE);
  attachInterrupt(digitalPinToInterrupt(3), PingItPin3, CHANGE);

}

void loop() {
  int GotSomeData;
  // Lets trigger your ultrasound sensor
  static unsigned long TriggerTimer;
  if ((millis() - TriggerTimer) >= (10)) {
    TriggerTimer = millis();
// the ping sessor will not retrigger until the echo has returned so this is safe to fire the trigger pin at will.
// We are taking all measurements with the echo pin using interrupts!
    digitalWrite(trigPin, !digitalRead(trigPin)); // toggle the pin every 10ms
  }
  noInterrupts ();  // this will prevent crazy readings from appearing if an interrupt is about to occur
  GotSomeData = GotData;
  if(GotData) GotData = 0;
  interrupts ();

  if (GotSomeData) {
    GotSomeData = 0;
    noInterrupts (); // this will prevent crazy readings from appearing if an interrupt is about to occur
    duration = PingTime;
    interrupts ();
    distanceCm = duration * 0.034 / 2;
    distanceInch = distanceCm / 2.54;

// Coontroll your motors here

    static unsigned long LCDTimer;
    if ((millis() - LCDTimer) >= (100)) {  // LCD's don't like to be pushed too hard so this protects the LCD from getting spammed
      LCDTimer = millis();
// Update the LCD every 100ms

      lcd.setCursor(0, 0); // Sets the location at which subsequent text written to the LCD will be displayed
      lcd.print("Distance: "); // Prints string "Distance" on the LCD
      lcd.print(distanceCm); // Prints the distance value from the sensor
      lcd.print("  cm");
      lcd.setCursor(0, 1);
      lcd.print("Distance: ");
      lcd.print(distanceInch);
      lcd.print("inch");

    }
  }

}

used interrupts for Ping sensor readings.
Note: The traditional ping routine has a terrible blocking routine which makes you wait till the sound returns the interrupt method is simple and has no while loop to block your code.
used blink without delay for the Ping Sensor trigger.
used blink without delay for LCD Spamming.
we only control motors when we receive a new reading.

Missing timeout conditions when no data is received from Ping sensors.

Z

No, unfortunately I cannot

lwadde2007:
No, unfortunately I cannot

I have another solution but its complex using interrupts on other pins.
Are you willing to try?
Yes :slight_smile:
I have a library for this :slight_smile:

#include <LiquidCrystal.h>
#include "Interrupts.h"

InterruptsClass Interrupt;
LiquidCrystal lcd(1, 2, 4, 5, 6, 7); // Creates an LCD object. Parameters: (rs, enable, d4, d5, d6, d7)

int Pin1 = 11;
int Pin2 = 12;
int Pin3 = 13;
int Pin4 = 14;
int _step = 0;
boolean dir = true;// false=clockwise, true=counter clockwise
int count = 0;

const int trigPin = 9;
const int echoPin = 10;
unsigned long duration;
int distanceCm, distanceInch;

void turn() {

  switch (_step) {
    case 0:
      digitalWrite(Pin1, LOW);
      digitalWrite(Pin2, LOW);
      digitalWrite(Pin3, LOW);
      digitalWrite(Pin4, HIGH);
      break;
    case 1:
      digitalWrite(Pin1, LOW);
      digitalWrite(Pin2, LOW);
      digitalWrite(Pin3, HIGH);
      digitalWrite(Pin4, HIGH);
      break;
    case 2:
      digitalWrite(Pin1, LOW);
      digitalWrite(Pin2, LOW);
      digitalWrite(Pin3, HIGH);
      digitalWrite(Pin4, LOW);
      break;
    case 3:
      digitalWrite(Pin1, LOW);
      digitalWrite(Pin2, HIGH);
      digitalWrite(Pin3, HIGH);
      digitalWrite(Pin4, LOW);
      break;
    case 4:
      digitalWrite(Pin1, LOW);
      digitalWrite(Pin2, HIGH);
      digitalWrite(Pin3, LOW);
      digitalWrite(Pin4, LOW);
      break;
    case 5:
      digitalWrite(Pin1, HIGH);
      digitalWrite(Pin2, HIGH);
      digitalWrite(Pin3, LOW);
      digitalWrite(Pin4, LOW);
      break;
    case 6:
      digitalWrite(Pin1, HIGH);
      digitalWrite(Pin2, LOW);
      digitalWrite(Pin3, LOW);
      digitalWrite(Pin4, LOW);
      break;
    case 7:
      digitalWrite(Pin1, HIGH);
      digitalWrite(Pin2, LOW);
      digitalWrite(Pin3, LOW);
      digitalWrite(Pin4, HIGH);
      break;
    default:
      digitalWrite(Pin1, LOW);
      digitalWrite(Pin2, LOW);
      digitalWrite(Pin3, LOW);
      digitalWrite(Pin4, LOW);
      break;
  }
  if (dir) {
    _step++;
  }
  else {
    _step--;
  }
  if (_step > 7) {
    _step = 0;
  }
  if (_step < 0) {
    _step = 7;
  }
  delay(1);

}

volatile unsigned long PingTime; // Pins 0 and 1 are ignored we are wasting 2 longs of memory
volatile int GotData;

void setup() {
  pinMode(Pin1, OUTPUT);
  pinMode(Pin2, OUTPUT);
  pinMode(Pin3, OUTPUT);
  pinMode(Pin4, OUTPUT);
  lcd.begin(16, 2); // Initializes the interface to the LCD screen, and specifies the dimensions (width and height) of the display
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  Interrupt.onInterrupt([ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    sei(); // re enable other interrupts at this point,
    Interrupt.PinCallBack(Time, PinsChanged, Pins);
  });
  Interrupt.onPin(echoPin, INPUT, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    unsigned int PingTime = Interrupt.Ping(echoPin, Time, Pins);
    if(PingTime) GotData = 1;
  });

}

void loop() {
  int GotSomeData;
  // Lets trigger your ultrasound sensor
  static unsigned long TriggerTimer;
  if ((millis() - TriggerTimer) >= (10)) {
    TriggerTimer = millis();
// the ping sessor will not retrigger until the echo has returned so this is safe to fire the trigger pin at will.
// We are taking all measurements with the echo pin using interrupts!
    digitalWrite(trigPin, !digitalRead(trigPin)); // toggle the pin every 10ms
  }
  noInterrupts ();  // this will prevent crazy readings from appearing if an interrupt is about to occur
  GotSomeData = GotData;
  if(GotData) GotData = 0;
  interrupts ();

  if (GotSomeData) {
    GotSomeData = 0;
    noInterrupts (); // this will prevent crazy readings from appearing if an interrupt is about to occur
    duration = PingTime;
    interrupts ();
    distanceCm = duration * 0.034 / 2;
    distanceInch = distanceCm / 2.54;

// Coontroll your motors here

    static unsigned long LCDTimer;
    if ((millis() - LCDTimer) >= (100)) {  // LCD's don't like to be pushed too hard so this protects the LCD from getting spammed
      LCDTimer = millis();
// Update the LCD every 100ms

      lcd.setCursor(0, 0); // Sets the location at which subsequent text written to the LCD will be displayed
      lcd.print("Distance: "); // Prints string "Distance" on the LCD
      lcd.print(distanceCm); // Prints the distance value from the sensor
      lcd.print("  cm");
      lcd.setCursor(0, 1);
      lcd.print("Distance: ");
      lcd.print(distanceInch);
      lcd.print("inch");

    }
  }
}

My Interrupt library is attached
Z

P.S.
The attached interrupt library works on any pin including analog pins.

Warning!!! Some More Notes and possibly deer in headlights feeling lol sorry

in the above code lets try to go into detail:

  Interrupt.onInterrupt([ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    sei(); // re enable other interrupts at this point,
    Interrupt.PinCallBack(Time, PinsChanged, Pins);
  });
  Interrupt.onPin(echoPin, INPUT, [ = ](uint32_t Time, uint32_t PinsChanged, uint32_t Pins) {
    unsigned int PingTime = Interrupt.Ping(echoPin, Time, Pins);
    if(PingTime) GotData = 1;
  });

The two Functions:
onInterrupt (CallbackFunciton) and onPin take a function pointer for an argument just like attachInterrupts does
But instead of a function with no arguments, the onInterrupt function requires us to include 3 arguments an unsigned long called Time another unsigned long called PinsChanged and a third called Pins
This specific callback function just needs to trigger sei() and hand the values over to the PinCallBack function. in order to not defer any other interrupt more than absolutely needed. we trigger sei() which allows other interrupts to occur at this point while finishing the callback function.

Now onPin(PinNumber,INPUT or INPUT_PULLUP, CallbackFunction) handles the Setup and storing the CallBack function that is triggered after checking which if the assigned pin has actually interrupted the code.
The INPUT tells the arduino that it is an input The only other option is INPUT_PULLUP for this spot as OUTPUTwon’t trigger an interrupt correctly.
onPin function receives a function pointer for its argument this function requires us to include 3 arguments an unsigned long called Time another unsigned long called PinsChanged and a third called Pins Note that these are the same values received in the onInterrupt function. This function calls another function called Ping which I created to work with the ultrasonic ping unit. you could create your own here or elsewhere and call it from here. Ping needs to know which pin the Ultrasound is attached to the time the interrupt occurred and the states of all the pins at the time of the interrupt which contain the pin we need to see.

What is Time: this stores the exact time of the interrupt
What is PinsChanged: well it is a Long Integer 32 Bits with bit-0 representing pin 0, bit 1 representing Bit 1 and so forth it compares the state of each pin with the state of the pin on the last pass. any pin that has changed the bit is true.
What is Pins: This is a copy of all the pins current state at the time of the interrupt Bit0 = Pin 0, etc…

I’ve mentioned function pointers so what is all this ={C Code } thing stuck in the middle of our function :slight_smile:
Well, it is an anonymous function or what is called Lambda functions. It is triggered when another event occurs that we wish to do but we don’t know what that to do is yet. so we create a callback and ask you to provide a pointer to the function you wish us to run. Because we only need a pointer to a function and our function isn’t too complex, let’s give it a function with no name and define it right here so we know exactly what will happen and when.
Our good friend Nick here on Arduino.cc has done a wonderful job on describing callbacks and Lambda or anonymous functions here https://www.gammon.com.au/callbacks
also, a great reference is mentioned here: C++11 - Lambda Closures, the Definitive Guide - Cprogramming.com

Interrupts.cpp (6.5 KB)

Interrupts.h (5.54 KB)

What is the thing that is wrong with my code that makes it not work? When I try the motor bit individually, everything works fine. Even when I don't change the wiring. But when I add a simple if statement, nothing works. What's happening here?

In your attached code the only thing that would do anything with the motor is the function turn() which is never called from anywhere. That’s assuming that the stupidly named Pin1, Pin2 etc are something to do with the motor. If so then I’d say that explains why the motor isn’t doing anything.

Have you considered using a few comments to explain what’s connected where and what you think should be going on?

Steve