Latching Push button on nano & Wemos D1 mini

Hi all,

I would like to interface my board with 1 push button.
Starting from initial status = 0; if i press it once i want to see the value 1, two times the value 2 and so on, when i reach the maximum value, it has to restart from 0.

i would also like to write this code so that i can add more push buttons later without rewriting many lines for each PB, so i would like to make an object that i can call in just one line.

So i wrote this:

//===PB Latching===//
int PB0as = 0;   // Actual Status
int PB0ns = 0;   // New Status
int PB0os = 1;   // Old Status  
int PB0sq = 5;   // StatusQty, 2=on/off; 3=a,b,c etc.

int prevPB0as = 0;

const int PB0Pin = 4; // On nano
// const int PB0Pin = D4; //On Wemos D1 mini

void setup() {
  delay(2000);
  Serial.begin(115200); 
  pinMode(PB0Pin, INPUT_PULLUP);
  Serial.println(">>>Setup complete<<<");
}

void loop() {
  PB0ns= !digitalRead(PB0Pin);
  PBoperation (PB0as, PB0ns, PB0os, PB0sq );
  if (PB0as!=prevPB0as) {
    Serial.println(PB0as);
    prevPB0as = PB0as;
  }
}

//////////========== Push Button Latching ==========//////////
int PBoperation(int &Status, int &New, int &Old, int &StatusQty) {
  if (Old==0 && New ==1) { // Rising front
    Status++;
    if (Status >= StatusQty) Status = 0;
  }
  Old=New;     
}

This code works very well on nano, without any problem, but on my Wemos D1 mini it has a very strange behaviour, it resets all the time and on the serial this appears:

>>>Setup complete<<<

--------------- CUT HERE FOR EXCEPTION DECODER ---------------

Exception (0):
epc1=0x40203faa epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000

>>>stack>>>

ctx: cont
sp: 3ffffe00 end: 3fffffc0 offset: 0190
3fffff90:  3fffdad0 00000000 3ffee500 40201058  
3fffffa0:  feefeffe feefeffe 3ffee554 402018e8  
3fffffb0:  feefeffe feefeffe 3ffe85e0 40100b95  
<<<stack<<<

--------------- CUT HERE FOR EXCEPTION DECODER ---------------

 ets Jan  8 2013,rst cause:2, boot mode:(3,7)

load 0x4010f000, len 3460, room 16 
tail 4
chksum 0xcc
load 0x3fff20b8, len 40, room 4 
tail 4
chksum 0xc9
csum 0xc9
v00041c90
~ld

Does anyone have any idea why and a solution to this problem?

I'm not an advanced programmer and don't really understand pointer mechanics, I think the problem is in the "&" in front of the variable in PBoperation, what do you think?

Who wrote it?

Is in your post the full code that crashes on one processor but not the other?

Code is code. It shouldn’t be an ‘&’ you don’t understand making it break between the two processors.

What are the differences between the two boards? One looks to be speed, with buttons that cou,d change behaviour. But it should not cause a crash like that.

Also have you verified the input pin works? Again, not something that would crash…

Your code functions OK on a UNO I have attached just now.

Does reset happen when you press the button or at another time also? How soon does it happen? Is anything else attached to your board?

a7

Your PBoperation() function promises to return an int but it fails to honour that promise and does not return a value. I assume that the ESP8266 core is less tolerant to such lies than the AVR core

This is somewhat ironic because it does not need to return a value at all because it operates on global variables and neither do they need to be passed to the function and certainly not to be passed by reference

Declare the function void and it compiles OK and you might as well remove all the parameters from the call to the function and from the function definition and change the variables in the function to their global names

1 Like

I don`t fully understand some of your questions but i think that you are tying to help me, so thank you:

Who wrote it?
-> hard to believe, but I wrote it myself :smiley:

Is in your post the full code that crashes on one processor but not the other?
-> Yes it is the full code they differ only in pin number (4 on nano, D4 on Wemos)

Code is code. It shouldn’t be an ‘&’ you don’t understand making it break between the two processors.
-> I dont understand what you mean, the idea is that since an object cant return more than a variable or an array is to use those pointers to write in global variables the variables in the object. I made many research on the correct usage of those pointers but never found a tutorial that explain fully how it works, so i just guessed, and on the Nano is working.

What are the differences between the two boards? One looks to be speed, with buttons that cou,d change behaviour.
-> One is Arduino Nano and the other is Wemos D1 mini with WiFi functionality integrated, i don`t understand what you mean with "looks to be speed" and "button that could change behaviour", the button is a normal NO, Momentary push button.

Also have you verified the input pin works?
-> yes both work fine, I read 1 when they are not pressed and 0 when I press the button on both boards.

Does reset happen when you press the button or at another time also? How soon does it happen?
-> no its restart continuosly, i put a "delay(2000);" in setup() because without it the message was repeating too fast.

Is anything else attached to your board?
-> no only one push button from the pin to the ground.

Thank you for your reply, but probably my English and programming skill does not match the required level to understand your reply, could you please show me an example?
My objective is to make a push button latching function that i can use for any other push button if i need to add here or also in other projects.

Interesting idea!

//////////========== Push Button Latching ==========//////////
int PBoperation(int &Status, int &New, int &Old, int &StatusQty) {
  if (Old==0 && New ==1) { // Rising front
    Status++;
    if (Status >= StatusQty) Status = 0;
  }
  Old=New;     
}

