Есть ли способ сделать мои дополнения кода гораздо более эффективными и обеспечить одновременный вывод нескольких выходов? - PullRequest
0 голосов
/ 06 января 2019

Я использую DIP-переключатели в качестве входов и светодиоды в качестве выходов, которые напоминают те, которые дополняют любой данный вход. Я программирую 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;
}

Кроме того, другая проблема, с которой я сталкиваюсь, заключается в том, что одновременно выключается только один светодиод; если я переключаю один переключатель, а затем другой, светодиод первого переключенного переключателя снова включается, как только я переключаю другой.

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Это неправильный код, и его можно сделать более простым и читаемым способом.

  • Вам следует избавиться от двоичной записи, поскольку она трудна для чтения и не соответствует стандарту C.
  • Вы должны читать аппаратные регистры только один раз и писать в них один раз. Доступ к одному и тому же регистру в длинной цепочке if else if, как это сделано здесь, является большим нет-нет. Состояние порта может меняться между чтениями.
  • При работе с любыми типами переключателей, будь то физические кнопки, DIP-переключатели, реле и т. Д., Вы должны обязательно реализовать какой-либо способ отвода сигнала . При нажатии кнопки происходит электромеханический отскок, который проявляется в виде шипа на линии до тех пор, пока он не станет устойчивым. Вы можете просмотреть это с помощью осциллографа, подключив одну сторону кнопки для питания через резистор, а другую сторону к земле.

    Неспособность отклонить такой сигнал - очень распространенная ошибка для начинающих. Чаще всего это делается в программном обеспечении, несколько раз прочитав кнопку, прежде чем принять решение. Или через аппаратный 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];

И это все.

0 голосов
/ 06 января 2019

Прежде всего, я рекомендую сначала просто очистить 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);

Конечно, вы можете использовать текущий способ включения / выключения светодиодов (но без длинной цепочки if ... else if):

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