Accelerometer Maze Game: The Big Picture

For our final lab assignment we were tasked with the most open ended objective possible, creating our own combination of hardware + software. We began throwing around ideas in labs 3 & 4, but nothing really stood out to us until Eugene suggested using an accelerometer to control some sort of game. With this idea in mind, we thought that a game where you navigate a cursor to the end of a maze to be interesting and challenging enough for us.

The game takes input from the accelerometer to move the position of a ball on the onboard LCD screen.  Once the ball reaches the end of the maze, the game won screen displays and the buzzer goes off.  The program then waits for the user to hit a button to start the game again.

 

Pictures of the project

IMG_1102

 

IMG_1103

Accelerometer Maze Game Code

This is the code for the maze game.  This program is pretty involved, and uses both C and Assembly.  The assembly files handle the conversion of the 10 bit signed integer position values from the accelerometer and turn them into signed 16 bit integers.  The rest of the code handles the bitmaps for the maze, the ball, and displaying the output to an LCD.  It also translates the coordinates into information about the acceleration of the ball and the direction.

(Instructor Note: This code uses Eugene Rockey’s serial I2C/TWI interface code, developed in spring 2016, which is going to lead to tons of great A3BU-based projects. The team did a lot of original work on getting the maze bitmaps to connect to accelerometer data and game actions.)

Here is the assembly file COMBINE.s


.global COMBINE

COMBINE: mov XL,r24 ;data_0
mov XH,r22 ;data_1
ldi r30,0x02 ;bit mask for testing sign bit
and r30,XH ;test sign bit
brbc 1,NEGATIVE ;if negative, jump to NEGATIVE routine
jmp END ;if positive, leave as is

NEGATIVE: ori XH,0xFC ;make X register a proper 16-bit two's complement

END: mov r24,XL ;move values to be stored into memory
mov r25,XH
ret

Here is the header file for the game_data.h

#ifndef GAME_DATA_H_
#define GAME_DATA_H_

#include <asf.h>

gfx_mono_color_t blank_data[5] = {
0x00,0x00,0x00,0x00,0x00
};

struct gfx_mono_bitmap blank = {
.width = 5 ,
.height = 8 ,
GFX_MONO_BITMAP_RAM ,
.data.pixmap = (gfx_mono_color_t *)blank_data
};

const gfx_mono_color_t ball_data[5] = {
0x04,0x0E,0x1F,0x0E,0x04
};

struct gfx_mono_bitmap ball = {
.width = 5 ,
.height = 8 ,
GFX_MONO_BITMAP_RAM ,
.data.pixmap = (gfx_mono_color_t *)ball_data
};

gfx_mono_color_t new_ball_data[5] = {
0x00,0x00,0x00,0x00,0x00
};

struct gfx_mono_bitmap new_ball = {
.width = 5 ,
.height = 8 ,
GFX_MONO_BITMAP_RAM ,
.data.pixmap = (gfx_mono_color_t *)new_ball_data
};

const gfx_mono_color_t maze_data[512] = {
//each page of data contains 128 bytes

//page1
0xFF,0x01,0x01,0x01,0x01,0x01,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0xC1,0x01,0x01,0x01,0x01,0x01,
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0xC1,0x01,0x01,0x01,0x01,0x01,0xC1,0x01,0x01,0x01,0x01,0x01,0x7F,0x41,0x41,0x41,0x41,0x41,
0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x01,0x01,0x01,0x01,0x01,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
0xC1,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0xC1,0x01,0x01,0x01,0x01,0x01,0xFF,0x01,0x01,0x01,0x01,0x01,
0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
//page 2
0xFF,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0xFF,0x30,0x30,0x30,0x30,0x30,
0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x3F,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
0x30,0x30,0x30,0x30,0x30,0x30,0xF0,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0xF0,0x00,0x00,0x00,0x00,0x00,
0xFF,0x00,0x00,0x00,0x00,0x00,0xF0,0x30,0x30,0x30,0x30,0x30,0xF0,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,0x00,
0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
//page 3
0xFF,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,
0xF8,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0xF8,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0xF8,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,
0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0xFF,0x08,0xE8,0xE8,0xE8,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
//page 4
0xFF,0x80,0x80,0x80,0x80,0x80,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x83,0x80,0x80,0x80,0x80,0x80,
0xFF,0x80,0x80,0x80,0x80,0x80,0x82,0x82,0x82,0x82,0x82,0x82,0x83,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x80,0x80,0x80,0x80,0x80,
0xFF,0x80,0x80,0x80,0x80,0x80,0x83,0x82,0x82,0x82,0x82,0x82,0x82,0x80,0x80,0x80,0x80,0x80,0x83,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,
0x83,0x80,0x80,0x80,0x80,0x80,0xFF,0x80,0x80,0x80,0x80,0x80,0x82,0x82,0x82,0x82,0x82,0x82,0x83,0x82,0x82,0x82,0x82,0x82,0x82,0x80,0x80,0x80,0x80,0x80,
0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

};