@kaname08 just change "int PBoperation(" in the above to "void PBoperation(", that makes the function legitimately one that does not return a value.

And removes the warning you were overlooking or haven't turned on about that function!

To test @UKHeliBob's theory. It's gotta be the thing here.

a7

1 Like

Wow! Thank you very much, it`s working correctly now!!

Even better, don't bother passing global variables to the function and certainly not by reference

//===PB Latching===//
int PB0as = 0;   // Actual Status
int PB0ns = 0;   // New Status
int PB0os = 1;   // Old Status
int PB0sq = 5;   // StatusQty, 2=on/off; 3=a,b,c etc.

int prevPB0as = 0;

//const int PB0Pin = 4; // On nano
const int PB0Pin = D4; //On Wemos D1 mini

void setup()
{
  delay(2000);
  Serial.begin(115200);
  pinMode(PB0Pin, INPUT_PULLUP);
  Serial.println(">>>Setup complete<<<");
}

void loop()
{
  PB0ns = !digitalRead(PB0Pin);
  //  PBoperation (PB0as, PB0ns, PB0os, PB0sq );
  PBoperation ();
  if (PB0as != prevPB0as)
  {
    Serial.println(PB0as);
    prevPB0as = PB0as;
  }
}

//////////========== Push Button Latching ==========//////////
//int PBoperation(int &Status, int &New, int &Old, int &StatusQty) {
void PBoperation()
{
  if (PB0os == 0 && PB0ns == 1) // Rising front
  {
    PB0as++;
    if (PB0as >= PB0sq) PB0as = 0;
  }
  PB0os = PB0ns;
}

This version is working, but in case i want add an other PB1 i have to write an other PBoperation1 dedicated to this button, or I'm wrong?
The other my target was also make a single "PBoperation" for all push buttons to simplify and shorten as possible the code.

Nice. As @UKHeliBob was getting at, writing a function that claims to return an int but fails to actually do results in “undefined behaviour”, which is geek speak for “anything can happen”.

And anything can and in this case does vary: between processors or compiler implementations or possibly even the phase of the Moon.

You are on the verge to discover objects and classes. I don’t write them, but I can use them and it looks like all the details of your goal would be met with a simple (!) latching button class.

I don’t know how to ensure it, but sometimes ppl will fall all over themselves right here demonstrating how that would look in this kind of circumstance.

a7

If you want to write a general purpose PBoperation() function then you have a number of ways to do it

One way would be to use global variables but to put them into an array of structs such that each level of the array holds the data for a particular switch. Pass the switch number to the function and use it as the index to the array to access the appropriate variables. Pass back a boolean indicating whether the state of the switch has changed if that is important to know or just use the values in the global array of structs in the main section of the code

I realise that this probably raises all sorts of questions for you such as what is a struct, and I don't know what your level of knowledge about arrays is, but writing a separate function to handle each switch is not the way to do what you want efficiently

I've been googling to see what turns up about functions that fail to return a value, as in this case.

I understand evidence-based programming, that is to say a diagnosis is made, a treatment proposed and the success of the treatment is accepted as evidence of the validity of the diagnosis.

Here I missed the problem, but I might have hoped that not returning a value wasOK. Using the function's return value would, however, be bad. Possibly very.

From 2012 and C99

So is it different now with whatever C++ version we are using?

If the 2012/C99 thing is still, then it means something else must have been going on in the original code.

a7

There was plenty going on which makes the exact problem difficult to diagnose

  • not returning a value
  • passing global variables
  • passing those variables by reference

Not really. That is all the plainest of vanilla code. OK, maybe some chocolate sprinkles for the use of pass by reference.

If this code blew up everywhere for everyone in all ways they chose to test it, it would make sense to look extremely closely at what appears to be obvious programming. All 36 lines of code.

However:

The OP's code reads fine, works on two Arduino platforms and as logic separated for analysis performs correctly under two other compilation scenarios. In one other case, the code misbehaves rather badly. In terms of mystery errors, there is actually very little going on in the code which might explain it. No arrays, no Strings, no loops &c.

So I come to a different conclusions.

Until someone says that the C99/2012 standard language I quoted earlier is inoperative, or can explain how I may have less than completely understood it, it is plain that the ESP8266 compiled code came out with errors, compiler errors.

The ESP8266 compiler is non-compliant.

a7

Whatever is causing it, the problem is easy to reproduce

void setup()
{
  Serial.begin(115200);
  testFuncA();
}

void loop()
{
}

int testFuncA()
{
}

I would assume that the call to testFuncA() and the function itself would be optimised away, but maybe not

Interestingly, removing the Serial.begin() stops the crash occurring

How do we prove that it is a compiler bug ?

Compiling the same code that causes a crash on the ESP8266 for an ESP32 gives the following error message

Arduino: 1.8.13 (Windows 10), Board: "WEMOS D1 MINI ESP32 BBB, 80MHz, Default, 240MHz (WiFi/BT), 921600"

C:\Users\Bob2\AppData\Local\Temp\arduino_modified_sketch_645421\sketch_jun19c.ino: In function 'int testFuncA()':

sketch_jun19c:13:1: error: no return statement in function returning non-void [-Werror=return-type]

 }

 ^

cc1plus.exe: some warnings being treated as errors

exit status 1

no return statement in function returning non-void [-Werror=return-type]



This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.