How to pause a void in C++ Arduino Uno - c++

My question is very simple but I'm stuck on it for a while now.
I need to make a script that when pushed on a button loop a() is put on pause. And when you press it again it should go from where it ended. But I can't figure out a way to do it.
I hope someone can help me.
This is my code:
int Aan = 1;
int Uit = 0;
int analogPin = A3;
int LED1 = 13;
int LED2 = 12;
int LED3 = 11;
int LED4 = 10;
int val;
bool r = false;
void setup() {
pinMode(analogPin, INPUT_PULLUP);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
pinMode(LED4, OUTPUT);
digitalWrite(LED1, Aan);
digitalWrite(LED2, Aan);
digitalWrite(LED3, Aan);
digitalWrite(LED4, Aan);
}
void loop() {
val = digitalRead(analogPin);
if (val == LOW)
{
if (r == true)
{
r = false;
}
if (r == false)
{
r = true;
}
}
if (r == true)
{
a();
}
}
void a() {
for (int i = 10; i <= 13; i++)
{
pinMode(i, OUTPUT);
digitalWrite(i, Uit);
delay(100);
digitalWrite(i, Aan);
}
for (int i = 13; i >= 10; i--)
{
pinMode(i, OUTPUT);
digitalWrite(i, Uit);
delay(100);
digitalWrite(i, Aan);
}
}
Just to explain whats happening.. Void a() makes 4 different leds light up and go out. The pattern thats used is Knight Rider (If you don't know the tv show just google the car of him)

I will assume you want the "Knight Rider" pattern to constantly run.
I've made a couple of changes. First, I added a function to run the led sequence one way. Second, I added a while loop that will always run once, and will continue to run while the button is pushed.
bool paused = false;
int buttonState = HIGH;
void loop() {
a();
}
// This only works if leds ports are consecutive
void runSequence(int ledStart, int ledEnd)
{
int direction = ledStart < ledEnd ? 1 : -1;
for (int i = ledStart; i != ledEnd + direction; i += direction) {
digitalWrite(i, Uit);
do {
delay(100);
} while (LOW == digitalRead(analogPin)); // Check button state
digitalWrite(i, Aan);
}
}
void a() {
runSequence(LED4, LED1);
runSequence(LED1, LED4);
}
EDIT Changes based on comment
bool paused = false;
int buttonState = HIGH;
int currentLED = LED1;
int currentDirection = -1;
void loop() {
checkButton();
if (!paused) {
// Flash the led
digitalWrite(currentLED, Uit);
delay(100);
digitalWrite(currentLED, Aan);
// Change direction?
if (LED1 == currentLED || LED4 == currentLED) {
currentDirection *= -1;
}
// Setup for next iteration
currentLED += currentDirection;
}
}
void checkButton() {
int state = digitalRead(analogPin);
// Check if button state has changed
if (state != buttonState) {
buttonState = state;
// Change paused state when button is released
if (state == HIGH) {
paused = !paused;
}
}
}

Inside your a() function put another while loop which becomes false when the button is Up.
Like:
while(digitalRead(analogPin) == LOW)
{
}
As long as the button is pressed down the loop will continue. When you release the button the program will exit the loop and continue execution of your code.

Related

how do i call a function in loop from another function in void loop arduino

#define CLK 2
#define DT 3
#define SW 4
#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(0x27);
int counter = 0;
int currentStateCLK;
int lastStateCLK;
int lastCLK,cnt=0,btnState,lastPress=0;
String currentDir ="";
unsigned long lastButtonPress = 0;
char *mainmenu[] ={"SET MODE","SET TEMP","SET HUMD","SERVO","RESET"};
char *setmode[] ={"INCUBATOR","HATCHER","BACK"};
void setup() {
// Set encoder pins as inputs
Wire.begin();
Wire.beginTransmission(0x27);
pinMode(CLK,INPUT);
pinMode(DT,INPUT);
pinMode(SW, INPUT_PULLUP);
lcd.begin(16, 2);
lcd.setBacklight(255);
lcd.home(); lcd.clear();
Serial.begin(9600);
lastStateCLK = digitalRead(CLK);
delay(100);
if(EEPROM_READ(0)==NULL){
SET_MODE();
}
Serial.print(EEPROM_READ(0));
}
void loop(){
disp();
rot();
}
void disp(){
lcd.setCursor(0,0);
lcd.print(" KGF");
}
void rot() {
int lim=sizeof(mainmenu)/2;
Serial.print(lim);
currentStateCLK = digitalRead(CLK);
if (currentStateCLK != lastStateCLK && currentStateCLK == 1){
lcd.clear();
lcd.setCursor(0, 1);
if (digitalRead(DT) != currentStateCLK) {
counter --;
if(counter<0){
counter=lim-1;
}
}
else {
// Encoder is rotating CW so increment
counter ++;
if(counter>lim-1){
counter=0;
}
lcd.print(mainmenu[counter]);
}
lastStateCLK = currentStateCLK;
int btnState = digitalRead(SW);
if (btnState == LOW) {
//if 50ms have passed since last LOW pulse, it means that the
//button has been pressed, released and pressed again
if (millis() - lastButtonPress > 50) {
if(counter==0){
SET_MODE();
}
}
}
lastButtonPress = millis();
}
delay(1);
}
void SET_MODE(){
int lim=sizeof(setmode)/2;
int currentCLK = digitalRead(CLK);
if (currentCLK != lastCLK && currentCLK == 1){
lcd.clear();
lcd.setCursor(0, 1);
if (digitalRead(DT) != currentCLK) {
cnt --;
if(cnt<0){
cnt=lim-1;
}
}
else {
// Encoder is rotating CW so increment
cnt ++;
if(cnt>lim-1){
cnt=0;
}
}
lcd.print(setmode[cnt]);
}
lastCLK = currentCLK;
btnState = digitalRead(SW);
if (btnState == LOW) {
//if 50ms have passed since last LOW pulse, it means that the
//button has been pressed, released and pressed again
if (millis() - lastButtonPress > 50) {
if(setmode[cnt]=="BACK"){
exit(0);
}
lcd.clear();
lcd.setCursor(0, 1);
EEPROM_WRITE(0,setmode[cnt]);
lcd.print("DONE");
}
lastPress = millis();
}
delay(1);
}
void EEPROM_WRITE(int addrOffset, const String &strToWrite)
{
byte len = strToWrite.length();
EEPROM.write(addrOffset, len);
for (int i = 0; i < len; i++)
{
EEPROM.write(addrOffset + 1 + i, strToWrite[i]);
}
}
String EEPROM_READ(int addrOffset)
{
int newStrLen = EEPROM.read(addrOffset);
char data[newStrLen + 1];
for (int i = 0; i < newStrLen; i++)
{
data[i] = EEPROM.read(addrOffset + 1 + i);
}
data[newStrLen] = '\0';
return String(data);
}
I want to call the SET_MODE() function in the loop from rot() function, I am building a menu based program so the SET MODE menu should redirect to the SET_MODE() function, and as I will be adding more menu and sub-menus how can I perform this task.
The SET_MODE() function doesn't work in loop I do not know why, it only works when I all it under void loop() directly.

How can I call three different functions based on if my button was A) just pressed, B) being held Down and C) Just released?

