DIY Motion Detection Alarm System

I'm working on the " DIY Motion Detection Alarm System Using PIR Sensor, I2C LCD, and Piezo Buzzer" from the Arduino website:

I'm getting the following error message when I verify the program:
Error message 1




#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd (0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

int pirPin = 2; // PIR sensor connected to digital pin 2
int buzzerPin = 7; // Piezo sensor connected to digital pin 7

void setup (){
  pinMode (pirPin, INPUT);
  pinMode (buzzerPin, OUTPUT);
  lcd.begin (16,2); // Set up the LCD's number of columns and rows
  lcd.backlight(); // Turn on the backlight
  lcd.setCursor(0,0);
  lcd.print ("Motion detected");
  delay (2000);
}

void loop (){
  int motion  = digitalRead(pirPin);

  if (motion == HIGH){
    lcd.clear();
    lcd.setCursor (0,0);
    lcd.print ("Intruder alert!");
    tone (buzzerPin, 1000); // Emit a 1kHz tone
    delay (1000); //sound the buzzer for 1 second
    noTone (buzzerPin); // Stops the buzzer
  }
else {
  lcd.clear();
  lcd.print ("Monitoring...");
  delay (500);
  }
}

Check the sample code, that is extremely wrong for I2C. Look at the sample Hello World for correct code.

I thought something was off, but I checked several times that I had copied the coding exactly.

Here's what is written on the web page:


#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
int pirPin = 2; // PIR sensor connected to digital pin 2
int buzzerPin = 7; // Piezo buzzer connected to digital pin 7

void setup() {
  pinMode(pirPin, INPUT);
  pinMode(buzzerPin, OUTPUT);
  lcd.begin(16, 2); // Set up the LCD's number of columns and rows   
  lcd.backlight(); // Turn on the backlight
  lcd.setCursor(0, 0);
  lcd.print("Motion Detector");
  delay(2000);
}

void loop() {
  int motion = digitalRead(pirPin);
  
  if (motion == HIGH) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Intruder Alert!");
    tone(buzzerPin, 1000); // Emit a 1kHz tone
    delay(1000); // Sound the buzzer for 1 second
    noTone(buzzerPin); // Stop the buzzer
  }
  else{
    lcd.clear();
    lcd.print("Monitoring...");
    delay(500);
  }
}

You are using the I2C library but the object is using SPI. Did you look at the sample?
I am feeling generous tonight so here is the correct code.

NOT lcd.begin(); // which is also incomplete as it is begin(cols, rows)

Thanks. I had to look up what an SPI is. (Yes, I am that new to circuits.)

I found a copy of the Hello World code.
What is 0x27?
If the lcd is a 16 characters on 2 rows, why is there “20,4”?
You wrote "NOT lcd.begin(); // which is also incomplete as it is begin(cols, rows).” What do I add to lcd.begin(16, 2); since you said that’s incomplete?

1. 0x27 (0b0100111) is the 7-bit Slave Address for I2CLCD device

While the Master (the Arduino) makes a Roll Call (this is write mode) to check the presence of I2CLCD device, the transmission protocol appends a zero (0) to the right-most position of the 7-bit Slave Address to make it 8-bit (010 01110 ==> 0100 1110 = 0x4E) to comply with the byte-oriented (8-bit) protocol of I2C bus.

In read mode (when Master requests Slave to send data), the protocol appends one (1) at the rightmost position to make it 8-bit I2C Bus address.

1 Like

In your code, it plainly says 16,2 which sets up the number of rows and columns.
That's a 2 row, 16 column display.
If the display is 2 rows of 20 characters, it's 20,2.
It's a long time since I looked at one, but in the right light, you can count up the rows and columns.
In fact, in your image, you can count up 16 columns. Can't see much more, but probably 16,2

That is the 'normal' I2C address. Just in case, check the device and packaging first, then do an I2C scan to be sure.

When you dedclared the lcd objec t you used the SPI form instead of the I2C form AGAIN, look at the examples.
In your code, not only is begin wrong, it was also incomplete as the proper form of begin is begin(col, row)

The correct coding as far as creating the lcd object and INITIALIZING is in post 2.

The post when I saw it had lcd.begin(); NO col, row.
I am done.

You seem to have a knack at picking bad internet tutorials.
Try this code:


#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);
int pirPin = 2;     // PIR sensor connected to digital pin 2
int buzzerPin = 7;  // Piezo buzzer connected to digital pin 7

void setup()
{
  pinMode(pirPin, INPUT);
  pinMode(buzzerPin, OUTPUT);
  lcd.init();
  lcd.backlight();   // Turn on the backlight
  lcd.setCursor(0, 0);
  lcd.print("Motion Detector");
  delay(2000);
}

