My first class but why does it work correctly?

Thank you for positive response.

@GolamMostafa
Well i think i got things the way you asked for and that was a nice practice run for me as well, enjoyed doing this. I haven't made a lot of .h and .cpp files yet.
I hope this will answer most of your questions.

I uploaded this myself to an ESP32_DevkitC_V4 but i think this should work on most arduino's as well.

As for my objectives (except for learning). I am writing a sketch for a "Stick catching machine". I have build one a few years ago but i wanted to upgrade it with a screen with menu so i can set different difficulty levels. I had two seperate (but actualy the same) functions for the two buttons and thought this would be a great moment to try making my very first class.

If i'm understanding your question 4 correctly, you'd like to use this for your students?
If so, i'm flattered you'd like to use something i made and i hope you can use this.
But as i think of myself as a beginner in programming, there will probably be more then enough to improve on this.

Class_test.ino

//class_test.ino

#include "Button.h"

//Create button objects. int = buttonpin, bool = true for internal pullup and false for external
Button knop(26, true);
Button knop2(25, false);

void setup() {
  //Start Serial monitor
  Serial.begin(115200);
  //Configure buttonpins
  knop.begin();
  knop2.begin();
}

void loop() {
  //Update buttonstates in loop() to check as frequently as possible
  knop.buttonUpdate();
  knop2.buttonUpdate();

  if (knop.buttonPressed()) {  //Check if button is pressed
    Serial.println("Button");
  }
  if (knop2.buttonPressed()) {  //Check if button 2 is pressed
    Serial.println("Button 2");
  }
}

Button.h

//Button.h

#ifndef BUTTON.H
#define BUTTON .H

#include <Arduino.h>

class Button {
private:
  int m_pinNumber{};       //holds the pinnumber for the button
  bool m_pullup{ false };  //if true = use internal pullup resistor, false = use external pullup resistor

  int m_previousSteadyState{};  //Previous button state
  int m_currentSteadyState{};   //Current button state
  int m_lastBouncyState{};      //Used to check if the button is finished bouncing

  unsigned long m_lastDebounceTime{ 0 };  //Used for timer, to debounce button
  unsigned long m_debounceDelay{ 50 };


public:
  //Constructor declaration
  Button(int pin, bool pullup);

  //Function declarations
  void begin();

  bool buttonPressed();

  void buttonUpdate();

};  // class Button

#endif

Button.cpp

//Button.cpp

#include "Button.h"

Button::Button(int pin, bool pullup)          //Constructor
  : m_pinNumber{ pin }, m_pullup{ pullup } {  //Initialize private menber variables
}

//Configure button pin with internal or external pullup resistor
void Button::begin() {
  if (m_pullup) {
    pinMode(m_pinNumber, INPUT_PULLUP);
  } else {
    pinMode(m_pinNumber, INPUT);
  }

  m_previousSteadyState = digitalRead(m_pinNumber);  //Initialize button states
  m_currentSteadyState = m_previousSteadyState;
  m_lastBouncyState = m_previousSteadyState;
}

//Member function for checking if the button has been pressed
bool Button::buttonPressed() {
  if (m_previousSteadyState == 1 && m_currentSteadyState == 0) {  //Because using pullup resitors 0 = pressed and 1 = not pressed
    return true;
  }
  return false;
}

//Member function for updating button state (call in loop() to update as frequently as possible)
void Button::buttonUpdate() {

  int buttonRead = digitalRead(m_pinNumber);  //Read button pin

  if (buttonRead != m_lastBouncyState) {  //Button changed
    m_lastDebounceTime = millis();        //Reset debounce timer
    m_lastBouncyState = buttonRead;
  }

  if (millis() - m_lastDebounceTime > m_debounceDelay) {  //reading longer then debounce time
    m_previousSteadyState = m_currentSteadyState;         //Update previous and current buttonstates (unbounced)
    m_currentSteadyState = buttonRead;
  }
}
1 Like

@gcjr
Thank you for the link to the book.
It will take me a while to get to this, it allready took me a couple of months to get to chapter 14 of the learncpp website. But i've saved the link and it is on the to-do list.

