Microcontroller - A Beginners Guide - The Button Game
It's time to apply a bit of what was learned and create an actual game. This game
uses a couple of push buttons, two sets of LEDs (2 rows of 7 LEDs). The object of
the game is for two people to try to press their button the most times in the shotest
amount of time. As the button is pressed, the LEDs are lit up one after another
until the last LED is lit and that side wins. The winner is exposed by their side
of LEDs flashing.
The circuit consists of two rows of LEDs, 7 LEDs on each row. Since there are 7
LEDs for each side, a single port can be used for each set, and there is still room
for a push button on each port. One push button and 7 LEDs can be wired to 8 pins,
or one port worth of pins. In the video, I use port B for one player's button and
LEDs and port D for the other player's button and LEDs.
Three other programming fundamentals were also demonstrated in the video: arrays,
encapsulation and a bit more information on variables. The arrays are used to simplify
the variables used for each player. Instead of creating unique varibles for the
button debouncing, button press and LEDs to be lit, a single variable was used for
each containing an array of "2", one for each player. This also made encapsulation
and repetitive code use much easier. If code is to be re-used in the program more
than once, it makes sense to put that code in a special area called a function,
or a method so it can be called whenever it is needed. since there were two players,
we had identical code that was going to be used twice when the button press and
release is tested and the code that is used to light up the LEDs.
Specifically, in the program, you will see a few new things. With the creation of
new functions, we can essentially create what looks like new commands that the program
will undestand. These functions are called ProcessPressedButton and ProcessReleasedbutton.
With the help of the arrays, all that needs to be done is the array number (player
number) be passed into these fnctions. In the program, the first thing you will
notice is that there are a couple of statements with "void" at the beginning. These
are called function prototypes. The language of C, or C++ requires these function
prototypes to inform the compiler that these are used in the program before they
are actuall defined. Notice that the functions are used in the program (within the
main function) before the actual functions and code (after the main function). An
alternative to this would be to actually put the main function at the end of the
program, and remove the prototypes, but I personally like keeping the main function
at the beginning for clarity. There is even a better alternative: to create a couple
of library files that contain these new functions, but we have not gotten to this
level of programming yet at this poing in the tutorial series.
You will also notice that there are integers (variables) outside of the main function
(ignore the brackets and number 2 for now). This will force these variables to have
a global scope. Ok, I know... I haven't discussed scope yet (not even in the video).
Scope is where the declared variables will be used. If a variable is declared within
a specific code block, like in a function, then the variable will live and die in
this code block, and any code blocks within this block. For instance, if the variables
are declared within the main function, these variables cannot be used within another
function that resides outside the main function. If the variables are defined at
the bottom most level (outside of any block), they become global, and any code block
can use them.
Now the arrays... notice the [2] at the end of the global variables. This allows
for two of these same variables to be created and differentiated by using a [0]
or [1]. Why "0"? The numbers are indexed from 0, not 1. So, take the Pressed[2]
as an example. This creates a variable called Pressed[0] and a Pressed[1]. Notice
in the functions that I have a variable within the brackets. Encapsulation and arrays
can provide some really cool features in programming.
#include <avr/io.h>
#include <util/delay.h>
void ProcessPressedButton(int ButtonPressed);
void ProcessReleasedButton(int ButtonReleased);
int Pressed_Confidence_Level[2];
int Released_Confidence_Level[2];
int Pressed[2];
int LEDNumber[2];
int main(void)
{
DDRB = 0b01111111;
DDRD = 0b01111111;
PORTB = 0b10000000;
PORTD = 0b10000000;
while (1)
{
if (bit_is_clear(PINB, 7))
{
ProcessPressedButton(0);
}
else
{
ProcessReleasedButton(0);
}
if (bit_is_clear(PIND, 7))
{
ProcessPressedButton(1);
}
else
{
ProcessReleasedButton(1);
}
}
}
void ProcessPressedButton(int ButtonPressed)
{
Pressed_Confidence_Level[ButtonPressed] ++;
if (Pressed_Confidence_Level[ButtonPressed] > 500)
{
if (Pressed[ButtonPressed] == 0)
{
Pressed[ButtonPressed] = 1;
if (ButtonPressed == 0) PORTB |= 1 << LEDNumber[ButtonPressed];
if (ButtonPressed == 1) PORTD |= 1 << LEDNumber[ButtonPressed];
LEDNumber[ButtonPressed] ++;
if (LEDNumber[ButtonPressed] >6)
{
for(int i=0;i < 10;i++)
{
if (ButtonPressed == 0) PORTB = 0b11111111;
if (ButtonPressed == 1) PORTD = 0b11111111;
_delay_ms(10);
if (ButtonPressed == 0) PORTB = 0b10000000;
if (ButtonPressed == 1) PORTD = 0b10000000;
_delay_ms(10);
}
LEDNumber[0] = 0;
LEDNumber[1] = 0;
PORTB = 0b10000000;
PORTD = 0b10000000;
}
}
Pressed_Confidence_Level[ButtonPressed] = 0;
}
}
void ProcessReleasedButton(int ButtonReleased)
{
Released_Confidence_Level[ButtonReleased] ++;
if (Released_Confidence_Level[ButtonReleased] > 500)
{
Pressed[ButtonReleased] = 0;
Released_Confidence_Level[ButtonReleased] = 0;
}
}