struct gfx_mono_bitmap maze = {
.width = 128 ,
.height = 32 ,
GFX_MONO_BITMAP_RAM ,
.data.pixmap = (gfx_mono_color_t *)maze_data
};
#endif /* GAME_DATA_H_ */

 

Here is another header file containing most of the custom functions


modified_functions.h

#include "gfx_mono_c12832_a1z.h"
#include "game_data.h"
#include <string.h>

#ifdef ST7565R_SERIAL_INTERFACE
# define CONFIG_ST7565R_FRAMEBUFFER
#endif

#ifdef CONFIG_ST7565R_FRAMEBUFFER
static uint8_t framebuffer[GFX_MONO_LCD_FRAMEBUFFER_SIZE];
#endif

#ifndef MODIFIED_FUNCTIONS_H_
#define MODIFIED_FUNCTIONS_H_

//prototypes
void twi_init(void);
void display_ball(struct gfx_mono_bitmap*, struct gfx_mono_bitmap*, struct gfx_mono_bitmap*,
gfx_coord_t, gfx_coord_t,int*);
void shift_ball_down(gfx_mono_color_t*,gfx_mono_color_t*,int);
void shift_ball_up(gfx_mono_color_t*,gfx_mono_color_t*,int);
void merge_graphics(gfx_mono_color_t*,gfx_mono_color_t*,gfx_coord_t,gfx_coord_t,int,int);
void clear_graphic_5v5(gfx_mono_color_t*);
void init_maze_array(bool[32][128],const gfx_mono_color_t*);
bool test_move_right(bool[32][128],int,int);
bool test_move_left(bool[32][128],int,int);
bool test_move_forward(bool[32][128],int,int);
bool test_move_backward(bool[32][128],int,int);
bool test_for_wall(bool[32][128],int,int);
void clearscreen(void);
void displaymenu(void);