About the m_ prefix i use, that was advice from the learncpp website
"One of the best reasons to prefix private data members with β€œm_” is to avoid having data members and getters with the same name"

As for the unnecessary code. I'm not trying to make my code look professional, far from it. I'm just trying to make things work the best way i can. And unfortunately, this is for now the best i can.
But you all help me a lot getting better. It will take me a while, but i'll get there.

Thanks

it's hard to learn how to write good code without seeing well written code. Object oriented code doesn't need to use a class.

Learning to code and write programs is not sufficient on its own; it is also important to understand the underlying theory. I notice that you are following the programming conventions of the referenced website rather than focusing on the principles behind them.

For example, why do you use int n{}; instead of int n = 0;? Beginners should start with more familiar constructs. The advanced programmers use the new features of the C++ Language.

1. I would like to request you to post a class based sketch to blink a LED connected at DPin-10 at 1-sec interval.

2. What is the difference between class and struct keywords?

3. Please, tell which function is executed first in your sketch and how the the following object passes the Dpin- number and its direction to the private variable: m_pinNumber.

Button knop(26, true);

4.
If I have a program which I can complete using C only, then should I still use C++?

5. Remember:
A Porgram as four parts. Take them as building blocks and then expand them as necessary to accomodate the tasks of your program.
(1) Variable declaration

byte a;
byte b;

(2) Variable definition

a = 6;
b = 3;

(3) Variable processing
byte sum = a + b;

(4.) Show result of processing on Screen/Monitor
Serial.print(sum, DEC);

@GolamMostafa

Well i have been programming arduino's and small apps with MIT App Inventor for a couple of years now, and so far i just "made it work", so this is all hobby stuff. But i've been reading the lerancpp website so i can do a bit more and make it cleaner.
But i think i'm a little late for seriously learning C++, probably should have started 20 or 30 years ago.

I thank you for trying to teach me a thing or two and giving me some problems to solve.
I will get to that but it will probably take me a while because i unfortunately have about 10 other projects i have to finish, like painting the in- and outside of the house or building some li-ion batteies for other projects etc. (just to mention a few). And of course i'm doing everything at the same time, so i'll probably never get things done this way.

I'll check back every now and then and when i've got some time left i'll try to get to your suggestion for the led-blink class and (if the topic is still open) post my solution.
At least i have my class working and can play around with that for a while.

So again, thank you for your time and efforts, but for now i'm going to get back to one of my other projects.

1 Like

Thank you very much for your kind and pleasant reply. I am impressed by your enthusiasm and dedication to learning and practicing new things.

If one is a beginner, there are no "familiar constructs", everything is new. So there's a case to be made for using the "bracket syntax". It's the preferred C++ initialization syntax because it makes it abundantly clear that the statement is an initialization and not an assignment.

Is the declaration int n = 1; in the global scope considered an initialization? If that is the case, then writing int n {1, 2}; makes it easier to introduce a mistake.

I do not clearly understand why modern C++ encourages the use of brace initialization, such as int n {1};, instead of int n = 1;.

I can confirm that you do not understand.

Confirm with illustrations.

As I said, the former syntax makes it clear that the statement is an initialization. While the latter syntax is also an initialization it, contains and "=" sign. Thus, at a glance, it could be mistakenly interpreted as an assignment.

I understand that int n = 1; is always an initialization regardless of whether it is in global or local scope. On the other hand, n = 5; is always an assignemnt. The possible ways of initialization are:

int n = 1;   // copy initialization
int n(1);    // direct initialization
int n {1};   // brace/list initialization (uniform initialization)

The veteran members may kindly discuss the advantages and disadvantages of the various kinds of initialization, and also the significances of the names -- copy, direct, and uniform.

Courtesy of google search "c++ initialisation of variables" :

That referred link does not discuss the advantages and disadvantages of various methods of itialization. These can be illustrated by an experienced and learned programmer.

Such people and their wisdom can also be found using, for example, google: c++ initialisation preferences

Are people of the forum and documments of the Google same?