【问题标题】:Is there a way to make my ones complement code far more efficient and to allow for multiple outputs at a time?有没有办法让我的补充代码更有效率并一次允许多个输出?
【发布时间】:2019-01-06 08:56:18
【问题描述】:

我使用 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 就会重新亮起。

【问题讨论】:

  • 这些测试看起来不对。而不是else if (PIND &amp; 0b10110000) {,我希望else if ((PIND &amp; 0b11110000) == 0x0b10110000) {
  • 如果你使用这种方法(你不应该),你应该在 tf-else if-else 链之前将 PIND once 读入一个变量并测试它而不是重复- 阅读随时可能改变的 PIND。

标签: c arduino embedded ones-complement


【解决方案1】:

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

【讨论】:

  • 这种方法的弱点在于它会导致启用给定 LED 的不连续性。虽然不是很容易在视觉上辨别,但会导致“嘈杂”的 LED
  • @chux 打开和关闭 LED 是控制 LED 亮度的常用技术。如果您查看许多 LED 标志,您会发现它们在任何时候都有一组有限的行,因为它们必须选择要更新的行。我不认为关闭 LED 几个 CPU 周期会导致很多问题。
  • 正如@Clifford 在另一个答案中提到的那样,对于“当前方式”的情况,您应该将PIND 读入一次局部变量,然后使用它。
  • PORTB 显然是一个 GPIO 寄存器所以不,你不应该先清除它。这将导致人眼可能无法注意到的不必要的闪烁,仍然是糟糕的编程,并且如果 LED 处于低电平有效状态,可能会导致不必要的电流消耗。您应该在 RAM 中使用临时变量并将数据存储在那里,首先将其设置为零,然后当一切完成后,将新值写入端口。
  • @Lundin 我同意你可以让 CPU 用 PWM 来完成它,但它也可以用 GPIO 在软件中完成。我同意最好阅读PORTB,更新所需的位,然后写入新值。
【解决方案2】:

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

  • 你应该摆脱二进制符号,因为它很难阅读,而且实际上不是 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-12-11
    • 1970-01-01
    • 2020-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-11
    • 2015-08-13
    相关资源
    最近更新 更多