Breaking a while loop in Arduino - while-loop

I have a program that moves a stepper motor to the right, left and have a stop button that stops the motor. In one part of my program, a motor gradually lowers a speed and stops after a certain period of time iv.
The problem is that in this part of a program (when a motor gradually lowers a speed and then stops) I can’t stop the motor upon pressing a stop button. I understand that I need to break a while loop somehow, but using a break statement doesn't wort for me.
Do you have some ideas?
Here is my function:
/* --- STEPPER MOTOR ---*/
const int motor_step = 3;
const int motor_dir = 4;
int stepSpeed = 0;
int stepMaxSpeed = 1000;
int fadeAmount = 100;
int fadeDelay = 10;
/* ---- STOP BUTTON ---- */
int buttonStop = 5;
int stateStop=0;
void setup() {
.
.
.
stateStop = digitalRead(buttonStop);
}
void loop () {
.
.
.
myfunc();
}
void myfunc() {
if(stateStop == HIGH) {noTone(motor_step); stepSpeed = 0;}
elapsedMillis te;
unsigned int iv = 1500;
while (te < iv) {
if(stepSpeed == stepMaxSpeed) {
stepSpeed = stepSpeed+0;
tone(motor_step,stepSpeed);
digitalWrite(motor_dir,HIGH);
}
else {
stepSpeed = stepSpeed + fadeAmount;
tone(motor_step,stepSpeed);
digitalWrite(motor_dir,HIGH);
delay(fadeDelay);
}
if(stateStop == HIGH) { stepSpeed = 0; break;}
}
if(stepSpeed == stepMaxSpeed) {
while(stepSpeed>0){
stepSpeed = stepSpeed-fadeAmount;
tone(motor_step,stepSpeed);
digitalWrite(motor_dir,HIGH);
delay(fadeDelay);
if(stateStop == HIGH) { stepSpeed = 0; break;}
}
}
stepSpeed = 0;
noTone(motor_step);
digitalWrite(enable,LOW); // enable changed from HIGH
}

Your break condition does never trigger as stateStop is never being updated inside your while loop. How is your program supposed to know? It's busy running the loop and does not care about anything outside it's scope.
Check the button state inside the while loops or use interrupts

Related

GlutKeyboardFunc callback doesn't work in openGL