I'm writing an Arduino program to control a minigun for a friend's cosplay. I need to write a program that when the button is pressed the motor ramps up from 0 to a given value (for now lets say "analogWrite(output_pin,200);") then loop at that RPM until the button is released, at which point it needs to ramp down back to zero.
When I try to put ramping into a loop it doesn't finish the code. I
I need something like this in c++ code for the Arduino button. (I've tried similar things using the "delay" function to no avail)
motorspeed = 0
if buttonpress == True:
buttonheld = True
for i in range (0,10):
delay(1)
motorspeed =+ 20
if buttonpress == False:
motorspeed = 0
if buttonheld == True:
motorspeed = 200
if buttonpress == False:
for i in range(0,10):
delay(1)
motorspeed =- 20
else:
#shut off motor
#Play error sound
Here is the current code that only runs the motor at one speed when the button is held down.
const int button1 =4;
int BUTTONstate1 = 0;
void setup()
{
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(9, OUTPUT);
pinMode(button1, INPUT);
}
void loop()
{
//set button to read
BUTTONstate1 = digitalRead(button1);
//if button is pressed
if (BUTTONstate1 == HIGH)
{
//run current through motor
digitalWrite(2, LOW);
digitalWrite(3, HIGH);
//set speed
//Rampup
analogWrite(9,200);
}
else
{
digitalWrite(2, LOW);
digitalWrite(3, LOW);
}
}
Here is a virtual environment for the circuit
https://www.tinkercad.com/things/cLOBc9JJuTz-copy-of-dayloncircuitrefinecode/editel?sharecode=b6cqTLlNqUCCN09-mQ_zykp5sMnXx6KLt_KNqlXJmcs
I would recommend using interrupts, it's pretty well documented in Arduino reference:
Arduino reference - Interrupts
Most helpful is "Parameters" and "Example code" section. I think you should prepare two methods and attach interrupt to your input (button) pin on RISING and FALLING trigger.
Make sure that the button pin can be used for interrupt (on Arduino UNO / NANO only pin 2 and 3).
I think it should look similar to this (I haven't tested that):
#define buttonPin 2; // pin usable for interrupt
#define outputPin 9;
#define powerPinA 3;
#define powerPinB 4;
bool running = false;
int currentSpeed = 0;
void buttonUp()
{
digitalWrite(powerPinA, LOW);
digitalWrite(powerPinB, LOW);
running = false;
}
void buttonDown()
{
digitalWrite(powerPinA, LOW);
digitalWrite(powerPinB, HIGH);
running = true;
}
void setup()
{
pinMode(outputPin, OUTPUT);
pinMode(powerPinA, OUTPUT);
pinMode(powerPinB, OUTPUT);
pinMode(buttonPin, INPUT);
attachInterrupt(digitalPinToInterrupt(interruptPin), buttonUp, RAISING);
attachInterrupt(digitalPinToInterrupt(interruptPin), buttonDown, FALLING);
}
void loop()
{
delay(1);
if (running && currentSpeed < 200)
currentSpeed += 20;
else if (!running && currentSpeed > 0)
currentSpeed -= 20;
analogWrite(outputPin, currentSpeed);
}
Here's an example that doesn't rely on any interrupts. Just reading the button and remembering the state in a variable and remembering the time of the last step in a variable to check against millis() (Compiled but Untested)
int buttonPin = 5;
int lastButtonState = HIGH;
unsigned long lastRampStep;
unsigned int stepTime = 10; // 10ms steps. Set to whatever you want.
int analogPin = 3;
int analogLevel = 0;
int maxLevel = 200;
int analogStepSize = 10;
void setup() {
pinMode(buttonPin, INPUT_PULLUP); // will read LOW when pressed
}
void loop() {
int buttonState = digitalRead(buttonPin);
if (buttonState != lastButtonState) {
// The button just changed!
if (buttonState == LOW) {
// was just now pressed
analogLevel = 0; // start ramp up
lastRampStep = millis(); // note the time that we took this step
} else {
// Button just released.
// not sure what you want to happen here
}
}
else if (buttonState == LOW) {
// While button is held ramp until we reach the max level
if(analogLevel < maxLevel){
if(millis() - lastRampStep >= stepTime){
analogLevel += analogStepSize;
lastRampStep = millis();
}
}
} else {
// While button is released (HIGH) ramp back down:
if(analogLevel > 0){
if(millis() - lastRampStep >= stepTime){
analogLevel -= analogStepSize;
lastRampStep = millis();
}
}
}
analogWrite(analogPin, analogLevel);
lastButtonState = buttonState;
}
You could use interrupts to handle pressed/release, set a value, and handle the ramp up/down in the loop.
Keep in mind that you should also debounce the button.
Below is some pseudocode:
const byte maxLevel = 200; // some example values (max 255)
const int rampDelay = 5;
volatile byte targetLevel = 0;
byte currentLevel = 0;
// ...
ISR for Button { // Could be in one ore two ISR's
if pressed
targetLevel = maxLevel;
// possible other calls
if released
targetLevel = 0;
// possible other calls
}
void loop()
{
if (currentLevel < targetLevel) {
SetLevel(++currentLevel);
}
else if (currentLevel > targetLevel) {
SetLevel(--currentLevel);
}
// if currentLevel == targetLevel nothing changes
// if your device is battery powered you could even put the mcu
// to sleep when both levels are zero (and wake up from the ISR)
// no need for constantly polling the button when using ISR
delay(rampDelay);
}
This will also start ramping down immediately if the button is released before the motor is at full speed.

Double click "Laser On" Double click "Laser Off" - Arduino

Thank you all for your time.
I Have my code that when I keep holding the button the laser turn on "HIGH"
when I release my finger from the button the laser turns off "LOW"
But I want when I double click the laser turn on and when I double click again the laser turn off.
Thank you and sorry for my bad English.
const int btn = 6;// The push button
int previousButtonStateLAZER = HIGH; // for btn6
void setup(){
pinMode(btn, INPUT);
pinMode (laserPin, OUTPUT);
}
void loop(){
int buttonStateLAZER = digitalRead(btn);
// if the button state has changed,
if (buttonStateLAZER != previousButtonStateLAZER){
if( buttonStateLAZER == HIGH ) {
digitalWrite (laserPin, HIGH);
}else{
digitalWrite (laserPin, LOW);
}
}
previousButtonStateLAZER = buttonStateLAZER;
}```
You need to store the last two times that a click was detected and then test to see if they occurred close enough together. Try this code out (edited from what you posted):
const int btn = 6;// The push button
int previousButtonStateLAZER = LOW; // for btn6
static long releaseTimes[2];
static int releaseIndex = 1;
static int laserStates[2];
static int laserIndex = 0;
void setup(){
pinMode(btn, INPUT);
pinMode (laserPin, OUTPUT);
releaseTimes[0] = 0;
releaseTimes[1] = 0;
laserStates[0] = LOW;
laserStates[1] = HIGH;
}
void loop(){
int buttonStateLAZER = digitalRead(btn);
// if the button state has changed,
if (buttonStateLAZER != previousButtonStateLAZER){
previousButtonStateLAZER = buttonStateLAZER;
if (buttonStateLAZER == HIGH) {
return;
}
releaseIndex = 1 - releaseIndex;
releaseTimes[releaseIndex] = millis();
if (abs(releaseTimes[0] - releaseTimes[1]) < 800) {
releaseTimes[0] = 0;
releaseTimes[1] = 0;
laserIndex = 1 - laserIndex;
digitalWrite(laserPin, laserStates[laserIndex]);
}
}
}

Arduino Continue with for-loop only when button is pressed

I have an int array of melodies. If i press the button it plays the whole song but if i put a break after the delay, than it just reset the i. How do i make it so that only after another button-press it continues? (i'm still a newbie at this sorry and thanks in advance)
int buttonPin = 12;
void setup()
{
// put your setup code here, to run once:
pinMode(buttonPin, INPUT);
}
void loop()
{
// put your main code here, to run repeatedly:
int buttonState = digitalRead(buttonPin);
for(int i = 0; i < sizeof(mariomelody); i++)
{
if(buttonState == HIGH)
{
tone(8, mariomelody[i], 70);
delay();
}
}
}
Stop the loop while the button press is still held in:
int buttonPin = 12;
void setup()
{
// put your setup code here, to run once:
pinMode(buttonPin, INPUT);
}
void loop()
{
// put your main code here, to run repeatedly:
int buttonState = digitalRead(buttonPin);
for(int i = 0; i < sizeof(mariomelody); i++)
{
if(buttonState == HIGH)
{
tone(8, mariomelody[i], 70);
delay();
}
while(digitalRead(buttonPin) == HIGH)
{
// wait until the button is released
}
while(digitalRead(buttonPin) == LOW)
{
//wait until the button is pressed again
}
}
}
I'm guessing that you want to play the melody while the button is pressed, and stop if the button is released.
Then it would be something like:
int i = 0;
void loop()
{
if(digitalRead(buttonPin) == HIGH)
{
tone(8, mariomelody[i], 70);
i = (i + 1) % sizeof(mariomelody);
delay();
}
}
To avoid resetting the position to the begin of the melody you need i to be a global variable.
If you want the button to switch on and off the melody you'll need another global variable playing:
bool playing = false;
void loop()
{
if(digitalRead(buttonPin) == HIGH)
{
playing = !playing;
while (digitalRead(buttonPin) == HIGH)
; //wait for release
}
if (playing) {
//the rest is the same
}
}

How can I blink a LED differently when I press a toggle button?

I'm trying to blink a LED according to press of toggle button. If I press the first toggle switch the first time, LED blinks at 5 Hz, when I press the toggle button for the second time, LED blink at 6 Hz and when I press the third time, LED turns off.
I tried using the program below, but It's not working as I wanted.
// constants won't change. They're used here to set pin numbers:
const int buttonPin = 7; // the number of the pushbutton pin
const int ledPin = 6; // the number of the LED pin
// variables will change:
int buttonState = 0;
// variable for reading the pushbutton status
void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
Serial.begin(9600);
}
void loop() {
int x=0;
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
Serial.print(x);
// check if the pushbutton is pressed. If it is, the buttonState is HIGH:
if (buttonState == HIGH && x==0) {
// turn LED on:
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
delay(1000);
Serial.print(x);
} else {
// turn LED off:
x = x+1;
}
if (buttonState == HIGH && x==1) {
// turn LED on:
digitalWrite(ledPin, HIGH);
delay(2000);
digitalWrite(ledPin, LOW);
delay(2000);
Serial.print(x);
} else {
// turn LED off:
digitalWrite(ledPin, LOW);
x = x+1;
}
if (buttonState == HIGH && x==2) {
// turn LED on:
digitalWrite(ledPin, HIGH);
delay(3000);
digitalWrite(ledPin, LOW);
delay(3000);
Serial.print(x);
} else {
// turn LED off:
digitalWrite(ledPin, LOW);
x = x+1;
}
if (buttonState == HIGH && x==3) {
// turn LED off:
digitalWrite(ledPin, LOW);
x = 0;
}
}
When I use this code it works for first case that is LED blinks at 1000 ms delay, but if I toggle switch it again works for first condition. How can I make it to execute second condition i.e. to blink at delay of 2000 ms?
Firstly this is your circuit. I tried this circuit and code and worked for me. I used interrupt for checking button state. And millis calculation is simple.
Frequency = 1 / Period
Period = Ton + Toff
6Hz = 1000 millis / T => T = 166 millis
166 = Ton + Toff (for %50 duty cycle Ton=Toff) => Ton = Toff = 83 millis
enter image description here
const int ledPin = 13;
const int buttonPin = 2;
int state = -1;
bool willLightOn = false;
unsigned long currentDelay = 0;
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(buttonPin), changeState, FALLING);
}
void loop() {
if(state % 3 == 0) { //6Hz
currentDelay = 83;
willLightOn = true;
} else if (state % 3 == 1) { //5Hz
currentDelay = 100;
willLightOn = true;
} else if (state % 3 == 2) { //LED off
currentDelay = 0;
willLightOn = false;
digitalWrite(ledPin, LOW);
}
currentMillis = millis();
if (currentMillis - previousMillis >= currentDelay && willLightOn) {
previousMillis = currentMillis;
digitalWrite(ledPin, !digitalRead(ledPin));
}
}
void changeState() {
state++;
}
Right now your logic checks 3 times for the value of x in a single loop.
Below code toggles light whenever x is greater than zero. x's value is changed when button is pressed.
But there is a big problem here: If button is pressed when there's something else going on in the processor or it is sleeping (like the long delays you want to use), it may be ignored. So you better study interrupts and implement this behavior using them.
if (x > 0)
{
digitalWrite(ledPin, HIGH);
delay(1000 * x);
digitalWrite(ledPin, LOW);
}
if (buttonState == HIGH)
{
x++;
if (x > 3)
x = 0;
}
You should create a global state of the application. This state is where you remember if you are blinking at 50hz/60hz/off. Then you can use a switch to do the right thing.
Then you check if the button is pressed and change the application state.
See my example below:
// constants won't change. They're used here to set pin numbers:
const int buttonPin = 7; // the number of the pushbutton pin
const int ledPin = 6; // the number of the LED pin
// variables will change:
int applicationState = 0;
bool lightOn = true;
int currentDelay = 1000;
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
// variable for reading the pushbutton status
void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
}
void loop() {
if (digitalRead(buttonPin) == HIGH) {
applicationState++;
if(applicationState >= 3) {
applicationState = 0;
}
delay(100);
}
switch(applicationState){
case 0:
currentDelay = 1000;
lightOn = true;
break;
case 1:
currentDelay = 2000;
lightOn = true;
break;
case 2:
digitalWrite(ledPin, LOW);
lightOn = false;
break;
}
currentMillis = millis();
if (currentMillis - previousMillis >= currentDelay && lightOn) {
previousMillis = currentMillis;
digitalWrite(ledPin, !digitalRead(ledPin));
}
}
I hope you understand what I try to say and demo with the example code.
Your code can not work:
You do need to check if the button state changes, detect when there is a edge. And make sure you detect a single edge only once.
You must repeat the blinking it in a loop till the button is pressed, then you can change the frequency.
You must check the button while you sleep, otherwise your program do not recognize when you press the button.
To make it work, you must change the complete program.
#define BLINK_SLEEP_TIME <some value> // insert value for 16.6666ms
//return 1 after a positive edge
bool button_read(void)
{
static bool lastState=1; //set this to 1, so that a pressed button at startup does not trigger a instant reaction
bool state = digitalRead(buttonPin);
if(state != lastState)
{
state=lastState;
return state;
}
return 0;
}
//Blink the LED with a given period, till button is pressed
//Times are in x*16.666ms or x/60Hz
//At least one time should be more than 0
void blink(uint8_t ontime, uint8_t offtime)
{
while(1)
{
for(uint8_t i=0;i<ontime;i++)
{
led_setOn();
delay(BLINK_SLEEP_TIME);
if(button_read())
{
return;
}
}
for(uint8_t i=0;i<offtime;i++)
{
led_setOff();
delay(BLINK_SLEEP_TIME);
if(button_read())
{
return;
}
}
}
}
const uint8_t time_table[][]=
{
{0,50},//LED is off
{6,6}, //LED blinks with 5Hz, 60Hz/2/6=5Hz
{5,5}, //LED blinks with 6Hz, 60Hz/2/5=6Hz
}
void endless(void)
{
uint8_t i=0;
for(;;)
{
i++;
if(i>2)
{
i=0;
}
blink(time_table[i][0],time_table[i][1]);
}
}
A better approach would be to use a hardware PWM-Module and change the values after a edge on the button.