0

我正在尝试使用旋转编码器来控制使用 Atmel(ATmega328P Xplained mini)微处理器从 0-9 计数的 7 段显示器的速度。我的问题是,每当我运行程序时,显示器的计数越来越快,直到你只能看到一个“8”,有时我似乎可以通过逆时针转动旋转编码器来降低速度,有时根本没有效果。由于我在编程方面没有那么丰富的经验,尤其是在这方面我希望有人有能力并且愿意提供帮助。

这是我的代码:

#include <avr/io.h>

void Display (uint8_t x)
{
    static uint8_t tabel[] =
    {0b11000000,0b11111001,0b10100100,0b10110000,0b10011001,0b10010010,0b10000010,0b11111000,0b10000000,0b10010000};
    PORTD = tabel[x];
}

int GetInput (void)
{
    uint8_t x = PINC&1;
    uint8_t y = (PINC>>1)&1;
    if (x == 0 && y == 0) {return 0; }
    else if (x == 1 && y == 0) {return 1;}
    else if (x == 0 && y == 1) {return 2;}
    else {return 3;}
}

int main(void)
{
    DDRD = 0xFF;  // set PortD as an output
    DDRC = 0x00;  // set PortC as an input
    PORTB = 0x03; // Activate Pull-up resistors

    float d = 9000;
    int tick = 0;
    int i = 0;
    int input, state = 0; // initial state
    int oldInput = 0;

    while (1)
    {   
        input = GetInput();
        if (oldInput == 0 && input == 1)
        {
            d = (d * 1.1);
            //slower
        }else if (oldInput == 0 && input == 2)
        {
            d = (d * 0.9);
            //faster
        }else if (oldInput == 1 && input == 0)
        {
            d = (d * 0.9);
            //faster
        }else if (oldInput == 1 && input == 3)
        {
            d = (d * 1.1);
            //slower
        }else if (oldInput == 2 && input == 0)
        {
            d = (d * 1.1);
            //slower
        }else if (oldInput == 2 && input == 3)
        {
            d = (d * 0.9);
            //faster
        }else if (oldInput == 3 && input == 1)
        {
            d = (d * 0.9);
            //faster
        }else if (oldInput == 3 && input == 2)
        {
            d = (d * 1.1);
            //slower
        }
        oldInput = input;

        switch (state)
        {
            case 0: //ini
                Display(0);
                state = 1;
                break;

            case 1: //count
                if (i == 9)
                {
                    i = 0;
                    Display(i);
                }
                else
                {
                    i++;
                    Display(i);
                }
                state = 2;
                break;

            case 2: // delay
                if (tick < d)
                {
                    state = 2;
                    tick++;
                }
                else
                {
                    state = 1;
                    tick = 0;
                }
                break;

            case 3: //reset / destroy
                break;
        }
    }
}
4

2 回答 2

1

首先尝试更改GetInput函数以返回更有用的值。请注意,第 0 位和第 1 位PINC已经组合形成您正在重建的整数。

int GetInput (void)
{
    // array to convert grey scale bit patterns to direction indicators.
    // Rows indexed by lastValue, columns indexed by thisValue, and the
    // content is -1 for CCW, +1 for CW, 0 for no motion.  Note that 0 is
    // also used for an invalid transition (2 bits changed at once), but a
    // different value could be used for fault detection.
    static const int tableGreyToDirection[4][4] =
    {
        0 , -1, 1 , 0 ,                        // lastValue==0
        1 , 0 , 0 , -1,                        // lastValue==1
        -1, 0 , 0 , 1 ,                        // lastValue==2
        0 , 1 , -1, 0                          // lastValue==3
    };

    static uint8_t lastValue = 0;             // A valid default starting value
    uint8_t thisValue = (PINC & 0b00000011);  // Use the bottom two bits as a value from 0..3
    int result = tableGreyToDirection[lastValue][thisValue];
    lastValue = thisValue;
    return result;
}

然后,您可以大大简化循环中的测试。

while (1)
{
    // Check the direction of the encoder: -1 = CCW, +1 = CW, anything else = no motion.
    input = GetInput();
    if(0 < input)
    {
        // Motion is CW, so increment the delay (within reasonable bounds).
        if(8900 > d) d += 100;
    }
    else if(0 > input)
    {
        // Motion is CCW, so decrement the delay (within reasonable bounds).
        if(100 < d) d -= 100;
    }

    // Keep the rest as it is...
}

建议改为dauint16_t并稍微整理一下。进一步的提示包括使用#define为常量提供可读的名称。例如,在我的方向表中,您可以使用:

#define ENCODER_CW 1
#define ENCODER_CCW -1
#define ENCODER_NEITHER 0

...

static const int tableGreyToDirection[4][4] =
{
    ENCODER_NEITHER, ENCODER_CCW, ENCODER_CW, ENCODER_NEITHER,  // lastValue==0
    ...

我相信你可以自己填写。

于 2014-12-16T15:49:22.043 回答
0

我检查了你的软件,但我无法立即找到大问题。你最好检查下面的部分。

  1. 如果您没有触摸编码器但速度越来越快:您是否有范围检查编码器输入端口是否有噪声从端口输入。
  2. 如果两个输入端口稳定,请检查您的值是否也稳定:旧输入和新输入值应该相同:通过日志或输出检查值更改时切换未使用的端口。您可以调试自己的代码。
  3. 您最好添加数量刻度值而不是直接相乘以防止 d 值变为 0。
  4. 您的 CPU 的运行速度必须与检测主循环中的端口状态变化一样快。- 我认为如果此代码是您系统的全部,这是可能的。
于 2014-12-16T14:26:33.480 回答