0

我使用 DIP 开关作为输入,使用 LED 作为输出,以类似于任何给定输入的补码。我正在编写一个 Arduino Uno 来尝试这样做。我对按位效率也不是很有经验;有没有办法大大减少我的代码中的行?

我目前拥有的是一堆 if 语句。

#include <avr/io.h>//library used to access the pin addresses

int main () {
        DDRB |= 0b00001111;
        DDRD &= ~(0b11110000);
        while (1) {
        if (PIND & 0b00010000) {
            PORTB |= 0b00001110;
            PORTB &= ~(0b00000001);
        }
        else if (PIND & 0b00100000) {
            PORTB |= 0b00001101;
            PORTB &= ~(0b00000010);
        }
        else if (PIND & 0b00110000) {
            PORTB |= 0b00001100;
            PORTB &= ~(0b00000011);
        }
        else if (PIND & 0b01000000) {
            PORTB |= 0b00001011;
            PORTB &= ~(0b00000100);
        }
        else if (PIND & 0b01010000) {
            PORTB |= 0b00001010;
            PORTB &= ~(0b00000101);
        }
        else if (PIND & 0b01100000) {
            PORTB |= 0b00001001;
            PORTB &= ~(0b00000110);
        }
        else if (PIND & 0b01110000) {
            PORTB |= 0b00001000;
            PORTB &= ~(00000111);
        }
        else if (PIND & 0b10000000) {
            PORTB |= 0b00000111;
            PORTB &= ~(0b00001000);
        }
        else if (PIND & 0b10010000) {
            PORTB |= 0b00000110;
            PORTB &= ~(0b00001001);
        }
        else if (PIND & 0b10100000) {
            PORTB |= 0b00000101;
            PORTB &= ~(0b00001010);
        }
        else if (PIND & 0b10110000) {
            PORTB |= 0b00000100;
            PORTB &= ~(0b00001011);
        }
        else if (PIND & 0b11000000) {
            PORTB |= 0b00000011;
            PORTB &= ~(0b00001100);
        }
        else if (PIND & 0b11010000) {
            PORTB |= 0b00000010;
            PORTB &= ~(0b00001101);
        }
        else if (PIND & 11100000) {
            PORTB |= 0b00000001;
            PORTB &= ~(0b00001110);
        }
        else if (PIND & 11110000) {
            PORTB |= 0b00000000;
            PORTB &= ~(0b00001111);
        }
    }
    return 0;
}

另外,我遇​​到的另一个问题是一次只有一个 LED 关闭。如果我翻转一个开关,然后另一个开关,我翻转的第一个开关的 LED 会在我翻转另一个开关时重新亮起。

4

2 回答 2

0

这不是正确的代码,它可以以更容易和更易读的方式完成。

  • 您应该摆脱二进制符号,因为它很难阅读,实际上不是 C 标准。

  • 您应该只读取一次硬件寄存器并写入一次。像这里所做的那样在长if else if链中访问相同的寄存器是一个很大的禁忌。端口的状态可能会在读取之间发生变化。

  • 在处理任何形式的开关时,无论是物理按钮、拨码开关、继电器等,您都必须绝对实现某种信号去抖动方式。按下按钮时,会产生机电弹跳,这表现为线路上的一个尖峰,直到它稳定为止。您可以通过将按钮的一侧连接到通过电阻器供电,并将另一侧连接到地来使用示波器查看这一点。

    未能消除这种信号的反弹是一个非常常见的嵌入式初学者错误。它通常在软件中完成,在做出决定之前通过多次阅读按钮。或者通过硬件中的 RC 滤波器,但这需要额外的组件。

你应该有这样的代码:

#define LED0 (1u << 0) // corresponding to PORTx:0
#define LED1 (1u << 1) // corresponding to PORTx:1
...

然后您可以声明一个输出矩阵,如下所示:

const uint8_t LED_OUTPUT [16] = 
{
  [0] = LED1 | LED2 | LED3,
  [1] = LED0 | LED2 | LED3,
  ...
};

输入从 PIND 读取一次,通过周期性读取消除抖动,可能使用简单的数字滤波器(如 3 次读取的中值),然后原位移位(右移 4 步),因此它对应于数字 0 到 15:

uint8_t index = get_buttons(); // function that returns the debounced valued read from PIND
PORTB = LED_OUTPUT[index];

就是这样。

于 2019-01-07T11:30:50.003 回答
0

首先,我建议您先简单地清除 PORTB。然后您可以轻松地设置您需要设置的位。

至于大链,你可以把四位if...else if的值下移,补上。PIND

就像是:

// Clear all bits (and turn off all LEDs)
PORTB = 0;

// Move the four high bits of PIND to the four lowest,
// gets the bitwise complement of that, and set those bits
// (Turning on some LEDs)
PORTB |= ~(PIND >> 4);

当然,您仍然可以使用当前的方式打开/关闭 LED(但仍然没有长if ... else if链):

PORTB |= ~(PIND >> 4);
PORTB &= ~(PIND >> 4);
于 2019-01-06T09:03:49.207 回答