void loop()
{
  int motion = digitalRead(pirPin);

  if (motion == HIGH)
  {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Intruder Alert!");
    tone(buzzerPin, 1000);  // Emit a 1kHz tone
    delay(1000);            // Sound the buzzer for 1 second
    noTone(buzzerPin);      // Stop the buzzer
  }
  else
  {
    lcd.clear();
    lcd.print("Monitoring...");
    delay(500);
  }
}
1 Like

Thanks.

The code I list in post #3 is from the Arduino website. https://www.arduinointro.com/articles/projects/diy-motion-detection-alarm-system-using-pir-sensor-i2c-lcd-and-piezo-buzzer

I'm surprised they let such incorrect coding be published.

Jim, what are some criteria I can use to help me pick good internet tutorials? Or can you recommend a tutorial website? Since, I took the code directly from the Arduino website, so I assumed it would be correct.

You are not alone.

Arduino's "Project Hub" is as bad as "Instructables" with inaccuracies and obsolescence. We (the general public) wish all the projects could be corrected, or perhaps, policed. I tried correcting Project Hub projects "little by little" by getting an account and making comments to the "authors" (more accurately; "copy/pasters") on the "bad" projects... but the authors rarely (1:20) respond, and really do not care ("It worked when I posted it" - typically). Neither do the host care, because the volume of garbage is indefinite (growing), and official resources are limited. The bad code eventually gets posted everywhere, and every one of them ends up here, with the title something akin to "ASAP URGENT FIX MY CODE. FINAL YEAR PROJECT DUE TOMORROW". Project Hub still has clever, working, projects, but many do not work. So, when you download a sketch, check it out. When it crashes, move on to the next one, until you find one that works. Eventually you will see solutions to old problems. Then, go back to the old problem and learn to fix it.

Best wishes. Keep trying.

p.s. I recognize that "... POSITIVE)" part of the LCD object from years ago, giving plenty of users a problem... and here it is again... there is a library around that will help, but I believe that old one has been deprecated (aged-out) for a modern library.

This one (the suffix .PDE is from the old Arduino Processing environment): Arduino-libraries/LiquidCrystal/examples/HelloWorld_i2c/HelloWorld_i2c.pde at master · jenschr/Arduino-libraries · GitHub

1 Like

Thanks for the explanation and understanding. I thought I was just not seeing something obvious. Being warned is being prepared. I got the Ardino Uno because I want to learn about electronics (I had to research what a volt is, for example).

Ironically, I came across the same link you just posted when I was trying to find the LCD model that came with my Arduino kit. I was trying to understand what VCC, SDA, and SCL (that are on the board) mean. I don't want to just plug wires and type text. I want to understand what everything means and why things work. Or don't work, as the case may be.

Let me know if you can recommend websites or online courses that I can use to learn about circuits and programming with C++ that comes with Arduino boards. Or even some projects that you've enjoyed working on.

I will definitely keep trying. I'm too curious to do otherwise. lol.

Cheers,
Mike

To be brief, my favorite "from the bottom, up" is Programming Electronics Academy. They have done the best at talking in layman's terms to develop your programming vocabulary.

You do not need their pay-course. Just use their excellent YouTube video series (plural).

Start here. It is a playlist, one of many they made. Take your time. Try everything. Ask any question:

1 Like

As far as I can see, that website is not associated with Arduino, it seem to be some persons private webpage, where he posts projects and sells things.

Or can you recommend a tutorial website?

Unfortunately no.
For learning electronics I recommend this website: all about circuits
I have personally read through many of the chapters and can verify they are correct.

1 Like

I’ll look at that site.

The part I think I need more help in is understanding how to program in C++. Its structure and syntax is different from the BASIC I learned those many centuries ago when I was in high school.

The Arduino Language Reference with "clickable" examples will have most everything you will need with C programming for the Arduino. https://docs.arduino.cc/language-reference/

There is also a cheat sheet... https://raw.githubusercontent.com/liffiton/Arduino-Cheat-Sheet/refs/heads/master/Arduino%20Cheat%20Sheet.pdf

The language used to program Arduino and ESP is C++... however... I have never, knowingly, written in C++. I just use the C that I know and constantly reference.

The C/C++ vocabulary for programming Arduino and ESP is small. Like traveling... learn a few words, and it gets you all you need. The Programing Electronics Academy video series will show you most of the commands you will need.