I am trying to simply quit the application on pressing a key in openGL and the keyboard doesn't seem to work.
Neither am I am not able to quit the application just by clicking on the close button of the window. Any explanation for this behaviour? I am not recreating the window continuously either.
Here's the code snippet
void keyboardfunc(unsigned char key, int x, int y) {
cout << "Inside" ;
switch (key) {
case 'q': exit(0);
default: break;
}
int main(int argc,char ** argv)
{
.
.
.
glutReshapeFunc(reshape_func);
glutDisplayFunc(draw);
glutKeyboardFunc(keyboardfunc);
myinit();
glutMainLoop();
return 0;
}
The program is to simulate insertion sort by representing the array graphically , using a for loop I am clearing the screen every time and representing the numbers as histogram each time
Just to be clear the simulation of insertion sort works , only the keyboard callback doesn't work.
Your draw functions take the CPU control and don't let to execute GLUT events loop. Take into account that GLUT is single thread.
You must register a timer. Timer will produce new rendering. Each second compute next iteration and force to redraw scene.
void draw(){
renderHistogram();
}
void timer(int value) {
getNextIteration();
glutPostRedisplay();
glutTimerFunc(1000, timer, 1); // executed on a second
}
To register timer include this line before glutMainLoop:
glutTimerFunc(1000, timer, 1); // executed on a second
next iteration function would be:
int i = 0, j = 0;
void getNextIteration()
{
if (i == n) {
// Array is sorted
return;
}
int key;
key = arr[i];
if (j == 0 || arr[j] <= key) {
// Internal loop finished, reset j, and advance i;
arr[j + 1] = key;
i++;
j = i - 1;
}
arr[j + 1] = arr[j];
j = j - 1;
}

How do you make a button only send one input to a source while being pushed down and not send another one until the button is let go and repressed?

In a basic variable and Button setup on an Arduino software, the idea is that if you press a button, you gain one on a variable. Theoretically, holding the button shouldn't cause the variable to increase more than one until the release and repressing of the button. However, I could not make this happen. How is this supposed to be done?
I tried using an else around a delay (because the adding one to a variable code was inside an "if" statement) so it would not delay unless the button and released and would not count multiple button inputs, but this resulted in a larger increase when a button was clicked rather than just a one increase.
const int buttonPin = 8;
int number = 0;
int numbertwo = 0;
int buttonState = 0;
void setup()
{
pinMode(buttonPin, INPUT);
}
void loop()
{
buttonState = digitalRead(buttonPin);
if (buttonState == LOW){
numbertwo = ++number;
delay(100);
}
(Can use any method to determine variable, like on an LCD)
As mentioned above, I expected the variable to only increase by one when a button is pressed and not to continue increasing until the button is released and re-pressed, but what actually happened was the variable kept increasing in value as the button was held.
I'm assuming you want the variable "number" increase by 1 per press. I think you are looking for something like this:
const int buttonPin = 8;
int number = 0;
int buttonState = 0;
void setup() {
pinMode(buttonPin, INPUT);
}
void loop()
{
buttonState = digitalRead(buttonPin);
if (buttonState == LOW){
++number;
// This loop is to make sure not to count up until button is released
do {
delay(5);
buttonState = digitalRead(buttonPin);
} while (buttonState == LOW);
}
}
If you don't like the loop based implementation, here's a state based implementation for you:
const int buttonPin = 8;
int number = 0;
int buttonState = 0;
int prevState = -1;
void setup() {
pinMode(buttonPin, INPUT);
prevState = -1;
}
void loop()
{
buttonState = digitalRead(buttonPin);
if (buttonState == LOW && prevState != buttonState){
++number;
prevState = buttonState;
}
delay(5);
}

Not able to set value 1 to pin as Input in MPLAB

I am using MPLAB to perform an operation on PIC kit 14f458.
Now I want to create a code to pass the different amount of voltage supply LED through the Microcontroller using a button. When button pressed the first time I should get waveform with 10% DC, for second and third time, 50% and 95% respectively.
I have worked on this But still getting Values OF RE2 PORT as 0 rather than 1. And I also don't know how to stop timer while I release the button.
My code is as follow:
#include<stdio.h> //Standard I/O Library
#include<p18cxxx.h> //for TRISA,E and PORTA,E declaration
#pragma config WDT = OFF //watchdog counter
#pragma config OSC = HS, OSCS = OFF
#pragma config PWRT = OFF, BOR = ON, BORV = 45
#pragma config DEBUG = OFF, LVP = OFF, STVR = OFF
void timer_10()
{
CCP1CON = 0;
PR2 = 249;
CCPR1L = 24;
TRISCbits.TRISC2 = 0;
T2CON = 0x00;
CCP1CON = 0x3c;
TMR2 = 0;
T2CONbits.TMR2ON = 1;
while(1)
{
PIR1bits.TMR2IF = 0;
while(PIR1bits.TMR2IF == 0);
}
}
void timer_50()
{
CCP1CON = 0;
PR2 = 249;
CCPR1L = 124;
TRISCbits.TRISC2 = 0;
T2CON = 0x00;
CCP1CON = 0x2c;
TMR2 = 0;
T2CONbits.TMR2ON = 1;
while(1)
{
PIR1bits.TMR2IF = 0;
while(PIR1bits.TMR2IF == 0);
}
}
void timer_95()
{
CCP1CON = 0;
PR2 = 249;
CCPR1L = 236;
TRISCbits.TRISC2 = 0;
T2CON = 0x00;
CCP1CON = 0x2c;
TMR2 = 0;
T2CONbits.TMR2ON = 1;
while(1)
{
PIR1bits.TMR2IF = 0;
while(PIR1bits.TMR2IF == 0);
}
}
void main()
{
int i = 1;
ADCON1 = 0x06; //Sets RA0 to digital mode
CMCON = 0x07;
TRISEbits.TRISE2 = 1; //set E2 PORTE pins as input
PORTEbits.RE2 = 1; //Here I am not able to SET Value 1
while(1)
{
while(PORTEbits.RE2 == 0)
{
switch(i)
{
case 1:
timer_10();
break;
case 2:
timer_50();
break;
case 3:
timer_95();
break;
}
if(i<4)
{
i++;
if(i>=4)
{
i=1;
}
}
}
}
}
And My compiler Get Stuck in function timer_10(). Please help me.
This is a bit too long for a comment, and I think you're probably able to discover the answer yourself - however, I'll give you some pointers.
In main()
TRISEbits.TRISE2 = 1; //set E2 PORTE pins as input
PORTEbits.RE2 = 1; //Here I am not able to SET Value 1
What behaviour do you expect when you write to port E2 after configuring E2 as an input? It is described in the PIC18F458 data sheet, specifically section 9.5
In timer_10()
void timer_10()
{
CCP1CON = 0;
PR2 = 249;
CCPR1L = 24;
TRISCbits.TRISC2 = 0;
T2CON = 0x00;
CCP1CON = 0x3c;
TMR2 = 0;
T2CONbits.TMR2ON = 1;
while(1)
{
PIR1bits.TMR2IF = 0;
while(PIR1bits.TMR2IF == 0);
}
}
You said your compiler got stuck, but I assume you mean debugger, as you were able to run main() to observe PORTEbits.RE2 = 1; not doing what you expected. If you single-step this in function a debugger, where does it get stuck? can you see why?
Ok, let's simplify this a bit. If you want the duty cycle to change on the negative edge of a push button, and you don't want to use interrupts, then you need to restructure what you have. Firstly, there are several issues with the timer_x routines: 1) you don't need the while loop in there, that is why you are getting stuck. 2) If you remove that loop, you will constantly call a timer routine which will reset the register values and you will not get what you expect. Also, since you are not using interrupts, who cares if the overflow flag is set or not, just leave it set.
To fix this, first, remove all the timer_x routines. Next, you need a timer routine to read the switch input. Remember that all switches have switch bounce so reading one value isn't reliable. You either need to read the switch slowly, at a rate greater than the switch bounce (~50ms) and only run your routines if you have two readings in a row that are the same, or you can read it faster, but you will need more readings that are the same to know you have a stable value.
From there, you can only increment "i" on the first negative edge, not all the time the switch is held down (unless you want it that way). your main routine should look something like (forgive the shortcut for the timer registers):
Main()
if (tmr2.overflow) // 50ms switch read timer
{
switchCurrent = PORTE2;
}
if ( (switchCurrent == swtichLast) // Two readings of the same value
&& (!switchCurrent) // and switch is pressed
&& (!switchUpdated) ) // and haven't updated the pwm yet
{
switchUpdated = TRUE; // Only allow one update per switch
i++;
if (i > 4)
{
i = 0;
}
switch (i)
{
case 0:
CCPR1L = 24;
break;
case 1:
CCPR1L = 124;
break;
... and so on. Note, the only difference in each case is CCPR1L, so just rewrite that register instead of resetting everything.
}
switchLast = swtichCurrent;
if (swtichCurrent)
switchUpdated = 0
This should give you a starting point, hope it helps

How to toggle LED

How to toggle LED with push button. I wrote program. There is problem in Program. This program fail if i held the button down continuously then LED turn ON/OFF continuously. How to solve problem ?
#include<REGX51.h>
#define led_off 0
#define switch_pressed 0
sbit Switch = P1^2; /*set bit P1^2 to Switch*/
sbit led = P1^0; /*set bit P1^0 to LED*/
void debounce (unsigned long wait) /* Debounce function */
{
unsigned int i;
for (i = 0; i < wait; i++);
}
void main (void)
{
led = led_off;
while (1)
{
if (Switch == switch_pressed)
{
led = ~led;
debounce (40000);
}
}
}
You are toggling the button so long as the button is pressed. when you need to toggle it only when the button changes from not pressed to pressed:
#include<REGX51.h>
#define BTN_UP 1
#define BTN_DN 0
#define DEBOUNCE_DELAY 40000
sbit Switch = P1^2 ;
sbit led = P1^0 ;
void delay( unsigned long wait )
{
for( volatile unsigned long i = 0 ;
i < wait;
i++ )
{ /* do nothing */ }
}
int main( void )
{
int prev_button_state = Switch ;
led = 0 ;
for(;;)
{
// Read current Switch state
int button_state = Switch ;
// If BTN_DN event...
if( button_state != prev_button_state &&
button_state == BTN_DN )
{
led = ~led;
delay( DEBOUNCE_DELAY ) ;
}
prev_button_state = button_state ;
}
return 0 ;
}

Arduino Uno Controlling multiple LEDs with one button for different amounts of time

Thanks in advance for your help.
Scenario Overview
In the real world, I am using one button to open two mechanical valves, but one of those valves should close after a period of time that we will hard code into the sketch, and the other valve stays open for as long as the button is pushed. For proof of concept, I am lighting two LEDs as stand-ins for the valves.
Pseudocode
If Button One is pressed, Valve One should Open, and Valve Two should also Open for 200ms then Close.
Initial Solution
Within the main loop, I look for the button to be pushed as part of an if statement. When that condition is passed, I used a while loop and timer to keep "valve2" open until the time is up. LEDs work, and all is superficially great. However...
The Issue
When my partner starts putting the actual mechanicals together, valve2 doesn't open because the while loop is cycling so quickly that the voltage required to initiate the opening of the valve is not high enough.
My Question
Is it possible to isolate (without using delays) the loop & evaluation of the timer condition from the main loop in order to allow full power to be sent to the valve mechanism (or LED in this case)? Or am I overthinking this whole thing (likely the case)?
The Code
const int button1 = 2; //Pin for switch 1
const int button2 = 3; //Pin for switch 2
const int valve1 = 12; //Pin for relay 1
const int valve2 = 13; //Pin for relay 2
// variables will change:
int state1 = 0; // variable for reading the pushbutton status
int state2 = 0; // variable for reading the pushbutton status
//THIS IS THE TIME IN MILLISECONDS FOR valve2 WHEN button1 IS DEPRESSED
int valve2time = 200;
void setup() {
//switches
pinMode(button1,INPUT); //Set button1 as input
pinMode(button2, INPUT); //Set button2 as input
//relays
pinMode(valve1, OUTPUT); //Set valve1 as output
pinMode(valve2, OUTPUT); //Set valve2 as output
Serial.begin(9600);
}
void loop(){
state1 = digitalRead(button1); //state1 returns the state of button1, up or down.
state2 = digitalRead(button2); //state2 returns the state of button2, up or down.
int duration = switchTime(); //Create variable to capture duration of switch press
if (state1 == LOW && state2 == LOW){ //if no buttons are pressed
digitalWrite(valve1,LOW); //make sure valve1 is off
digitalWrite(valve2,LOW); //make sure valve2 is off
}
else if (state1 == HIGH && state2 == LOW) { //if JUST button one is pressed
digitalWrite(valve1,HIGH); //turn on valve1
while (duration <= valve2time){ //as long as the timer is below or = to what we defined up top....
digitalWrite(valve2,HIGH); //...Turn on valve2...
break; //...Then stop the while loop...
}
digitalWrite(valve2,LOW); //...and finally turn off valve2
}
else if (state2 == HIGH){ //final condition, if button two is pressed
digitalWrite(valve1,HIGH); //turn on valve1
digitalWrite(valve2,HIGH); //turn on valve2
}
}
//return the time in ms that the switch has been pressed (LOW)
long switchTime(){
//these variables are static
static unsigned long startTime = 0; //the time the switch state was first detected
static boolean state; //the current state of the switch
if(digitalRead(button1) != state){ //check to see if the switch has changed state
state = ! state; //yes, invert the state
startTime = millis(); //store the time
}
if(state == HIGH){
return millis() - startTime; //switch pushed, return time in ms
}
else{
return 0; //return 0 if the switch is not pushed (in the HIGH state)
}
}
UPDATE: The working Code
//button pins
const int BUTTON1_PIN = 2;
const int BUTTON2_PIN = 3;
const int VALVE1_PIN = 0; //mml for tiny
const int VALVE2_PIN = 1; //mml for tiny
// IO Channels - Used to simulate arduino IO
boolean inputChannels[] = {LOW, LOW}; // digital input channels "Button1" and "Button2"
boolean outputChannels[] = {LOW, LOW}; // digital output channels "Valve1" and "Valve2"
// =============================================================================================================
// You can probably ignore everything above this line
// State machine variables
const int STATE_CLOSED = 0;
const int STATE_BUTTON1_PRESSED = 1;
const int STATE_BUTTON1_RELEASED = 2;
const int STATE_BUTTON2_PRESSED = 3;
const int STATE_BUTTON2_RELEASED = 4;
int currentState = 0;
int lastState = 0;
// button debounce time in ms
unsigned long BUTTON_DEBOUNCE = 200;
unsigned long BUTTON1_PRESSED_VALVE2_FLASH = 350;
unsigned long BUTTON1_RELEASE_VALVE2_FLASH = 1000;
// state tracking arrays
boolean buttonState[] = {LOW, LOW};
boolean buttonDebounce[] = {LOW, LOW};
unsigned long buttonTimers[] = {0, 0};
unsigned long valveTimers[] = {0, 0};
void setup(){
pinMode(BUTTON1_PIN, INPUT);
digitalWrite(BUTTON1_PIN, HIGH); //MML
pinMode(BUTTON2_PIN, INPUT);
digitalWrite(BUTTON2_PIN, HIGH); //MML
pinMode(VALVE1_PIN, OUTPUT);
pinMode(VALVE2_PIN, OUTPUT);
}
/**
* Main control loop
*/
void loop() {
switch (currentState) {
case STATE_CLOSED:
handleClosedState();
lastState = STATE_CLOSED;
break;
case STATE_BUTTON1_PRESSED:
handleButton1PressedState();
lastState = STATE_BUTTON1_PRESSED;
break;
case STATE_BUTTON1_RELEASED:
handleButton1ReleasedState();
lastState = STATE_BUTTON1_RELEASED;
break;
case STATE_BUTTON2_PRESSED:
handleButton2PressedState();
lastState = STATE_BUTTON2_PRESSED;
break;
case STATE_BUTTON2_RELEASED:
handleButton2ReleasedState();
lastState = STATE_BUTTON2_RELEASED;
break;
default:;
}
}
/**
* Handler method for STATE_CLOSED
*/
void handleClosedState() {
// ensure valves are closed
if (digitalRead(VALVE1_PIN) == HIGH) {
digitalWrite(VALVE1_PIN, LOW);
}
if (digitalRead(VALVE1_PIN) == HIGH) {
digitalWrite(VALVE2_PIN, LOW);
}
// wait for button1 press
if (LOW == debouncedDigitalRead(BUTTON1_PIN, BUTTON_DEBOUNCE)) {
buttonState[BUTTON1_PIN] = LOW;
currentState = STATE_BUTTON1_PRESSED;
}
}
/**
* Handler method for STATE_BUTTON1_PRESSED
*/
void handleButton1PressedState() {
// check for button1 release
if (HIGH == debouncedDigitalRead(BUTTON1_PIN, BUTTON_DEBOUNCE)) {
currentState = STATE_BUTTON1_RELEASED;
return;
}
// open valve1
if (digitalRead(VALVE1_PIN) == LOW) {
valveTimers[VALVE1_PIN] = millis();
digitalWrite(VALVE1_PIN, HIGH);
}
// on state change open valve2
if (lastState != currentState) {
valveTimers[VALVE2_PIN] = millis();
digitalWrite(VALVE2_PIN, HIGH);
}
// and close it after 200 ms
else if ((millis() - valveTimers[VALVE2_PIN]) > BUTTON1_PRESSED_VALVE2_FLASH && digitalRead(VALVE2_PIN) == HIGH) {
digitalWrite(VALVE2_PIN, LOW);
}
// check for button2 press
if (LOW == debouncedDigitalRead(BUTTON2_PIN, BUTTON_DEBOUNCE)) {
currentState = STATE_BUTTON2_PRESSED;
}
}
/**
* Handler method for STATE_BUTTON1_RELEASED
*/
void handleButton1ReleasedState() {
// open valve2
if (lastState != currentState) {
valveTimers[VALVE2_PIN] = millis();
digitalWrite(VALVE2_PIN, HIGH);
digitalWrite(VALVE1_PIN, LOW);
}
// and close valve2 after 1000ms
else if ((millis() - valveTimers[VALVE2_PIN] > BUTTON1_RELEASE_VALVE2_FLASH)) {
digitalWrite(VALVE2_PIN, LOW);
currentState = STATE_CLOSED;
}
}
/**
* Handler method for STATE_BUTTON2_PRESSED
*/
void handleButton2PressedState() {
// open valve2
if (digitalRead(VALVE2_PIN) == LOW){
digitalWrite(VALVE2_PIN, HIGH);
digitalWrite(VALVE1_PIN, HIGH);
}
// check for button1 release
if (HIGH == debouncedDigitalRead(BUTTON1_PIN, BUTTON_DEBOUNCE)) {
currentState = STATE_BUTTON1_RELEASED;
}
// check for button2 release
else if (HIGH == debouncedDigitalRead(BUTTON2_PIN, BUTTON_DEBOUNCE)) {
currentState = STATE_BUTTON2_RELEASED;
}
}
/**
* Handler method for STATE_BUTTON2_PRESSED
*/
void handleButton2ReleasedState() {
// open valve2
if (digitalRead(VALVE2_PIN) == HIGH){
digitalWrite(VALVE2_PIN, LOW);
digitalWrite(VALVE1_PIN, HIGH);
}
// check for button1 release
if (HIGH == debouncedDigitalRead(BUTTON1_PIN, BUTTON_DEBOUNCE)) {
currentState = STATE_BUTTON1_RELEASED;
}
// check for button2 press
else if (LOW == debouncedDigitalRead(BUTTON2_PIN, BUTTON_DEBOUNCE)) {
currentState = STATE_BUTTON2_PRESSED;
}
}
/**
* Utility for debouncing input channels
* #param channel
* #param debounce
* #return
*/
boolean debouncedDigitalRead(int channel, unsigned long debounce) {
int input = digitalRead(channel);
if (input != buttonState[channel] && HIGH == buttonDebounce[channel]) {
buttonTimers[channel] = millis();
buttonDebounce[channel] = LOW;
}
if ((millis() - buttonTimers[channel]) > debounce) {
buttonState[channel] = input;
buttonDebounce[channel] = HIGH;
}
return buttonState[channel];
}
In order for the code to simultaneously a) keep looping to check the buttons, and b) achieve the desired behavior for valve2, you need a software state machine that keeps track of what valve2 is doing. In the code below, I renamed your state1 and state2 variables, so that I could introduce a new state variable that controls valve2.
The state variable is normally in the idle state.
When button1 is pressed
valve2 is turned on
a timestamp is taken
the state is changed to active
After a 200 msec delay
valve2 is turned off
the state is changed to done
The state will stay done until either button1 is released or button2 is pressed, since either of those actions resets the state to idle.
Here's what the code looks like
void loop()
{
int state = 0; //variable to keep track of valve2: 0=idle 1=active 2=done
unsigned long start; //variable to keep track of when valve2 was turned on
boolean pressed1 = (digitalRead(button1) == HIGH); //pressed1 is true if button1 is pressed
boolean pressed2 = (digitalRead(button2) == HIGH); //pressed2 is true if button2 is pressed
if ( !pressed1 && !pressed2 ) //if no buttons are pressed
{
digitalWrite(valve1,LOW); //make sure valve1 is off
digitalWrite(valve2,LOW); //make sure valve2 is off
state = 0; //clear valve2 state
}
else if ( pressed2 ) //if button2 is pressed
{
digitalWrite(valve1,HIGH); //turn on valve1
digitalWrite(valve2,HIGH); //turn on valve2
state = 0; //clear valve2 state
}
else //button1 is pressed
{
digitalWrite(valve1,HIGH); //turn on valve1
if ( state == 0 ) //if valve2 is idle
{
digitalWrite(valve2,HIGH); //turn on valve2
state = 1; //valve2 is active
start = millis(); //capture the start time
}
else if ( state == 1 ) //if valve2 is active
{
if ( millis() - start > 200 ) //has it been 200ms?
{
digitalWrite(valve2,LOW); //turn valve2 is off
state = 2; //valve2 is done
}
}
}
}