Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. The Lounge
  3. What are some stupid-useful coding tricks you rely on?

What are some stupid-useful coding tricks you rely on?

Scheduled Pinned Locked Moved The Lounge
hardwareiotquestionworkspace
36 Posts 15 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R raddevus

    Yeah, it's a simple thing that makes it so: 1. Debouncing is handled for all buttons in one place. 2. The specific functionality for the button is run. Otherwise you have button debouncing code all over the place. It definitely cleans it up. And, yes, C++ could do this a bit cleaner via encapsulation (in it's own class) but I find that Arduino C++ is more like a hybrid of C & C++ because C++ class overhead does use some memory so there are places in Arduino where you often do more C-like and other places where you may do more C++-like (include classes). :)

    H Offline
    H Offline
    honey the codewitch
    wrote on last edited by
    #9

    Just to be difficult, classes don't use memory in C++ intrinsically, with the exception of classes with vtbls. It's just a way to structure your code. C++ doesn't introduce overhead compared to C unless you write it so that it does.

    To err is human. Fortune favors the monsters.

    R 1 Reply Last reply
    0
    • R raddevus

      I had a number of buttons on my Arduino project that needed to do similar (but slightly different) things. I had all this code to handle the button debouncing. So then I discovered a nice way to pass a pointer to a function (button press handler) so that the code was the same no matter which button was pressed, but the specific function for the correct button is called. And, all the debouncing for each button is wrapped up nicely.

      typedef void (*ButtonPressHandler) (void);

      void checkButton(const int BUTTON, bool &last, bool &current, ButtonPressHandler handler ){
      current = debounce(last, BUTTON); // Read debounced state
      if (last == LOW && current == HIGH) // If it was pressed…
      {
      // This runs the code that we want to happen
      // when the user presses the button. The function ptr
      // allows us to do different types of work
      handler();
      }
      last = current; // Reset button value
      }

      boolean debounce(boolean last, int button)
      {
      boolean current = digitalRead(button); // Read the button state
      if (last != current) // If it's different…
      {
      delay(5); // Wait 5ms
      current = digitalRead(button); // Read it again
      }
      return current; // Return the current value
      }

      Now you just call it with whichever button is pressed so it can all be handled:

      // My device has a button that changes the room (location)
      // The last argument is the button handler code (pointer to function)
      checkButton(ROOM_BTN,roomBtnPrev,roomBtnCurrent,checkChangeRoomButton);

      // It also has a button that turns data writing (to SD Card) on / off
      checkButton(DATA_BTN, dataBtnPrev, dataBtnCurrent, checkWriteDataButton);

      Now they are both handled the same way and all the debouncing is wrapped up. What do you think?

      Mircea NeacsuM Offline
      Mircea NeacsuM Offline
      Mircea Neacsu
      wrote on last edited by
      #10

      raddevus wrote:

      What do you think?

      If we wouldn't be in the lounge where programming topics are off-limits, I'd call your solution sub-optimal: waiting 5 ms or more for each button, on a non-preemptive system like Arduino, is just asking for trouble. My favorite debouncing solution is a loop that reads all buttons and feeds them to software shift registers. When a shift register is filled with the same value, button is debounced. But, as I said, here in the lounge I'll just keep my big mouth shut :D

      Mircea

      R 1 Reply Last reply
      0
      • H honey the codewitch

        Just to be difficult, classes don't use memory in C++ intrinsically, with the exception of classes with vtbls. It's just a way to structure your code. C++ doesn't introduce overhead compared to C unless you write it so that it does.

        To err is human. Fortune favors the monsters.

        R Offline
        R Offline
        raddevus
        wrote on last edited by
        #11

        True, they don't use more memory. However, they use program space which can be very limiting. For example an Arduino Nano utilizes an ATMega328 which has 32K Flash, but this is even smaller with the bootloader included. So, if you create a large number of classes in code on an Arduino you will find that much of your program memory is eaten up. I wrote an extensive Arduino program which : 1. allows writes to SD Card -- requires code 2. has a Bluetooth component which transmits data to phone 3. contains a tmp36 (temperature module) 4. displays info to oled screen 5. contains a real-time clock for recording time temp was taken That pushes the limits of program memory (requires more code to handle things, thus eating more flash) and I moved to the ATMega4809 (which includes 48K flash). You can see the entire schematic here[^]. So, if you write more code (which includes all those class wrappers) you'll run out of code space more quickly. You can see the code at my github[^].

        H 2 Replies Last reply
        0
        • Mircea NeacsuM Mircea Neacsu

          raddevus wrote:

          What do you think?

          If we wouldn't be in the lounge where programming topics are off-limits, I'd call your solution sub-optimal: waiting 5 ms or more for each button, on a non-preemptive system like Arduino, is just asking for trouble. My favorite debouncing solution is a loop that reads all buttons and feeds them to software shift registers. When a shift register is filled with the same value, button is debounced. But, as I said, here in the lounge I'll just keep my big mouth shut :D

          Mircea

          R Offline
          R Offline
          raddevus
          wrote on last edited by
          #12

          If I were to respond to your message, which I won't, I would say something along hte lines of: 1. Programmers and the like are the most abysmal people of all. They cannot enjoy any solution other than the ones they understand. 2. The OP asked for code samples which they found useful -- and I replied with code I found useful and interesting -- but never intimated that it was the _best_ solution. I am a hobbyist on Arduino. Nothing more. 3. It is comments exactly like yours that make the internet such an abysmal experience for everyone. 4. And I thought of another -- the debounce code that you don't like was actually taken from Jeremy Blum's fantastic book, Exploring Arduino[^]. So take it up with him. See his github and do a code review on him there (GitHub - sciguy14/Exploring-Arduino-2nd-Edition: Companion Code for the Second Edition of "Exploring Arduino," the book by Jeremy Blum[^]). But I will not respond here. :rolleyes:

          Mircea NeacsuM 1 Reply Last reply
          0
          • R raddevus

            If I were to respond to your message, which I won't, I would say something along hte lines of: 1. Programmers and the like are the most abysmal people of all. They cannot enjoy any solution other than the ones they understand. 2. The OP asked for code samples which they found useful -- and I replied with code I found useful and interesting -- but never intimated that it was the _best_ solution. I am a hobbyist on Arduino. Nothing more. 3. It is comments exactly like yours that make the internet such an abysmal experience for everyone. 4. And I thought of another -- the debounce code that you don't like was actually taken from Jeremy Blum's fantastic book, Exploring Arduino[^]. So take it up with him. See his github and do a code review on him there (GitHub - sciguy14/Exploring-Arduino-2nd-Edition: Companion Code for the Second Edition of "Exploring Arduino," the book by Jeremy Blum[^]). But I will not respond here. :rolleyes:

            Mircea NeacsuM Offline
            Mircea NeacsuM Offline
            Mircea Neacsu
            wrote on last edited by
            #13

            I sincerely apologize if my post rubbed you the wrong way. My old boss once said that I have the same level of empathy as Catbert, the evil HR director. :-D To make amends, here is a good post about debouncing that I've perused for many years: Debounce Code – One Post To Rule Them All | Hackaday[^]

            Mircea

            R 1 Reply Last reply
            0
            • H honey the codewitch

              I was just thinking about this today when I was retooling my IoT button library. I use template-instance statics to get around not being able to pass an argument to an interrupt routine (which must be void ()) under the Arduino framework

              template
              class button {
              // assign this to "this" on initialization of a class instance
              static button* m_this;
              // ISR
              static IRAM_ATTR void isr() { m_this->... }
              };
              ...

              like that. It's really useful but it makes me kinda wanna puke too, even though there's absolutely nothing wrong with it, technically speaking, since it doesn't make sense to have two buttons on one pin anyway, and you're not dealing in a pre-emptively threaded environment in 80% of all cases on 80% of all platforms. Template-instance statics (i don't know what else to call them) are something I have to rely on way more than I wish I had to, but I am glad they are there. What's your go to coding technique that nevertheless makes you uncomfortable?

              To err is human. Fortune favors the monsters.

              M Offline
              M Offline
              Marc Clifton
              wrote on last edited by
              #14

              Well, in C# I have a whole bunch of extension methods to make life easier for string manipulation, looping, matching, assertions, encoding/decoding, etc. I guess that's not exactly a coding trick, more of a re-usable library. And the only "discomfort" is that C# newbies think these things are built-in classes and methods on their respective data types. :laugh:

              Latest Article:
              Create a Digital Ocean Droplet for .NET Core Web API with a real SSL Certificate on a Domain

              H 1 Reply Last reply
              0
              • Mircea NeacsuM Mircea Neacsu

                I sincerely apologize if my post rubbed you the wrong way. My old boss once said that I have the same level of empathy as Catbert, the evil HR director. :-D To make amends, here is a good post about debouncing that I've perused for many years: Debounce Code – One Post To Rule Them All | Hackaday[^]

                Mircea

                R Offline
                R Offline
                raddevus
                wrote on last edited by
                #15

                Thanks, that was very nice and I accept your apology. I will take a look at the post. I honestly was offering the original code just as an interesting thing. I was probably triggered by your post because I started out in IT back in '91 and since then it has always been a "my code is better than yours" pissing war with Devs. :laugh: I started out in Tech Support and knew I was a slug in the IT world. Worked my way into QA and was there for 5 years or so and remember when this Dilbert came out[^]. Oh, it's funny now. I finally made worked my way into Dev and have been here for about 22 years but I find that Devs are (and have always been) so competitive and are "always right". it just kind of triggers me. When I was in QA if a dev ticked me off, I would just test his code, find a critical bug and then post it Friday afternoon. :laugh:

                M 1 Reply Last reply
                0
                • R raddevus

                  True, they don't use more memory. However, they use program space which can be very limiting. For example an Arduino Nano utilizes an ATMega328 which has 32K Flash, but this is even smaller with the bootloader included. So, if you create a large number of classes in code on an Arduino you will find that much of your program memory is eaten up. I wrote an extensive Arduino program which : 1. allows writes to SD Card -- requires code 2. has a Bluetooth component which transmits data to phone 3. contains a tmp36 (temperature module) 4. displays info to oled screen 5. contains a real-time clock for recording time temp was taken That pushes the limits of program memory (requires more code to handle things, thus eating more flash) and I moved to the ATMega4809 (which includes 48K flash). You can see the entire schematic here[^]. So, if you write more code (which includes all those class wrappers) you'll run out of code space more quickly. You can see the code at my github[^].

                  H Offline
                  H Offline
                  honey the codewitch
                  wrote on last edited by
                  #16

                  I'd argue that it's *easier* to write compact code in C than it is in C++, but I challenge anyone to come up with a realistic C construct that can't be reflected using C++isms and result in functionally the same assembly code. One thing people forget is that types don't exist. They are like concrete molds that set your data in a form, but then that mold is tossed during compilation as it's no longer needed in the resulting code. So as long as you know what stuff generates what ASM, you can write lean C++ code. Now if you're relying on the STL or just being casual about it, you'll definitely see C++ as more bloated. But there's an actual pattern to creating classes that's replicated in C all the time. Any time you see a "handle" in fact, that's a "class pointer" except in C lingo. Now, you'll find if you want to make lean C++ code you'll be using statics a lot - any time you don't need "handles" You'll also probably prefer the C malloc/free paradigm to new and delete for several reasons. But within parameters, you can write C++ code that's every bit as lean as C code. You just have to know what your compiler is going to be creating. At the end of the day, that means C is probably the best choice for enforcing lean code. But an experienced C++ developer need not do away with many of their C++ niceties for want of RAM or even program space. off my soapbox now. :)

                  To err is human. Fortune favors the monsters.

                  1 Reply Last reply
                  0
                  • M Marc Clifton

                    Well, in C# I have a whole bunch of extension methods to make life easier for string manipulation, looping, matching, assertions, encoding/decoding, etc. I guess that's not exactly a coding trick, more of a re-usable library. And the only "discomfort" is that C# newbies think these things are built-in classes and methods on their respective data types. :laugh:

                    Latest Article:
                    Create a Digital Ocean Droplet for .NET Core Web API with a real SSL Certificate on a Domain

                    H Offline
                    H Offline
                    honey the codewitch
                    wrote on last edited by
                    #17

                    I have one I just made the other day in C# for reading and writing structs over a serial port using marshalling. WriteStruct and ReadStruct on a SerialPort class. =) It doesn't make *me* uncomfortable, but people might puke at the idea of using marshalling for sending data over serial rather than using something like binary serialization. Marshalling requires less code. :) I'm nothing if not lazy.

                    To err is human. Fortune favors the monsters.

                    1 Reply Last reply
                    0
                    • R raddevus

                      True, they don't use more memory. However, they use program space which can be very limiting. For example an Arduino Nano utilizes an ATMega328 which has 32K Flash, but this is even smaller with the bootloader included. So, if you create a large number of classes in code on an Arduino you will find that much of your program memory is eaten up. I wrote an extensive Arduino program which : 1. allows writes to SD Card -- requires code 2. has a Bluetooth component which transmits data to phone 3. contains a tmp36 (temperature module) 4. displays info to oled screen 5. contains a real-time clock for recording time temp was taken That pushes the limits of program memory (requires more code to handle things, thus eating more flash) and I moved to the ATMega4809 (which includes 48K flash). You can see the entire schematic here[^]. So, if you write more code (which includes all those class wrappers) you'll run out of code space more quickly. You can see the code at my github[^].

                      H Offline
                      H Offline
                      honey the codewitch
                      wrote on last edited by
                      #18

                      As an aside, I noticed you are using the Arduino IDE. Forgive me if this has been suggested before, or if you've otherwise tried it, but you may want to consider VS Code + Platform IO as an alternative development IDE and toolchain. Arduino is sort of like a fisher price toy, and it doesn't do a lot for you as a developer. Platform IO supports: - Microsoft's intellisense/autocomplete goodness, and all their fancy VS Code IDE wizardry - Per project settings and libraries, in an INI file rather than forcing you to mess with menus (but you can use menus to edit the ini file if you want) - A nice library repository system using semantic versioning - Several frameworks and platforms, including Arduino, ESP-IDF, and others. - Autodetection of the right COM port to use. Yay! - and other stuff I'm forgetting right now. Arduino IDE's sole advantage is the bleeding edge releases of the framework tend to be supported on it a little earlier. And Platform IO is a Ukrainian project, so there have been some rough points over the past year in terms of maintenance - understandably so! - but it's been solid lately.

                      To err is human. Fortune favors the monsters.

                      1 Reply Last reply
                      0
                      • H honey the codewitch

                        I was just thinking about this today when I was retooling my IoT button library. I use template-instance statics to get around not being able to pass an argument to an interrupt routine (which must be void ()) under the Arduino framework

                        template
                        class button {
                        // assign this to "this" on initialization of a class instance
                        static button* m_this;
                        // ISR
                        static IRAM_ATTR void isr() { m_this->... }
                        };
                        ...

                        like that. It's really useful but it makes me kinda wanna puke too, even though there's absolutely nothing wrong with it, technically speaking, since it doesn't make sense to have two buttons on one pin anyway, and you're not dealing in a pre-emptively threaded environment in 80% of all cases on 80% of all platforms. Template-instance statics (i don't know what else to call them) are something I have to rely on way more than I wish I had to, but I am glad they are there. What's your go to coding technique that nevertheless makes you uncomfortable?

                        To err is human. Fortune favors the monsters.

                        G Offline
                        G Offline
                        Gary R Wheeler
                        wrote on last edited by
                        #19

                        honey the codewitch wrote:

                        Template-instance statics

                        I've done that for cases where I didn't want to pass around a singleton instance:

                        class API
                        {
                        public:

                        static void DoThing();
                        

                        private:

                        API();
                        
                        static API \*\_This;
                        

                        };

                        API *API::_This = NULL;

                        void API::DoThing()
                        {
                        if (_This == NULL) _This = new API();
                        }

                        It's useful for create-only-if-needed scenarios. For us, those arise fairly often adapting to different hardware. They're also useful when the creation process is expensive or time-consuming. In C++ I like the idea that API::DoThing() is a blatant syntax for a singleton concept. I've also had cases where the public static functions define the 'API' for a collection, while the instance members and values are the elements in the collection. Now, I know that singletons are a 'code smell', but trust me... I know what I'm doing. :-D

                        Software Zen: delete this;

                        H 1 Reply Last reply
                        0
                        • H honey the codewitch

                          I was just thinking about this today when I was retooling my IoT button library. I use template-instance statics to get around not being able to pass an argument to an interrupt routine (which must be void ()) under the Arduino framework

                          template
                          class button {
                          // assign this to "this" on initialization of a class instance
                          static button* m_this;
                          // ISR
                          static IRAM_ATTR void isr() { m_this->... }
                          };
                          ...

                          like that. It's really useful but it makes me kinda wanna puke too, even though there's absolutely nothing wrong with it, technically speaking, since it doesn't make sense to have two buttons on one pin anyway, and you're not dealing in a pre-emptively threaded environment in 80% of all cases on 80% of all platforms. Template-instance statics (i don't know what else to call them) are something I have to rely on way more than I wish I had to, but I am glad they are there. What's your go to coding technique that nevertheless makes you uncomfortable?

                          To err is human. Fortune favors the monsters.

                          Mircea NeacsuM Offline
                          Mircea NeacsuM Offline
                          Mircea Neacsu
                          wrote on last edited by
                          #20

                          Maybe the "Named parameter idiom"[^]. Instead of:

                          Rectangle r(10, 15, 24, 42);

                          you can write:

                          Rectangle r;
                          r.left(10).top(15).width(24).height(42);

                          Makes a world of difference when you have complicated objects with lots of parameters.

                          Mircea

                          H C 2 Replies Last reply
                          0
                          • G Gary R Wheeler

                            honey the codewitch wrote:

                            Template-instance statics

                            I've done that for cases where I didn't want to pass around a singleton instance:

                            class API
                            {
                            public:

                            static void DoThing();
                            

                            private:

                            API();
                            
                            static API \*\_This;
                            

                            };

                            API *API::_This = NULL;

                            void API::DoThing()
                            {
                            if (_This == NULL) _This = new API();
                            }

                            It's useful for create-only-if-needed scenarios. For us, those arise fairly often adapting to different hardware. They're also useful when the creation process is expensive or time-consuming. In C++ I like the idea that API::DoThing() is a blatant syntax for a singleton concept. I've also had cases where the public static functions define the 'API' for a collection, while the instance members and values are the elements in the collection. Now, I know that singletons are a 'code smell', but trust me... I know what I'm doing. :-D

                            Software Zen: delete this;

                            H Offline
                            H Offline
                            honey the codewitch
                            wrote on last edited by
                            #21

                            I totally get what you're saying. Just for clarity though template-instance statics add another dimension to statics because they are not shared between different instantiations of the same template.

                            template struct foo final {
                            static int value;
                            };
                            ...

                            ...
                            foo<1>::value = 5;
                            foo<2>::value = 4;
                            printf("%d + %d = %d\n",foo<1>::value,foo<2>::value,foo<1>::value+foo<2>::value);
                            // prints 5 + 4 = 9

                            To err is human. Fortune favors the monsters.

                            G 1 Reply Last reply
                            0
                            • Mircea NeacsuM Mircea Neacsu

                              Maybe the "Named parameter idiom"[^]. Instead of:

                              Rectangle r(10, 15, 24, 42);

                              you can write:

                              Rectangle r;
                              r.left(10).top(15).width(24).height(42);

                              Makes a world of difference when you have complicated objects with lots of parameters.

                              Mircea

                              H Offline
                              H Offline
                              honey the codewitch
                              wrote on last edited by
                              #22

                              yikes! I've done similar, but mostly for constructing Abstract Syntax Trees.

                              To err is human. Fortune favors the monsters.

                              1 Reply Last reply
                              0
                              • R raddevus

                                CPallini wrote:

                                You could do that with a virtual function, couldn't you?

                                I'm not sure. What is a virtual function? Can you create a virtual function in Arduino code? I've been developing software for 30 years and I remember something about vtables and maybe a virtual function is a function lookup? I'm just guessing to see how close I am to your answer. let me know, thanks. :) Oh, base-class abstract method? yes, could be done. 6 one way, half a dozen the other. :laugh: C# has delegates. This whole, "call some function I define in the future" is really done in many different ways with various names. :-D

                                H Offline
                                H Offline
                                honey the codewitch
                                wrote on last edited by
                                #23

                                A virtual function is a function that can be overloaded by a derived class. In C# you mark such a function as virtual, IIRC - same as you do in C++.

                                To err is human. Fortune favors the monsters.

                                1 Reply Last reply
                                0
                                • R raddevus

                                  I had a number of buttons on my Arduino project that needed to do similar (but slightly different) things. I had all this code to handle the button debouncing. So then I discovered a nice way to pass a pointer to a function (button press handler) so that the code was the same no matter which button was pressed, but the specific function for the correct button is called. And, all the debouncing for each button is wrapped up nicely.

                                  typedef void (*ButtonPressHandler) (void);

                                  void checkButton(const int BUTTON, bool &last, bool &current, ButtonPressHandler handler ){
                                  current = debounce(last, BUTTON); // Read debounced state
                                  if (last == LOW && current == HIGH) // If it was pressed…
                                  {
                                  // This runs the code that we want to happen
                                  // when the user presses the button. The function ptr
                                  // allows us to do different types of work
                                  handler();
                                  }
                                  last = current; // Reset button value
                                  }

                                  boolean debounce(boolean last, int button)
                                  {
                                  boolean current = digitalRead(button); // Read the button state
                                  if (last != current) // If it's different…
                                  {
                                  delay(5); // Wait 5ms
                                  current = digitalRead(button); // Read it again
                                  }
                                  return current; // Return the current value
                                  }

                                  Now you just call it with whichever button is pressed so it can all be handled:

                                  // My device has a button that changes the room (location)
                                  // The last argument is the button handler code (pointer to function)
                                  checkButton(ROOM_BTN,roomBtnPrev,roomBtnCurrent,checkChangeRoomButton);

                                  // It also has a button that turns data writing (to SD Card) on / off
                                  checkButton(DATA_BTN, dataBtnPrev, dataBtnCurrent, checkWriteDataButton);

                                  Now they are both handled the same way and all the debouncing is wrapped up. What do you think?

                                  J Offline
                                  J Offline
                                  jmaida
                                  wrote on last edited by
                                  #24

                                  Viewing this as a old C programmer, it all makes sense, is quite clear and does the job. C++ version seems to introduce fuzziness and obfuscation (although straight C can do the same thing). Cute or clever does not always = maintainable code. Just saying.

                                  "A little time, a little trouble, your better day" Badfinger

                                  1 Reply Last reply
                                  0
                                  • Mircea NeacsuM Mircea Neacsu

                                    Maybe the "Named parameter idiom"[^]. Instead of:

                                    Rectangle r(10, 15, 24, 42);

                                    you can write:

                                    Rectangle r;
                                    r.left(10).top(15).width(24).height(42);

                                    Makes a world of difference when you have complicated objects with lots of parameters.

                                    Mircea

                                    C Offline
                                    C Offline
                                    CPallini
                                    wrote on last edited by
                                    #25

                                    Nice. With C++ 20, you might enjoy designated initializers[^].

                                    "In testa che avete, Signor di Ceprano?" -- Rigoletto

                                    1 Reply Last reply
                                    0
                                    • R raddevus

                                      I had a number of buttons on my Arduino project that needed to do similar (but slightly different) things. I had all this code to handle the button debouncing. So then I discovered a nice way to pass a pointer to a function (button press handler) so that the code was the same no matter which button was pressed, but the specific function for the correct button is called. And, all the debouncing for each button is wrapped up nicely.

                                      typedef void (*ButtonPressHandler) (void);

                                      void checkButton(const int BUTTON, bool &last, bool &current, ButtonPressHandler handler ){
                                      current = debounce(last, BUTTON); // Read debounced state
                                      if (last == LOW && current == HIGH) // If it was pressed…
                                      {
                                      // This runs the code that we want to happen
                                      // when the user presses the button. The function ptr
                                      // allows us to do different types of work
                                      handler();
                                      }
                                      last = current; // Reset button value
                                      }

                                      boolean debounce(boolean last, int button)
                                      {
                                      boolean current = digitalRead(button); // Read the button state
                                      if (last != current) // If it's different…
                                      {
                                      delay(5); // Wait 5ms
                                      current = digitalRead(button); // Read it again
                                      }
                                      return current; // Return the current value
                                      }

                                      Now you just call it with whichever button is pressed so it can all be handled:

                                      // My device has a button that changes the room (location)
                                      // The last argument is the button handler code (pointer to function)
                                      checkButton(ROOM_BTN,roomBtnPrev,roomBtnCurrent,checkChangeRoomButton);

                                      // It also has a button that turns data writing (to SD Card) on / off
                                      checkButton(DATA_BTN, dataBtnPrev, dataBtnCurrent, checkWriteDataButton);

                                      Now they are both handled the same way and all the debouncing is wrapped up. What do you think?

                                      B Offline
                                      B Offline
                                      BillWoodruff
                                      wrote on last edited by
                                      #26

                                      raddevus wrote:

                                      What do you think?

                                      I think this "belongs" on one of the technical forums ... but, given the general neglect of many forums, and the free-for-all the Lounge has become, I am just "blowing smoke" :wtf: :)

                                      «The mind is not a vessel to be filled but a fire to be kindled» Plutarch

                                      Mircea NeacsuM 1 Reply Last reply
                                      0
                                      • H honey the codewitch

                                        I totally get what you're saying. Just for clarity though template-instance statics add another dimension to statics because they are not shared between different instantiations of the same template.

                                        template struct foo final {
                                        static int value;
                                        };
                                        ...

                                        ...
                                        foo<1>::value = 5;
                                        foo<2>::value = 4;
                                        printf("%d + %d = %d\n",foo<1>::value,foo<2>::value,foo<1>::value+foo<2>::value);
                                        // prints 5 + 4 = 9

                                        To err is human. Fortune favors the monsters.

                                        G Offline
                                        G Offline
                                        Gary Wheeler
                                        wrote on last edited by
                                        #27

                                        Congratulations, your Witch-ness! You have successfully taught an Old Dog a wonderful new trick! :-\

                                        Software Zen: delete this;

                                        H 1 Reply Last reply
                                        0
                                        • G Gary Wheeler

                                          Congratulations, your Witch-ness! You have successfully taught an Old Dog a wonderful new trick! :-\

                                          Software Zen: delete this;

                                          H Offline
                                          H Offline
                                          honey the codewitch
                                          wrote on last edited by
                                          #28

                                          I didn't tell you the downside. You must initialize the statics to avoid a linker error, and I don't know about C++20 but previous versions require declarations like this for statics:

                                          template
                                          int_button*
                                          int_button::m_this = nullptr;

                                          To err is human. Fortune favors the monsters.

                                          G 1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups