and you totally ignore the button press that brings the cycle to 0 every time it does.
So the user of your device sees
button works
button works
button works
button works
button does nothing
rinse and repeat.
Which is why I recommend you change it (back) to do the test of equality 0 1 2 and 3 using the count modulo 4…
Zero is a perfectly good number, there is no reason not to use it in this case. Having a hiccup in the button as you will have if you insist on testing 1 2 3 and 4 under a modulo 5 scenario is a bad idea. It’s something you’d need to explain to anyone else and you may find it making you wonder about what’s going on one day.
Perhaps not so important with this small toy you are developing, but srsly I ask you what your opinion might be about something you use every day, like you microwave oven, just appearing to ignore a button once every five time you push it…
But I never argue with success: if you feel you’ve succeeded I say good work, well done and good day! Or night, really.
With 0 1 2 3 it does not work at all. All returned numbers are not correct. It returns 10000 instead of 12,500 with one press 8000 instead of 10000 with two presses and so on...
When the sketch starts, consider that you have "selected" the 0 indexed set of parameters.
So one press on any button will move you to the next, or second (1 indexed) parameter.
If you don't like the order of the selection, simply move them around. But I see nothing wrong with starting with something (like a default).
But you have other problems I am only noticing as I waste spend time on this.
ezButton behaves badly if you don't
button4.loop(); // MUST call the loop() function first
for example, very frequently.
Since you go blind to input and kill your loop with the for statement that does the pulse output, I was unable to make EZ button 4 control the pulse output section so it would do the train once and only once… I asked before: how are you handling that? To do the for loop once per button 4 press?
I think you've got some thinking to do about the calculations around ledon, ledoff, runtime and so forth.
If this means 12.5 ms period (80 Hz) 90 % duty cycle for 6 seconds the countt is OK but the ledon and ledoff times are 1000 times too large?
delayMicroseconds takes a sixteen bit Arduino int and you feeding it huge numbers which basically means you are getting only the bottom 16 bits of that number.
Which means you havent really looked at the output to check for basic plausible behaviour. Which raises the question: how are you determining that you have successfully generated the pulse train you set up with the selected parameters? Because you aren't yet.
Here in wokwi is your program with my ideas working way better:
Look closely. Play with it.
I use my modulo idea. It works perfectly.
I fixed (I think) your maths and calls to delayMicroseconds
I removed button 4 from the purview of ezButton and just used pinMode and digitalRead.
[This is why I hate and avoid libraries when I can. They give with one hand and (for me) invariably get aroufd to taking, often more than they gave, with the other. Hand.]
I left some printing and debugging stuff in there. I bumped up you baud rate to something more 21st century.
Please try it. Read the code carefully.
You may want to consider adding something to suspend a 30 second train run. I found myself using the reset button quite a bit, 30 seconds accidental selected is an eternity to wait while your blind for loop finiches.
Good catch with ledOn and LedOf. ledOn+ledOFF= period. I aslo fixed runtime.
The code does not work because it does not allow to select 4 parameters for each variable. It allows to select 3 parameters and then rolls over. it is a problem.
It works with 5 or with if (btnCount == n). It does not roll over but it can be resolved with reset or resetting the counter to 0.
Why treating button4 the same way as other buttons is a problem? I killed the loop with
if ( btn4Count > 0)... because I did not want an accidental button press to change the parameter when the program is being executed. What I'm building is not a toy it is a cosmetology device. It will have only one end user- my wife. Ideally it would have only one button but even then she would probably argue about the way to operate it.
The bigger problem is the button bouncing. I don't know if something in the code interferes with the button reading or the debouncing algorithm of ezButton library does not work with the membrane switch. I've tested the code written by st3v3n92 and there is no bouncing problem with his code.
This is output from my code as seen on the wokwi. If you are getting different results, you are doing something different. Than running that code. Or you've broken it accidentally.
Here I step through the 4 periods then I step through the four powers. Trust me when I say I could as well step through the four runtimes - or any combination of any of your parameters.
It works with 5
5 does not enter into my program. Forget about 5. Learn about 0. 0 1 2 3. If you need to have one press mean a particular value, rearrange the order they are matched to the count mod 4.
All I did below was remove duplicate lines listing the parameter indices and put some space to move the parameter I was changing out where you wouldn't miss it.
ezButton works, as long as you call the buttonX.loop() function very frequently OR stay off the button before, throughout and after anything that blocks the processor from doing the button.loop.
The only button you had that was susceptible to that was button 4, which causes entry to the for loop, which ties up the processor.
I did not want an accidental button press to change the parameter when the program is being executed.
That makes no sense. When the "program is being executed" is all the time. You want to be able to change parameters. Unless you meant "when the pulses are being generated", which also makes no sense, because... ezButton is blind, you can press all the buttons you want when the for loop keeping your loop from looping and calling buttonN.loop().
If on the third hand you mean to have the pulse train repeat continuously (started over right away again and again) and you don't want the parameters to change, then you should change the logic of your program so once the pulse trains are running, ignore the buttons for the parameters.
Hello Modulo 4 World!
1 0 0 1
period: 10000.00
power: 90.00
ledon: 9000.00
ledoff: 1000.00
runtime: 6.00
runtime: countt:
600.00
running the train now
it took 6 seconds
2 0 0 1
period: 4000.00
power: 90.00
ledon: 3600.00
ledoff: 400.00
runtime: 6.00
runtime: countt:
1500.00
running the train now
it took 6 seconds
3 0 0 1
period: 2000.00
power: 90.00
ledon: 1800.00
ledoff: 200.00
runtime: 6.00
runtime: countt:
3000.00
running the train now
it took 6 seconds
0 0 0 1
period: 12500.00
power: 90.00
ledon: 11250.00
ledoff: 1250.00
runtime: 6.00
runtime: countt:
480.00
running the train now
it took 6 seconds
0 1 0 1
period: 12500.00
power: 80.00
ledon: 10000.00
ledoff: 2500.00
runtime: 6.00
runtime: countt:
480.00
running the train now
it took 6 seconds
0 2 0 1
period: 12500.00
power: 60.00
ledon: 7500.00
ledoff: 5000.00
runtime: 6.00
runtime: countt:
480.00
running the train now
it took 6 seconds
0 3 0 1
period: 12500.00
power: 40.00
ledon: 5000.00
ledoff: 7500.00
runtime: 6.00
runtime: countt:
480.00
running the train now
it took 6 seconds
0 0 0 1
period: 12500.00
power: 90.00
ledon: 11250.00
ledoff: 1250.00
runtime: 6.00
runtime: countt:
480.00
running the train now
it took 6 seconds
0 0 0 0
I had more faith in your code than you . It works and the pulse has a better front than with mine. I wander why? I will post a pic. The only problem that I have is timing. I extended run time in the matrix array to:
uint16_t runtimes[] = { 600000, 800000, 2000000, 3000000 }
1 button press gives me 10176 instead of 600000.
2 button presees gives me 13568
3 -- 33920 and incorrect led
4 -- 50880
My bad. I have not changed the bound rate so when I was checking serial monitor I was getting some symbols.
After you removed Button 4 from ezButton the bouncing problem is gone! I still don't get it as other buttons are called once and there is no bounce problem.
When I had all variables as int except ledon ledof that were float the code did not work. I had to use float for the period and power to make it work.
I've changed the float to unassigned long. The code is working and here is what I'm getting on the scope for 4 ms period
The only array of runtimes is in @anon46966594's version, and his values are very small…
Besides the fact that 600000 doesn't fit in an uint16_t.
65535 is the largest 16 bit unsigned integer.
And (drum roll)
600000 modulo 65536 is 10176
So whose code Well never mind, just post the code you are calling happy now, and describe anything that is not yet 100 percent what you want.
As for ezButton, I tried to 'splain what is happening with button number 4. Is it your claim that my fix for button 4 somehow fixed buttons 1, 2 and 3 bouncing problem?
Impossible! <- say with French accent.
BTW my dumb button 4 fix I think gives you an ability. If you put a switch there instead of a button, switching it on (or holding down the pushbutton) will make the pulse train will repeat over and over.
I got away with simple button 4 code because the pulse train takes some time, plenty of time to get one's finger off the buttton.
I did preface it by saying that the LED code and maths/values would likely need changing as I couldn't test anything out in Wokwi to see the effects properly... Nor did I fully understand quite what the 'goal' effect was from the LED.... but if @aiasnikov wants to use mine as a base for editing as the structure is quite well suited to his needs, then feel free!
I increased the time in st3v3n92 code without knowing that I went over the size limit. It should be an easy fix just changing var to unassigned long, Interesting that his code makes better pulse which does not really matter in this case but with much shorter pulses it would.
What? There is nothing in the software that can explain that. You have a loose wire, or a grounding problem, or a bad scope probe or something…
The code lines that actually make the pulse train are functional identical in every version anyone has presented: a loop that turns on and off an output pin…
Here is the final code.
I've got some rotary switches but I think I can live with the keypad for now. I designed the board first and then started working on a code. I used to make my own boards but I'm ordering them from China so I'm stuck with ATTINY 85 on the board. I thought I could get away with three buttons so I've got only one free pin left (reset). I can lose the reset and put a LED on it. it will blink the number of button presses. It would be better to add a screen. I've got some including the one that is run on two wires. I suppose it is possible to replace Button4 with the long press of another button to start the program. Anyway the major problem that I currently have is that the button counters don't reset to 0 after LED finish blinking and I have no clue how to do it.
#include <ezButton.h>
const int ledPin = 11;
ezButton button1(3); // create Button object that attach to pin 2;
ezButton button2(2); // create Button object that attach to pin 3;
ezButton button3(5);
// ezButton button4(4);
# define doItPin 4
unsigned long period = 0;
unsigned long power = 0;
int runtime = 0;
unsigned long ledon = 0;
unsigned long ledoff = 0;
unsigned long countt = 0;
void setup() {
Serial.begin(115200); // 9600? 1980 called and wants its baud rate back!
Serial.println("Hello Modulo 4 World!");
pinMode(ledPin, OUTPUT);
button1.setDebounceTime(25); // set debounce time to 25 milliseconds PLENTY.
button2.setDebounceTime(25);
button3.setDebounceTime(25);
// button4.setDebounceTime(25);
pinMode(doItPin, INPUT_PULLUP);
button1.setCountMode(COUNT_FALLING);
button2.setCountMode(COUNT_FALLING);
button3.setCountMode(COUNT_FALLING);
// button4.setCountMode(COUNT_FALLING);
}
void loop() {
button1.loop(); // MUST call the loop() function first
button2.loop(); // MUST call the loop() function first
button3.loop();
// button4.loop();
int btn1State = button1.getState();
int btn2State = button2.getState();
int btn3State = button3.getState();
// int btn4State = button4.getState();
unsigned long btn1Count = button1.getCount();
unsigned long btn2Count = button2.getCount();
unsigned long btn3Count = button3.getCount();
// unsigned long btn4Count = button4.getCount();
unsigned char doTheThing = !digitalRead(doItPin);
Serial.print(btn1Count % 4); Serial.print(" ");
Serial.print(btn2Count % 4); Serial.print(" ");
Serial.print(btn3Count % 4 ); Serial.print(" ");
Serial.print(doTheThing); Serial.print(" ");
Serial.print(" ");
if ((btn1Count % 4) == 0) {
period = 2000;
}
else if ((btn1Count % 4) == 1) {
period = 12500;
}
else if ((btn1Count % 4) == 2) {
period = 10000;
}
else if ((btn1Count % 4) == 3) {
period = 4000;
}
if ((btn2Count % 4) == 0) {
power = 40;
}
else if ((btn2Count % 4) == 1) {
power = 90;
}
else if ((btn2Count % 4) == 2) {
power = 80;
}
else if ((btn2Count % 4) == 3) {
power = 60;
}
if ((btn3Count % 4) == 0) {
runtime = 30; // runtime in sec
}
else if ((btn3Count % 4) == 1) {
runtime = 6;
}
else if ((btn3Count % 4) == 2) {
runtime = 8;
}
else if ((btn3Count % 4) == 3) {
runtime = 20;
}
static long previousBtn4Count = 0;
if (doTheThing) {
ledon = period * power/100;
ledoff = period * (100 - power)/100;
countt = runtime*60000000/ period;
Serial.println("");
Serial.print("period: ");
Serial.println(period);
Serial.print("power: ");
Serial.println(power);
Serial.print("ledon: ");
Serial.println(ledon);
Serial.print("ledoff: ");
Serial.println(ledoff);
Serial.print("runtime: ");
Serial.println(runtime);
Serial.print("runtime: ");
Serial.println("countt:");
Serial.println(countt);
// fork();
Serial.println("running the train now");
unsigned long now = millis();
for (int y = 0; y < countt - 1; y++) {
digitalWrite(ledPin, HIGH);
delayMicroseconds(ledon);
digitalWrite(ledPin, LOW);
delayMicroseconds(ledoff);
}
Serial.print(" it took ");
Serial.print((millis() - now) / 1000);
Serial.println(" seconds ");
}
Serial.println("");
}
// stick a fork in this turkey [freeze the program]
void fork()
{
Serial.println("\nFORK!\n");
for (; ; );
}
Pro tip: libraries are sometimes documented. This one was.
Pro tip: reading the code of libraries can turn up stuff that is under- or not documented.
No matter the documentation, the code is the truth.
There is no code ends up in your program that isn’t on your computer when you compile and upload a program. Somewhere.
BTW this is a good place for anyone following along to figure out that making PCBs before the hardware and software have kinda formed up a bit can be a problem.
Also, you can delete the fork() function - it is no longer called, it was just a thing to stop the program dead in its tracks which I found necessary before it got a little more, erm, tame.
What I meant is that after LED completes its cycle button counter keeps its last value. Buton. reset.Count() solved it. I think I have a final code for now. Thank you very much for your help!