这是与按钮/游戏杆互动的正确方法吗?

问题描述

我目前正在尝试使用led创建记忆游戏,但是这变得很丢脸。从想法开始会更合乎逻辑。这个想法是在两个二极管的帮助下,播放了一些序列,您必须使用操纵杆重复该过程。我的程序应该看起来像这样...

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

这两个功能正常工作。

    generateNewGame();
    blinkLeds();

我对此功能有疑问

waitForPress()

我的“ GameArray”充满了1和0。 我要这样做,以便如果我将操纵杆转到左侧,那么函数“ waitForPress()”将返回1,并且在主菜单中,我要将其与我的“ GameArray”进行比较,如果为真,请检查下一个元素。与“游戏”数组的比较对我不起作用。另外,由于某种原因,我的左LED指示灯一直亮着,操纵杆没有响应。我希望我的话是有道理的,如果您有任何疑问,我准备补充这个问题。 此刻我的代码

#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)首先:在将用户输入与游戏数组进行比较的FOR循环中,当用户输入正确答案时,您两次调用waitForPress()。这不是您想要的,您的代码应如下所示:

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

或者您可以这样做:

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

(2)假设(1)中的代码已更正,我认为另一个主要问题是您通常处理用户输入的方式。让我来说明问题:

  • 开始时,没有任何操作。您的主程序名为waitForPress(),并“塞住”了WHILE循环,等待用户按下操纵杆。​​ li>
  • 当用户最终按下操纵杆时,该函数返回1或0。
  • 在您的主程序中,此返回值是根据FOR循环中的IF语句处理的(请参阅(1))。
  • 此后不久,waitForPress()再次被调用(在输入错误的情况下,几乎立即;在延迟后输入的情况是正确的;我假设这意味着像简短的输入一样)所有LED的“闪烁”可能持续几百毫秒。
  • 由于仍然按下该按钮(人类很慢!),waitForPress()立即返回。现在,您的程序以为您再次输入了相同的内容,尽管您甚至没有根据自己的理解进行第二次输入。

要解决此问题,您需要检测信号沿。最简单的方法是在等待一个按钮按下之前,确保释放操纵杆。您可以像这样修改waitForPress()

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

    //...

此外,您可能希望添加处理弹跳的机制。

(3)您永远不会在main()函数中退出WHILE循环。因此,您的程序始终保持在期望用户输入的状态。

(4)在函数PlayDemo()中,您正在访问“不存在的”游戏数组元素(Game[8]),因为FOR循环的条件是i <= 8并且不是i < 8

此外,可能存在硬件或硬件配置问题。可能很难在StackOverflow上找到这些问题,因为我没有或不知道您的确切设置。您可以运行测试程序来检查硬件是否运行正常。