[ Log In ]
Thumbnail: quad buffer line driver 74HC126E

Quad Buffer Line Driver (Through Hole)

$0.69
Qty:
Image of the Atmega324p

Atmega324P

$8.50
Qty:
Serial to USB converter with Micro USB cable

USB to Serial Converter

$10.95
Qty:
Thumbnail: Crystal Oscillator 18.432 MHz for UART

18.432 MHz Crystal Oscillator 18pf 30ppm

$0.94
Qty:
Thumbnail: 22 pF Capacitor

22 pF Multilayer Ceramic Capacitor

$0.43
Qty:
Thumbnail: Quartz crystal oscillator - 16 MHz

16 MHz Crystal Oscillator 20 pF Through Hole

$0.75
Qty:
Thumbnail: 4x4 keypad top view.

4x4 Keypad with Adhesive Backing

$3.80
Qty:
USB AVR programmer

USB AVR Programmer

$9.95
Qty:
3 pin slide switch

SPDT Slide Switch 3 pin 30V

$1.49
Qty:
Handheld auto range multimeter

Handheld Auto Ranging Digital Multimeter

$17.95
Qty:
Skip Navigation Links

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