有没有办法让我的补码更有效率,并允许一次输出多个?
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];
就是这样。
我使用 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];
就是这样。