//definitions
void twi_init(void)
{
twi_master_options_t opt = {
.speed = 100000,
.chip = 0x53
};
twi_master_setup(&TWIC, &opt);
}
void display_ball(struct gfx_mono_bitmap *ball, struct gfx_mono_bitmap *new_ball, struct gfx_mono_bitmap *maze,
gfx_coord_t x, gfx_coord_t y, int *previous_page)
{
int current_page = y/8;
int page_starting_point = current_page * 8;
//clear stuff
clear_graphic_5v5(new_ball->data.pixmap);
clear_graphic_5v5(blank_data);

if(y<8){
if(x<5){
merge_graphics(blank_data,maze->data.pixmap,0,y,0,x); //clear left
gfx_mono_put_bitmap(&blank,0,0);
clear_graphic_5v5(blank_data);
merge_graphics(blank_data,maze->data.pixmap,0,y,1,x); //clear left, one page down
gfx_mono_put_bitmap(&blank,0,8);
clear_graphic_5v5(blank_data);

merge_graphics(blank_data,maze->data.pixmap,x,y,1,blank.width); //clear center-down
gfx_mono_put_bitmap(&blank,x,8);
clear_graphic_5v5(blank_data);
merge_graphics(blank_data,maze->data.pixmap,x+5,y,0,blank.width); //clear right
gfx_mono_put_bitmap(&blank,x+5,0);
clear_graphic_5v5(blank_data);
merge_graphics(blank_data,maze->data.pixmap,x+5,y,1,blank.width); //clear right, one page down
gfx_mono_put_bitmap(&blank,x+5,8);
clear_graphic_5v5(blank_data);
}
else if(x>4 && x<123){
merge_graphics(blank_data,maze->data.pixmap,x-5,y,0,blank.width); //clear left
gfx_mono_put_bitmap(&blank,x-5,0);
clear_graphic_5v5(blank_data);
merge_graphics(blank_data,maze->data.pixmap,x+5,y,0,blank.width); //clear right
gfx_mono_put_bitmap(&blank,x+5,0);
clear_graphic_5v5(blank_data);
merge_graphics(blank_data,maze->data.pixmap,x-5,y+8,1,blank.width); //clear left
gfx_mono_put_bitmap(&blank,x-5,8);
clear_graphic_5v5(blank_data);
merge_graphics(blank_data,maze->data.pixmap,x+5,y+8,1,blank.width); //clear right
gfx_mono_put_bitmap(&blank,x+5,8);
clear_graphic_5v5(blank_data);
}
else{
merge_graphics(blank_data,maze->data.pixmap,x-5,y,0,blank.width); //clear left
gfx_mono_put_bitmap(&blank,x-5,0);
clear_graphic_5v5(blank_data);
merge_graphics(blank_data,maze->data.pixmap,x-5,y,1,blank.width); //clear left
gfx_mono_put_bitmap(&blank,x-5,8);
clear_graphic_5v5(blank_data);
}
}
else if(y>7 && y<23){
if(x<5){
merge_graphics(blank_data,maze->data.pixmap,0,y,current_page,x); //clear left
gfx_mono_put_bitmap(&blank,0,page_starting_point);
clear_graphic_5v5(blank_data);
merge_graphics(blank_data,maze->data.pixmap,0,y,current_page+1,x); //clear left, one page down
gfx_mono_put_bitmap(&blank,0,page_starting_point+8);
clear_graphic_5v5(blank_data);

merge_graphics(blank_data,maze->data.pixmap,x+5,y,current_page,blank.width); //clear right
gfx_mono_put_bitmap(&blank,x+5,page_starting_point);
clear_graphic_5v5(blank_data);
merge_graphics(blank_data,maze->data.pixmap,x+5,y,current_page+1,blank.width); //clear right, one page down
gfx_mono_put_bitmap(&blank,x+5,page_starting_point+8);
clear_graphic_5v5(blank_data);
}
else if(x>4 && x<123){
merge_graphics(blank_data,maze->data.pixmap,x-5,y,current_page,blank.width); //clear left
gfx_mono_put_bitmap(&blank,x-5,page_starting_point);
clear_graphic_5v5(blank_data);
merge_graphics(blank_data,maze->data.pixmap,x+5,y,current_page,blank.width); //clear right
gfx_mono_put_bitmap(&blank,x+5,page_starting_point);
clear_graphic_5v5(blank_data);
merge_graphics(blank_data,maze->data.pixmap,x-5,y+8,current_page+1,blank.width); //clear left, one page down
gfx_mono_put_bitmap(&blank,x-5,page_starting_point+8);
clear_graphic_5v5(blank_data);
merge_graphics(blank_data,maze->data.pixmap,x+5,y+8,current_page+1,blank.width); //clear right, one page down
gfx_mono_put_bitmap(&blank,x+5,page_starting_point+8);
clear_graphic_5v5(blank_data);
}
else{
merge_graphics(blank_data,maze->data.pixmap,x-5,y,current_page,blank.width); //clear left
gfx_mono_put_bitmap(&blank,x-5,page_starting_point);
clear_graphic_5v5(blank_data);
merge_graphics(blank_data,maze->data.pixmap,x-5,y,current_page+1,blank.width); //clear left, one page down
gfx_mono_put_bitmap(&blank,x-5,page_starting_point+8);
clear_graphic_5v5(blank_data);
}
}
else{
if(x<5){
merge_graphics(blank_data,maze->data.pixmap,0,y,current_page,x); //clear left
gfx_mono_put_bitmap(&blank,0,page_starting_point);
clear_graphic_5v5(blank_data);
merge_graphics(blank_data,maze->data.pixmap,x+5,y,current_page,blank.width); //clear right
gfx_mono_put_bitmap(&blank,x+5,page_starting_point);
clear_graphic_5v5(blank_data);
}
else if(x>4 && x<123){
merge_graphics(blank_data,maze->data.pixmap,x-5,y,current_page,blank.width); //clear left
gfx_mono_put_bitmap(&blank,x-5,page_starting_point);
clear_graphic_5v5(blank_data);
merge_graphics(blank_data,maze->data.pixmap,x+5,y,current_page,blank.width); //clear right
gfx_mono_put_bitmap(&blank,x+5,page_starting_point);
clear_graphic_5v5(blank_data);
}
else{
merge_graphics(blank_data,maze->data.pixmap,x-5,y,current_page,blank.width); //clear left
gfx_mono_put_bitmap(&blank,x-5,page_starting_point);
clear_graphic_5v5(blank_data);
}
}
//display ball graphic window
if((y-page_starting_point) < 4){ //ball should display on one page (no overlap)
shift_ball_down(ball->data.pixmap,new_ball->data.pixmap,y-page_starting_point);
merge_graphics(new_ball->data.pixmap,maze->data.pixmap,x,y,y/8,new_ball->width); //merge maze and ball graphics
gfx_mono_put_bitmap(new_ball,x,y);
}
// else if((y-page_starting_point) > 3){
else{
shift_ball_down(ball->data.pixmap,new_ball->data.pixmap,y-page_starting_point);
merge_graphics(new_ball->data.pixmap,maze->data.pixmap,x,y,y/8,new_ball->width);
gfx_mono_put_bitmap(new_ball,x,y);

shift_ball_up(ball->data.pixmap,new_ball->data.pixmap,y-page_starting_point);
merge_graphics(new_ball->data.pixmap,maze->data.pixmap,x,y,y/8+1,new_ball->width);
gfx_mono_put_bitmap(new_ball,x,y+8);
}

/*
merge_graphics(blank_data,maze->data.pixmap,x-5,y,y/8);
gfx_mono_put_bitmap(&blank,x-5,y);
*/
if(current_page>*previous_page){
clear_graphic_5v5(new_ball->data.pixmap);
merge_graphics(new_ball->data.pixmap,maze->data.pixmap,x,y-8,(y-8)/8,new_ball->width);
gfx_mono_put_bitmap(new_ball,x,y-8);
}
if((y-page_starting_point)==3){
clear_graphic_5v5(new_ball->data.pixmap);
merge_graphics(new_ball->data.pixmap,maze->data.pixmap,x,y+8,(y+8)/8,new_ball->width);
gfx_mono_put_bitmap(new_ball,x,y+8);
}

*previous_page = current_page;
}
void shift_ball_down(gfx_mono_color_t *ball_data, gfx_mono_color_t *new_ball_data, int relative_y)
{
int i;

for( i=0; i<5; i++ ){
new_ball_data[i] = ball_data[i] << relative_y;
}
}
void shift_ball_up(gfx_mono_color_t *ball_data, gfx_mono_color_t *new_ball_data, int relative_y)
{
int i;

for( i=0; i<5; i++ ){
new_ball_data[i] = ball_data[i] >> (8-relative_y);
}
}

