Reputation: 45
I am trying to incorporate a push button switch to control my software for a stepper motor.
I have three functions for the motor where it would rotate at three different angles (from 0-180 degrees forward, 90 degrees reverse and 90 reverse again back to 0) in a sequence, one after the other.
I would like to use one push button switch to step through these functions in an order.
Would anyone have any suggestions on how to do this? I am imagining I have to create a case statement but have been going in circles with no progress.
This is my current code below, at the moment pressing the switch will just run the first "if" function rotating the motor clockwise by 180 degrees:
#define F_CPU 1000000
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define A PINB0
#define C PINB1
#define B PINB4
#define D PINB3
int16_t i=0; // Auxiliary variable ()
void HalfStep(uint8_t step);
void Forward_180(void);
void Reverse_90(void);
void Reverse_90_2(void);
/********************************* MAIN ********************************/
int main(void)
{
DDRB |= (1<<A) | (1<<B) | (1<<C) | (1<<D); // Set output pins
DDRB &= ~(1<<PINB5); // Set input pin for switch
while(1)
{
if(bit_is_clear(PINB, 5))
{
Forward_180(); // Clockwise 180 degrees
}
if(bit_is_clear(PINB, 5)) // Anti-clockwise 90 degrees
{
Reverse_90();
}
if(bit_is_clear(PINB, 5)) // Anti-clockwise 90 degrees again
{
Reverse_90_2();
}
}
return 0;
}
/***************** HALF STEPPING & DIRECITON FUNCTIONS *****************/
void HalfStep(uint8_t step)
{
switch (step)
{
case 0: // whole number after i%8
PORTB |= (1<<A) | (1<<D);
PORTB &= ~((1<<B) | (1<<C));
break;
case 1: // 0.125
PORTB |= (1<<A);
PORTB &= ~((1<<B)|(1<<C)|(1<<D));
break;
case 2: // 0.25
PORTB |= (1<<A)|(1<<C);
PORTB &= ~((1<<B)|(1<<D));
break;
case 3: // 0.375
PORTB |= (1<<C);
PORTB &= ~((1<<A)|(1<<B)|(1<<D));
break;
case 4: // 0.5
PORTB |= (1<<B)|(1<<C);
PORTB &= ~((1<<A)|(1<<D));
break;
case 5: // 0.625
PORTB |= (1<<C);
PORTB &= ~((1<<A)|(1<<B)|(1<<D));
break;
case 6: // 0.75
PORTB |= (1<<D)|(1<<C);
PORTB &= ~((1<<A)|(1<<B));
break;
case 7: // 0.875
PORTB |= (1<<D);
PORTB &= ~((1<<A)|(1<<B)|(1<<C));
break;
}
}
void Forward_180(void)
{
while (i<=48)
{
HalfStep(i%8);
i++;
_delay_ms(5);
};
}
void Reverse_90(void)
{
while (i>=24)
{
HalfStep(i%8);
i--;
_delay_ms(10);
};
}
void Reverse_90_2(void)
{
while (i>=0)
{
HalfStep(i%8);
i--;
_delay_ms(10);
};
}
Upvotes: 1
Views: 557
Reputation: 138
I would suggest using a state machine.
Something like this (I'm assuming you need to write some code to do a demo only):
/* States */
typedef enum EnumStates
{
ST_IDLE,
ST_FORWARD_180,
ST_WAIT_FOR_STEP_2,
ST_REVERSE_90,
ST_WAIT_FOR_STEP_3,
ST_REVERSE_90_2,
}
EState;
/* to know if the switch was pressed */
char _keypressed = 0;
/* state variable */
EState _state = ST_IDLE;
/* very simple keyboard process */
void SwitchTask(void)
{
/* The keypressed flag will be valid for one cycle of the while loop */
_keypressed = 0;
if (bit_is_clear(PINB, 5))
{
_keypressed = 1;
/* this is a simple way to implement debouncing */
/* I assume you do not have timing requirements */
_delay_ms(100);
}
}
/* demo task */
/* This task implements a simple state machine */
void DemoTask(void)
{
switch(_state)
{
case ST_FORWARD_180:
Forward_180();
_state = ST_WAIT_FOR_STEP_2;
break;
case ST_REVERSE_90:
Reverse_90();
_state = ST_WAIT_FOR_STEP_3;
break;
case ST_REVERSE_90_2:
Reverse_90_2();
_state = ST_IDLE;
break;
case ST_IDLE:
case ST_WAIT_FOR_STEP_2:
case ST_WAIT_FOR_STEP_3:
if (_keypressed > 0)
{
_state++;
}
break;
default:
break;
}
}
int main(void)
{
/* initialization */
DDRB |= (1<<A) | (1<<B) | (1<<C) | (1<<D); // Set output pins
DDRB &= ~(1<<PINB5); // Set input pin for switch
_keypressed = 0;
while(1)
{
SwitchTask();
DemoTask();
}
return 0;
}
Upvotes: 1