Where you will see a LOT of new words is when using the function calls (symbols) from the "libraries" you will use for particular devices. Some device libraries have only a few functions/symbols, and some libraries have hundreds.

One of the libraries you will be exploring is Serial.h (upper-case S... spelling counts). https://docs.arduino.cc/language-reference/en/functions/communication/serial/ In the "Functions" section, you will see over twenty Serial functions... but you might use only seven for most of your programs.

1 Like

Thanks xfpd

FYI:
I see you are using the R4 and as your error message in post#1 points out not all Arduino libraries are compatible with it.

Here is the compatibly list:

1 Like

1. Fundamentally, C language still exists, and I have been using it to write programs limited to 200–500 lines, targeted for low-flash-memory AVR microcontrollers such as the ATmega328P on the UNO R3 board.

2. C++ is approximately equal to "C + few more additions (the classes and others)". There are reasons why Bjarne Stroustrup thought of developing C++, which are beyond discussion in this post.

3. Using C, we write progam in "Procedural Method" in which the executing steps come one-after-another. In C, the variables/data are seperated from the functions which operate on data.

4. C++ allows creating sketches using the so called classes; where, the variables/data and the operating methods/functions remain together offering some kind of protection -- a feature that is not available in C.

5. A beginner always start with C. Once, he becomes proficient in C, he tries to convert his C-based programs/sketches into C++ to see the benefits of C++.

C++ motivates a programmer to treat hardware as real objects and then apply methods to modify their properties and behaviors. For example: you have a fully inflated balloon which will burst if you push a pin into it. Here:

"inflated ballonn" is an object,
"push a pin into it" is a method (C++ vocabulary)
"burst" is a eaction (output)

6. Example of a Procedural Program using C to blink onboard led-L of UNO R3 board.

#define ledL 13

void setup() 
{
   Serial.begin(9600);
   pinMode(ledL, OUTPUT);
}

void loop() 
{
    digitalWrite(Built_inLed, HIGH);
    delay(2000);
    digitalWrite(Built_inLed, LOW);
    delay(1000);
 }

7. Let us convert the sketch of Step-6 using C++ Language constructs.
(1) List the variable(s)

  • DPin number with which led-L is conneted
  • Diection of DPin line
  • On time of led-L
  • Off time of led-L

(2) List the methods (functions)

  • ioDirection()
  • ledOn()
  • ledOff()
  • timeDelay()

8. Before writing a class based sketch for the Procedural sketch of Step-6, let us get familiar with various fields of a typpical "Class Structure" (Fig-1) that is created using class keyword.


Fgure-1:

9. Now let us see how I have creted below a simple "class structure" using class keyword. I have followed the template (Fig-1) of Step-8. (I always use three spaces for indentation.)

class SimpleLED
{
   private:
      byte DPin;
      byte direction;
      unsigned long onTime;
      unsigned long offTime;

   public:
      SimpleLED(byte pin, byte dir, unsigned long onT, unsigned long offT);
      void ioDirection();
      void ledOn();
      void ledOff();
      void timeDelay(unsigned long delayTime);
};

SimpleLED ledL(13, OUTPUT, 2000, 1000);   //object ledL is created 

Note-1: Only member functions are allowed to access (performing read/write operations) on the private variables.

Note-2: Any function outside even the loop() function that is outside of class has no right to access any private variables of that class.

Note-3: Any function outside the class has the right o access the member functions.

Note-4: Member functions can access each other.

Note-5: Relationship among object, method, member operator, and function (Fig-2):

image
Figure-2:

Q: Note that the number of variables (4) agrees with Step-7 except that number of methods is 5. Why is there one more method (SimpleLed()) that has been added?
A: It is the rule of C++ that it adds one constructor() function with the same name as the "Class name" is. The constructor() function is automatically called upon for execution when an object is created as we will see in Step-10.

10. Now, we have to write defining codes for the methods and then integrate them with the setup() and loop() functions of Arduio Sketch.
(1) Object creation/declaration

SimpleLED ledL(13, OUTPUT, 2000, 1000);   //object ledL is created 

(2) Defning codes of SimpleLED() method

SimpleLED::SimpleLED(byte pin, byte dir, unsigned long onT, unsigned long offT)
{
   DPin      = pin;
   direction = dir;
   onTime    = onT;
   offTime   = offT;
}

Note-1: The name of the construction() function is always be the name of the class name. the constructor function does not return any value and not even void.

Note-2: The value of the first argument (13) of the led1 object is passed to the pin parameter of the SimpleLED() constructor, and from there it is assigned to the private member variable DPin. The value 13 cannot be assigned directly to a private variable; it must be passed through a public method/member function (the constructor). The same applies to the other arguments: OUTPUT, 2000, and 1000 of the object.