void merge_graphics(gfx_mono_color_t *new_ball_data, gfx_mono_color_t *maze_data, gfx_coord_t x, gfx_coord_t y, int page, int width)
{
int i;

for(i=0;i<width;i++){
new_ball_data[i] = new_ball_data[i] | maze_data[i+x+(page*128)];
}
}

void clear_graphic_5v5(gfx_mono_color_t *graphic_data)
{
for(int i = 0;i <5; i++){
*(graphic_data + i) = 0;
}
}
void init_maze_array(bool maze_array[32][128], const gfx_mono_color_t *maze_data)
{
//converts data from maze bitmap into boolean array
//true==wall
//false==empty
uint8_t temp,bitmask,bitpos,row,column,page;

for(int i=0;i<512;i++){
bitpos = 0;
bitmask = 0x01;
page = i / 128;
column = i - (page * 128);
temp = *(maze_data + i); //stores byte of bitmap into variable

for(int x=0;x<8;x++){
row = bitpos + (page * 8);
maze_array[row][column] = (bool)((temp & bitmask) >> bitpos);

bitpos++;
bitmask = bitmask << 1;
}
temp = 0;
}

//clear winning cell
for(row=0;row<5;row++){
for(column=0;column<5;column++){
maze_array[row+20][column+109] = false;
}
}

}
bool test_for_wall(bool maze_array[32][128],int xpos,int ypos)
{
return maze_array[ypos][xpos];
}

