Is this the right way to interact with the button/joystick?

Viewed 95

I am currently trying to create memory game with leds, but it becomes humiliating struggle. It would be more logical to start with idea. The idea is that with the help of two diodes some sequence is played and you have to repeat it with the joystick. My program should look something like this...

void main() {
    generateNewGame();
    blinkLeds();
    for (uint8_t index = 0; i < Game_Length; index++) {
        if(waitForPress() != GameArray[index])
            blinkFail();
            return;
        }
    }
    blinkSuccess();
}

This two functions are working fine.

    generateNewGame();
    blinkLeds();

I have a problem with this function

waitForPress()

My "GameArray" is filled with ones and zeros. I want to make it so that if I turn the joystick let's say to the left, then the function "waitForPress()" will return 1 and in the main i want to compare this 1 with my "GameArray", and if this is true, check the next element. Comparison with the "Game" array does not work for me. In addition, for some reason,my left led is constantly on, and the joystick does not respond. I hope my words make sense, I am ready to supplement the question if you have any questions. My code at the moment

#define F_CPU 2000000UL
#include <avr/io.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

// Global
uint8_t Game[8];
int i;


const uint16_t n = 500;

void delay(uint16_t n) {
    for(uint16_t i = 0; i < n ; i++) {
        for(uint16_t j = 0; j < 200 ; j++) {
            asm volatile ("NOP");
        }
    }
}
// Function for filling the game array with ones and zeros 
void RandomNumber() {
    
    srand((unsigned int)time(NULL));
    for(unsigned int i = 0; i < sizeof(Game)/sizeof(Game[0]); i++) {
        int v = rand() % 2;
        Game[i] = v;
    }
}
// Function for flashing the Game array sequence
void PlayDemo() {
    int i;
    for(i = 0; i <= 8; i++) {
        if(Game[i] == 1) {
            PORTA = 0x80;
            delay(n);
            PORTA = 0x00;
            delay(n);
        }
        else if (Game[i] == 0) {
            PORTA = 0x01;
            delay(n);
            PORTA = 0x00;
            delay(n);
        }
        else {
            PORTA = 0x00;
        }
    }
}

int waitForPress() {

    uint8_t x = PINF;
    // Until the button is off, do nothing
    while(!(x & 0x20) && !(x & 0x08)) {
        x = PINF;
    }
    // Check if we press to the left
    if(x & 0x20) {
        // Last LED ON
        PORTA = 0x80;
        // Wait ( Debouncing )
        delay(n);
        return 1;
    }
    // Check if we press to the right side
    if(x & 0x08) {
        // First LED ON
        PORTA = 0x01;
        // Wait ( Debouncing )
        delay(n);
        return 0;
    }
    return 0;
}


int main(void) {
    MCUCR |= 0x80;
    MCUCR |= 0x80;
    DDRA = 0xFF;
    PORTF = 0x20;
    
    RandomNumber();
    PlayDemo();
    
    while(1)
    {
        // Check all elements of the "Game" array
        for(uint8_t index = 0; index < 8; index++) {
            // If the output of the function "waitForPress()" is not equal to "Game" array element
            if(waitForPress() != Game[index]) {
                // End the game
                break;
            } else if(waitForPress() == Game[index]) {
                // Turn all led ON
                PORTA = 0xFF;
                // Wait
                delay(n);
                // Turn all led OFF
                PORTA = 0x00;
                // Wait
                delay(n);
            }
        }
    }
}
1 Answers

There might be multiple issues with your program:

(1) First of all: In the FOR-loop in which you are comparing the user input with your Game-Array, you are calling waitForPress() two times when the user entered the correct answer. This is not what you want, your code should look like this:

//...
if (waitForPress() != Game[index])
{
    //...
    break;
}
else
{
    //... (correct answer)
}
//...

Or you could do:

//...
int userInput = waitForPress();
if (userInput != Game[index])
{
    //...
    break;
}
else
{
    //... (correct answer)
}
//...

(2) Assuming the corrected code in (1), I think another main issue is the way you are processing the user input in general. Let me illustrate the problem:

  • Starting off, nothing is pressed. Your main program called waitForPress() and is "stuck" in the WHILE-loop, waiting for the user to push the joystick.
  • When the user finally pushes the joystick, the function returns 1 or 0.
  • In your main program, this return value is processed according to your IF-statements inside the FOR-loop (see (1)).
  • Shortly after this, waitForPress() is called again (in the case of a wrong input almost immediately; in the case of a correct input after your delays; I'm assuming this is meant to be something like a short "flash" of all LEDs lasting maybe a few hundred milliseconds).
  • Because the button is still pressed (humans are slow!), waitForPress() returns immediately. Now, your program thinks you made the same input again although you didn't even make a second input by your understanding.

To solve this, you want to detect a signal edge. The easiest way to do this is to make sure that the joystick is released before waiting until one button comes on. You may modify waitForPress() like:

int waitForPress() {
    uint8_t x = PINF;

    // Make sure that the user released the joystick
    while((x & 0x20) || (x & 0x08)) {
        x = PINF;
    }

    // Until one button comes on, do nothing
    while(!(x & 0x20) && !(x & 0x08)) {
        x = PINF;
    }

    //...

Additionally, you might want to add mechanisms for dealing with bouncing.

(3) You never exit the WHILE-loop in your main() function. Therefore, your program always remains in the state of expecting user input.

(4) In your function PlayDemo(), you are accessing a "non-existing" Game-array element (Game[8]) because the condition of your FOR-loop is i <= 8 and not i < 8.

Additionally, there might be hardware or hardware configuration problems. Such problems might be hard to find over StackOverflow because I don't have or know your exact setup. You could run test programs to check if your hardware is working fine.

Related