【问题标题】:Moving through code using a Push Button switch使用按钮开关移动代码
【发布时间】:2016-02-17 14:49:50
【问题描述】:

我正在尝试合并一个按钮开关来控制我的步进电机软件。

我为电机提供了三个功能,它可以依次以三个不同的角度(从正向 0-180 度、反向 90 度和反向 90 度再次回到 0)依次旋转。

我想使用一个按钮开关按顺序逐步执行这些功能。

有人对如何做到这一点有任何建议吗?我想象我必须创建一个案例陈述,但一直在兜圈子,没有任何进展。

下面是我当前的代码,此时按下开关只会运行第一个“if”函数,将电机顺时针旋转 180 度:

#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);
    };
}

【问题讨论】:

  • 研究一下state machibnes和debouncing
  • 除了去抖动之外,您没有等待密钥被释放,正如@LPs 暗示的那样,您必须考虑当前状态。
  • @LPs 谢谢大家,我之前做过状态机,所以需要刷新我的记忆并尝试一下

标签: c switch-statement case atmel


【解决方案1】:

我建议使用状态机。

类似这样的东西(我假设您只需要编写一些代码来进行演示):

/* 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;
}

【讨论】:

  • 感谢您回答我的问题,幸运的是我之前在课程中简要地做过状态机。看来我得回去刷新我的记忆了:s
  • 在 switch 语句中使用嵌套的 if 语句: case ST_IDLE: case ST_WAIT_FOR_STEP_2: case ST_WAIT_FOR_STEP_3: if (_keypressed > 0) { _state++; } 休息;默认值:中断;这是告诉处理器逐步遍历枚举器,当它遍历上述三个时,基本上什么都不做或等待枚举类型中的下一个枚举器?
  • 嵌套的if 语句后跟break,因此switch 代码块和函数都退出了。
  • 那段代码有点棘手。 IDLE、WAIT_FOR_STEP_2 和 WAIT_FOR_STEP_3 状态是等待状态,它们的唯一目的是等待按键按下。当触发此事件时,状态机将进入以下状态。请注意,枚举 EnumStates 必须按照特定顺序才能使这段代码正常工作。
猜你喜欢
  • 1970-01-01
  • 2012-03-22
  • 1970-01-01
  • 2012-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-27
相关资源
最近更新 更多