bool test_move_right(bool maze_array[32][128],int xpos,int ypos)
{
bool test0,test1,test2,test3,test4;

test0 = !test_for_wall(maze_array,xpos+5,ypos);
test1 = !test_for_wall(maze_array,xpos+5,ypos+1);
test2 = !test_for_wall(maze_array,xpos+5,ypos+2);
test3 = !test_for_wall(maze_array,xpos+5,ypos+3);
test4 = !test_for_wall(maze_array,xpos+5,ypos+4);

if(test0 && test1 && test2 && test3 && test4){
return true;
}
else
return false;

}
bool test_move_left(bool maze_array[32][128],int xpos,int ypos)
{
bool test0,test1,test2,test3,test4;

test0 = !test_for_wall(maze_array,xpos-1,ypos);
test1 = !test_for_wall(maze_array,xpos-1,ypos+1);
test2 = !test_for_wall(maze_array,xpos-1,ypos+2);
test3 = !test_for_wall(maze_array,xpos-1,ypos+3);
test4 = !test_for_wall(maze_array,xpos-1,ypos+4);

if(test0 && test1 && test2 && test3 && test4){
return true;
}
else
return false;

}
bool test_move_forward(bool maze_array[32][128],int xpos,int ypos)
{
bool test0,test1,test2,test3,test4;

test0 = !test_for_wall(maze_array,xpos,ypos-1);
test1 = !test_for_wall(maze_array,xpos+1,ypos-1);
test2 = !test_for_wall(maze_array,xpos+2,ypos-1);
test3 = !test_for_wall(maze_array,xpos+3,ypos-1);
test4 = !test_for_wall(maze_array,xpos+4,ypos-1);

if(test0 && test1 && test2 && test3 && test4){
return true;
}
else
return false;

}
bool test_move_backward(bool maze_array[32][128],int xpos,int ypos)
{
bool test0,test1,test2,test3,test4;

test0 = !test_for_wall(maze_array,xpos,ypos+5);
test1 = !test_for_wall(maze_array,xpos+1,ypos+5);
test2 = !test_for_wall(maze_array,xpos+2,ypos+5);
test3 = !test_for_wall(maze_array,xpos+3,ypos+5);
test4 = !test_for_wall(maze_array,xpos+4,ypos+5);

if(test0 && test1 && test2 && test3 && test4){
return true;
}
else
return false;

}

void clearscreen(void)
{
for(int page=0;page<5;page++){
st7565r_set_page_address(page);
for(int column=0;column<128;column++){
st7565r_set_column_address(column);
st7565r_write_data(0x00);
}
}
}
void displaymenu(void)
{
clearscreen();
char string[22]="Welcome to The Maze";
gfx_mono_draw_string(string,0,0,&sysfont);
gfx_mono_draw_horizontal_line(0,7,strlen(string)*6,GFX_PIXEL_CLR);

strcpy(string,"Press any button...");
gfx_mono_draw_string(string,0,16,&sysfont);
gfx_mono_draw_horizontal_line(0,23,114,GFX_PIXEL_CLR);

}

#endif /* MODIFIED_FUNCTIONS_H_ */

 

 

Here is the main function file main.c


#include <asf.h>
#include <board.h>
#include <sysclk.h>
#include "game_data.h"
#include "modified_functions.h"
#include "keyboard.h"
//variables
int8_t data_x0=0,data_x1=0,data_y0=0,data_y1=0,data_z0=0,data_z1=0;
int16_t x_combined, y_combined, z_combined;
char mystring[20];
uint8_t bit_pos;
int ball_xpos=1, ball_ypos=14, ball_previous_page=0;
bool temp,maze_array[32][128];
struct pwm_config mypwm;

#define MOVEMENT_THRESHOLD_POS 40 //Minimum threshold values
#define MOVEMENT_THRESHOLD_NEG -20

#define WINNING_POS_X 109 //Winning x and y coordinates
#define WINNING_POS_Y 20
//prototypes
extern int16_t COMBINE(int8_t,int8_t); //assembly function that combines output register data and
//converts it to a 16-bit value

int main(void){

board_init();
sysclk_init();
gfx_mono_init();
twi_init(); //initialize I2C interface
pwm_init(&mypwm, PWM_TCC0, PWM_CH_C, 100); //initialize PWM channel
gpio_set_pin_high(NHD_C12832A1Z_BACKLIGHT); //turn on LCD backlight

int8_t data; //data variable to store info to write to ADXL
int8_t data_received[10]; //data buffer array for I2C
int8_t* ptr = &data;
twi_package_t packet_write={ //I2C data write structure
.addr[0] = 0x31, //DATA_FORMAT register location on ADXL
.addr_length=sizeof(uint8_t),
.chip=0x53, //ADXL address
.buffer=(void*)ptr,
.length=sizeof(data)
};
data = 0x00;
while (twi_master_write(&TWIC, &packet_write) != TWI_SUCCESS); //sets the AXDL resolution to 2g resolution

//set AXDL to measure
packet_write.addr[0] = 0x2D; //PWER_CTL register location on ADXL
data=0x08;
while (twi_master_write(&TWIC, &packet_write) != TWI_SUCCESS); //sets AXDL to "measure mode"

twi_package_t packet_read = { //I2C data write structure
.addr = {0x32,0x33,0x34,0x35,0x36,0x37}, // array of data registers that will be read from ADXL
.addr_length = sizeof(int8_t),
.chip = 0x53, // slave address
.buffer = data_received, // transfer data destination buffer
.length = 6 // transfer data size (bytes) / one for each register
};

init_maze_array(maze_array,maze_data); //creates boolean array for boundaries from bitmap data

//gfx_mono_draw_string("X=",0,0,&sysfont); //Display the axis on LCD
//gfx_mono_draw_string("Y=",0,8,&sysfont);
//gfx_mono_draw_string("Z=",0,16,&sysfont);

int duty; //variable to set PWM duty cycle
struct keyboard_event input; //struct for button operation on menu screen

while(1)
{
displaymenu(); //display start menu
do{
keyboard_get_key_state(&input);
}while(input.type != KEYBOARD_RELEASE); //when button is pressed and released, begin game

clearscreen(); //Display instructions
strcpy(mystring,"Tilt the breadboard");
gfx_mono_draw_string(mystring,0,0,&sysfont);
gfx_mono_draw_horizontal_line(0,7,strlen(mystring)*6,GFX_PIXEL_CLR);
strcpy(mystring,"to move the ball");
gfx_mono_draw_string(mystring,0,8,&sysfont);
gfx_mono_draw_horizontal_line(0,15,strlen(mystring)*6,GFX_PIXEL_CLR);
strcpy(mystring,"to the end");
gfx_mono_draw_string(mystring,0,16,&sysfont);
gfx_mono_draw_horizontal_line(0,23,strlen(mystring)*6,GFX_PIXEL_CLR);
delay_s(15);

/* BEGIN GAME */

while(true){

gfx_mono_put_bitmap(&maze,0,0); //print maze and ball
display_ball(&ball,&new_ball,&maze,ball_xpos,
ball_ypos,&ball_previous_page);

if(ball_xpos== WINNING_POS_X //check to see if ball is winning position
&& ball_ypos == WINNING_POS_Y){

clearscreen(); //print winning message
gfx_mono_draw_string("You win!!",35,8,&sysfont);
gfx_mono_draw_horizontal_line(35,15,9,GFX_PIXEL_CLR);

int loop=0; //trigger winning sound
pwm_start(&mypwm,50);

while(loop<6){
for(duty=35;duty<=65;duty++){
pwm_set_duty_cycle_percent(&mypwm,duty);
delay_ms(10);
}
for(duty=65;duty>=35;duty--){
pwm_set_duty_cycle_percent(&mypwm,duty);
delay_ms(10);

}
loop++;
}
pwm_set_duty_cycle_percent(&mypwm,0);

ball_xpos = 1; //reset ball to starting position
ball_ypos = 14;

break;
}

for(int i=0;i<10;i++){ //initialize buffer array before reading
data_received[i]=0;
}//end for

if(twi_master_read(&TWIC, &packet_read) == TWI_SUCCESS){
data_x0 = data_received[0]; //Read data from AXDL and store values
data_x1 = data_received[1];
data_y0 = data_received[2];
data_y1 = data_received[3];
data_z0 = data_received[4];
data_z1 = data_received[5];
}//end if

x_combined = 0; //clear previous values
y_combined = 0;
z_combined = 0;

x_combined = COMBINE(data_x0,data_x1); //combine results into a 16-bit signed value
y_combined = COMBINE(data_y0,data_y1);
z_combined = COMBINE(data_z0,data_z1);

if((int)x_combined >= MOVEMENT_THRESHOLD_POS //test for x axis tilt
|| (int)x_combined <= MOVEMENT_THRESHOLD_NEG){
if((int)x_combined >= MOVEMENT_THRESHOLD_POS){
gfx_mono_st7565r_put_byte(ball_ypos/8,ball_xpos,0x00);
if(test_move_right(maze_array,ball_xpos,ball_ypos)){
ball_xpos++; //increment ball if it clear path
if(ball_xpos>123){
ball_xpos=123; //if ball is at edge of screen, don't increment
}//end if
}
}//end if
else if((int)x_combined <= MOVEMENT_THRESHOLD_NEG){ //test for x axis tilt
gfx_mono_st7565r_put_byte(ball_ypos/8,ball_xpos+4,0x00);
if(test_move_left(maze_array,ball_xpos,ball_ypos)){
ball_xpos--; //decrement ball if it clear path
if(ball_xpos<0){
ball_xpos=0; //if ball is at edge of screen, don't decrement
}
}
}
}

if((int)y_combined >= MOVEMENT_THRESHOLD_POS
|| (int)y_combined <= MOVEMENT_THRESHOLD_NEG){
if ((int)y_combined >= MOVEMENT_THRESHOLD_POS){ //test for y axis tilt
if(test_move_forward(maze_array,ball_xpos,ball_ypos)){
ball_ypos--; //decrement ball if it clear path
if(ball_ypos<0){
ball_ypos=0; //if ball is at edge of screen, don't decrement
}//end if
}
}//end if
else if((int)y_combined <= MOVEMENT_THRESHOLD_NEG){ //test for y axis tilt
if(test_move_backward(maze_array,ball_xpos,ball_ypos)){
ball_ypos++; //increment ball if it clear path
if(ball_ypos>27){
ball_ypos=27; //if ball is at edge of screen, don't increment
}
}
}
}

display_ball(&ball,&new_ball,&maze,
ball_xpos,ball_ypos,&ball_previous_page); //draw ball with new position

delay_ms(15); //wait for a bit...
}
}
}//end main

Accelerometer Maze Game: Schematic

This is the schematic for the Maze Game.  This project was not as involved on the hardware side as a lot of other projects were.  It only required an accelerometer, 3 220-ohm resistors, a piezo buzzer, and several wires for the I2C communication from the accelerometer and the A3BU.

Image

(Instructor note: hmmm. this link does not work off campus. The Speedometer project uses the same accelerometer, here’s their schematic)