有没有办法让我的补码更有效率,并允许一次输出多个?

Is there a way to make my ones complement code far more efficient and to allow for multiple outputs at a time?

我使用 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 会在我按另一个开关后立即重新亮起。

首先我建议你先清除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);

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

PORTB |= ~(PIND >> 4);
PORTB &= ~(PIND >> 4);

这不是正确的代码,可以用更简单、更易读的方式完成。

  • 你应该摆脱二进制符号,因为它很难阅读而且实际上不是 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];

就是这样。