【问题标题】:Atmel microprocessor and rotary encoder controlling speed of 7 segment displayAtmel微处理器和旋转编码器控制7段显示器的速度
【发布时间】:2014-12-16 13:25:15
【问题描述】:

我正在尝试使用旋转编码器来控制使用 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;
        }
    }
}

【问题讨论】:

  • micro 会在第一次超时前多次循环运行,每次乘以 0.9 将很快使 d 变为 0。一旦达到 0,无论乘以多少次 1.1它将保持为 0,您将永远不会再在 case 2: 中等待。
  • 如果您可以解释编码器的位模式的含义以及您希望它们如何影响时序,我可以建议一个替代方案。
  • 在每次点击旋转编码器之间,位值都会经过:CW 为 2-3-1-0,CCW 为 1-3-2-0,它应该只是计数,例如顺时针转动时快 10%,逆时针转动时慢 10%。实际上,我只是希望它在每次点击之间更改一次(例如,如果值从 0-1 或 1-0 变化)但是当它不起作用时扩展代码然后我迷路了。

标签: c atmel microprocessors atmelstudio


【解决方案1】:

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

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...
}

建议将d 更改为uint16_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
    ...

我相信你可以自己填写。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-03
      • 2012-12-19
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多