简体   繁体   中英

How to change led direction depending on button pressed using C, PIC16 and PIC development board?

I created a programn to shift led lights depending on which button is pressed on port a and port b as led flashes either left to right or right to left when a button is pressed on port a. When button 3 is pressed, the led starts bouncing from left to right and resets and continues to do the same forever. When button 0 is pressed, it reverses the direction and moves from right to left. When button 4 is pressed, it reverses the direction again and now it moves from left to right. My problem is that once button 4 is pressed, i cannot reverse the direction again by pressing button 0. How would i modify the code to make it work? Using PIC16F877A and a pic development board

#include <system.h>

void delay(int j) {
int i;
int x = 8600;
while (j != 0) {
    for (i = x; i != 0; i--);
    j--;
}
}

void main() {

trisb = 0; // sets all bits in port B as outputs
adcon1 = 0x06; // sets port A as digital inputs
while (1) // creates infinite loop
{

    if ((porta & 0x8)) { // Switch 3 - Left bounces from left to right and right to left

        portb = 0x80;
        delay(1);

        while (1) {
            while ((portb != 0)) { // Shifts LED from left to right as long as LED 0 is not active
                portb = portb >> 1;
                delay(1);

                if ((portb == 0)) { // When LED 0 is lit, it resets to LED 7
                    portb = 0x80;
                    delay(1);
                }

                if ((porta & 0x1)) { // If SA0 is pressed, LED shifting direction will reverse (right to left)
                    while ((portb != 0x80)) {
                        portb = portb << 1;
                        delay(1);
                        if ((portb == 0x80)) {
                            portb = 0x1;
                            delay(1);
                        }
                        if ((porta & 0x10)) { // If SA4 is pressed, LED shifting direction will reverse (left to right)
                            while ((portb != 0)) {
                                portb = portb >> 1;
                                delay(1);
                                if ((portb == 0)) {
                                    portb = 0x80;
                                    delay(1);
                                }
                            }

                        }
                    }

                }


            }

        }

    }

}

}

EDIT:

void shiftRight() {

char value;
value = 0x80;

for (int i = 0; i < 8; i++) {
    portb = value;
    value = value >> 1;
    delay(1);
}

}

void shiftLeft() {

char value;
value = 0x1;

for (int i = 0; i < 8; i++) {
    portb = value;
    value = value << 1;
    delay(1);
}
}

EDIT 2:

#include <system.h>

void delay(int j) {
int i;
int x = 8600;
while (j != 0) {
    for (i = x; i != 0; i--);
    j--;
}
}

void shiftRight() {

char value = 0b10000000;


for (int i = 0; i < 8; i++) {
    portb = value;
    value = value >> 1;
    delay(1);
}

 }

void shiftLeft() {

char value = 0b00000001;


for (int i = 0; i < 8; i++) {
    portb = value;
    value = value << 1;
    delay(1);
}
}

void main() {

trisb = 0; // sets all bits in port B as outputs
adcon1 = 0x06; // sets port A as digital inputs


int movingRight = 1; //which way the led is moving - 0 = left, 1 = right

// creates infinite loop
while(1)
{

    if(movingRight == 1)
    {
        //led is moving right   
        shiftRight();

        if((porta & 0b00000001) && portb == 0b00000001) /*right button is pressed AND led is at the far right*/ 
        {
            //flip direction
            movingRight = 0;
        }
    }
    else
    {
        //led is moving left
        shiftLeft();

        if((porta&  0b00010000) && portb == 0b10000000) /*left button is pressed AND led is at the left right*/
        {
            //flip direction
            movingRight = 1;
        }
    }
}
}

Use a state variable to keep track of whether the LEDs are supposed to be bouncing, moving left, or moving right and use a single while loop without any nested while loops. Each time through the loop you'd delay for a period of time, then move the LEDs left or right depending on the variable, and then check the status of the buttons, setting the state variable accordingly. Like Weather Vane said it would be a good idea to keep the LED pattern in a variable too.

Possible Python-like psuedocode for this would be

state = 0  # 0 = LEDs off
           # 1 = LEDs bounce left
           # 2 = LEDs bounce right
           # 3 = LEDs cycle left
           # 4 = LEDs cycle right
led_pattern = 0x00 

while True:
    set_leds(led_pattern)          # portb = led_pattern

    delay()

    # Update led_pattern according to the current state

    if state == 1 or state == 3:   # bounce or cycle left
        led_pattern <<= 1          
        if led_pattern & 0xFF == 0x00:
            if state == 1:         # bounce
                led_pattern = 0x40
                state = 2          # start bouncing right
            else:
                led_pattern = 0x01

    if state == 2 or state == 4:   # bounce or cycle right
        led_pattern >>= 1          
        if led_pattern == 0x00:
            if state == 2:         # bounce
                led_pattern = 0x02
                state = 1          # start bouncing left
            else:
                led_pattern = 0x80

    # Check the buttons and change state if necesssary

    if button_3_pressed():         # porta & 0x08
        if state == 1 or state == 3:
             state = 1             # continue moving left if already moving left
        else:
             if state == 0: 
                 led_pattern = 0x80  
             state = 2             # otherwise start moving LEDs to the right

    if button_0_pressed():         # porta & 0x01
        state = 3                  # start cycling left

    if button_3_pressed():         # porta & 0x10
        state = 4                  # start cycling right

The program starts with the state variable set to 0 with the led_pattern variable is set 0x00 . In state 0 the loop doesn't change led_pattern so it always remains 0x00 keeping the all the LEDs turned off. It is however checking the status of the buttons, and if any of them are pushed then it will change the value of the the state variable.

Pressing button 3 when in state 0 causes the the state variable to change to 2 and the led_pattern variable to be set to 0x80 . While in state 2 each iteration of the loop shifts led_pattern one bit to the right. When this results in led_pattern becoming 0, it "bounces" setting led_pattern to 0x02 (as it was 0x01 at the start of the loop), and changes the state variable to 1 . In state 1 the led_pattern variable is shifted to the left and once it "bounces" the state changed back to 2 .

Pressing button 1 when in any state causes causes the state variable to changed to 3 . In this state the led_pattern variable is shifted to the left during each iteration of the loop, just like in state 1 , but instead of "bouncing" it "cycles". Since this doesn't change the direction the LEDs are supposed to move, the state remains 3 and only led_pattern is updated. Similarly pressing button 4 changes the state to 4 where the LEDs are cycled to the right.

Now it's not entirely clear from your question if this is actually what you want your code to do. It doesn't, for example, wait until the moving LEDs have reached the end of their movement before checking the buttons. You can push a button at any time and it'll result in the LEDs immediately start moving in the direction indicated.

Regardless, you should be able to see how you can use just one while loop and a state variable or two to implement whatever behaviour you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM