Search code examples
carduinoembeddedones-complement

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


I am using dip switches as inputs and LEDs as outputs to resemble the ones complement of any given input. I am programming an Arduino Uno to attempt to do that. I am also not very experienced with bitwise efficiency; is there a way to greatly reduce lines in my code?

What I currently have is a bunch of if-statements.

#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;
}

Also, another problem I'm having is that only one LED turns off at a time; if I flip one switch and then the other, the LED for the first switch I flipped turns back on as soon as I flip the other one.


Solution

  • First of all I recommend that you simply clear PORTB first. Then you can easily set just the bits you need to be set.

    As for the big if...else if chain, you could shift down the value of PIND four bits, and complement it.

    Something like:

    // 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);
    

    Of course, you you can still use your current way to turn on/off the LEDs (but still without the long if ... else if chain):

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