(3) Defining codes for ioDirecton() method.

void SimpleLED::ioDirection() //:: says ioDirection() belongs to SimpleLed class
{
  pinMode(DPin, direction);   //pinMode(13, OUTPUT);
}

Note-1: The double colon (::) is called "Scope Resolution Operator." It syas to the compiler that the method to its right (ioDirection()) belongs to the class that is located at its left (SimpleLED).

(4) Defining codes for ledOn() method.

void SimpleLED::ledOn()
{
  digitalWrite(DPin, HIGH);
}

(5) Defining codes for ledOff() method.

void SimpleLED::ledOff()
{
  digitalWrite(DPin, LOW);
}

(6) Defining codes for timeDelay() method.

void SimpleLED::timeDelay(unsigned long delayTime)
{
  delay(delayTime);
}

11. The Sketch

//-- place code to declare class structure
//-- place code to declare object

void setup()
{
    ledL.ioDirection();
}

void loop()
{
    ledL.ledOn()
    ledL.timeDelay(argOn);//argOn must be evaluated to 2000 (onTime variable)
    ledL.ledOff();
    ledL.timeDelay(argOff);//argOff must be evaluated to 1000 (offTime variable)
}

//-- place code to define SimpleLED() method
//-- place code to defiine ioDirection() method
//-- place code to define ledOn() method
//-- place code to define ledOff() method
//--place code to define timeDelay() method

Note-1: The argOn argument must be evaluated to onTime (2000 ms). The onTime is a private variable. So, it must be accessed via a member function like unsigned long getOnTime(). This type of function is known as getter function.

Note-2: Similarly to assign the value of the offTime (1000) variable to argOff argument, the member function unsigned long getOffTime() is needed.

Note-3: As a result, the class structure of Step-9 will take the following form:

class SimpleLED
{
   private:
      byte DPin;
      byte direction;
      unsigned long onTime;
      unsigned long offTime;

   public:
      SimpleLED(byte pin, byte dir, unsigned long onT, unsigned long offT);
      void ioDirection();
      void ledOn();
      void ledOff();
      void timeDelay(unsigned long delayTime);

      unsigned long getOnTime();     //getter function
      unsigned long getOffTime();
};

Note-4: Defining codes for getOnTime() method

unsigned long SimpleLED::getOnTime()
{
  return onTime;   //2000 ms goes to argOn variable of calling function
}

Note-5: Defining codes for getOffTime() method

unsigned long SimpleLED::getOffTime()
{
  return offTime;
}

12. The final integrated sketch:

class SimpleLED
{
  private:
    byte DPin;
    byte direction;
    unsigned long onTime;
    unsigned long offTime;

  public:
    SimpleLED(byte pin, byte dir, unsigned long onT, unsigned long offT);
    void ioDirection();
    void ledOn();
    void ledOff();
    void timeDelay(unsigned long delayTime);

    unsigned long getOnTime(); //getter declaration
    unsigned long getOffTime();
};

SimpleLED ledL(13, OUTPUT, 2000, 1000);  // DPin 13, OUTPUT, 2000/1000ms ON/OFF

void setup()
{
  ledL.ioDirection();
}

void loop()
{
  ledL.ledOn();
  unsigned long argOn = ledL.getOnTime();
  ledL.timeDelay(argOn);//(ledL.getOnTime());
  
  ledL.ledOff();
  unsigned long argOff = ledL.getOffTime();
  ledL.timeDelay(argOff);//(ledL.getOffTime());
}

SimpleLED::SimpleLED(byte pin, byte dir, unsigned long onT, unsigned long offT)
{
  DPin      = pin;
  direction = dir;
  onTime    = onT;
  offTime   = offT;
}

void SimpleLED::ioDirection()
{
  pinMode(DPin, direction);
}

void SimpleLED::ledOn()
{
  digitalWrite(DPin, HIGH);
}

void SimpleLED::ledOff()
{
  digitalWrite(DPin, LOW);
}

void SimpleLED::timeDelay(unsigned long delayTime)
{
  delay(delayTime);
}

unsigned long SimpleLED::getOnTime()
{
  return onTime;
}

unsigned long SimpleLED::getOffTime()
{
  return offTime;
}

13. Upload Sketch of Step-12 into Arduino UNO R3 and check that the led_L is bicking with 2 sec onTime and 1 sec offTime.

14. Exercise
Rewrite Sketch of Step-12 to get onTIme/offTime form the Serial Monitor and then pass them to the class.

2 Likes