嵌入式系统设计实训
本次嵌入式系统实训式设计一款2048小游戏,在Linux编译环境下及ARM Cortex-A8开发平台下的,实现2048游戏的开发,且对其进行性能分析。《2048》是一款比较流行的数字游戏,最早于2014年3月20日发行。原版2048首先在GitHub上发布,原作者是Gabriele Cirulli,后被移植到各个平台。这款游戏是基于《1024》和《小3传奇》的玩法开发而成的新型数字游戏。《2048》这款小游戏是一款流行的数字游戏,游戏设计初衷是一款益智类的游戏,其特点在于轻松、简单、有趣。在此次实训报告的制作过程中,我们小组将运用学习到的知识以及c编程知识,通过网上现有的资料尝试完成此次实训的开发。
2048益智游戏:有16个格子,初始时会有两个格子上安放了两个数字2,每次可以选择上下左右其中一个方向去滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢外,系统也会在空白的地方随即出现一个数字方块,相同数字的方块在靠拢、相撞时会相加。不断的叠加最终拼凑出2048这个数字就算成功。《2048》中每个格子的数据和颜色的都在不断地刷新,在每一次移动之后,几乎在这4*4的每一个方格上的数据都会变化,因此在每一次移动之后,每一个方格上的数据都要刷新一次。相对的,每一个数的背景颜色是不同的,也就是说,在每一次数据刷新的时候,每一个方格上的颜色也要同样的刷新一次。当屏幕上没有写有数据的方格并且屏幕上的数据没有哪两个相邻的数据是一样的两个数,那么就判定为游戏结束。
本次工程实践训练第一部分是实训装置的使用说明,讲述了系统的组成、硬件的特点和技术指标、软件的使用介绍。第二部分是实训项目部分,叙述了实训的原理、步骤及注意事项等。通过对实训工作情况及项目原理、软硬件的详细介绍,通过实际操作让我们对实训项目有一个充分的认识,培养学生的工程实践能力,进一步提高学生分析和编程能力。
本次项目硬件平台采用粤嵌自主研发的GEC210平台,采用三星s5pv210为芯片方案,该芯片内核为ARM Cortex-A8【2】 。
嵌入式系统是以应用为中心,以计算机技术为基础,软硬件可裁减,以适应应用系统对功能、可靠性、成本、体积和功耗等有严格要求的专用计算机系统。
Linux操作系统介绍
Linux【3】是一套免费使用和自由传播的类UNIX操作系统,其创始人为美国著名黑客 --林纳斯托瓦兹。它能运行主要的UNIX工具软件、应用程序和网络协议,且支持32位和64位硬件,是一个性能稳定的多用户网络操作系统。
操作系统:操作系统是计算机系统中最基本的系统软件,它用于有效地管理系统资源,并为用户使用计算机提供了便利的环境。
ubuntu是一个基于linux的免费开源桌面PC操作系统。
交叉开发
一般来说,研发嵌入式产品,由于从产品成本及功能专用性角度出发考虑。嵌入式产品一般只有程序的运行环境,而并没有程序的编译开发环境。
所以,我们一般在通用电脑上用各种编译开发软件把程序编译调试好后,再下载到开发板或相关产品上去运行。
这个过程,我们称之为交叉开发。
SecureCRT的设置与连接
(1)获取连接上的端口号
用串口线连接好开发板后,启动开发板。
在设备管理器中,查找识别出的端口。
若不能正确识别端口(有感叹号),则需要安装驱动。
(2)SecureCRT的设置
点击快速连接,并进行设置
a.协议: Serial
b.端口: 你电脑识别出的端口号
c.波特率: 115200
d.把数据流控制中的RTS/CTS(R)勾去掉
其它保持默认设置
由于ARM处理器与Inter处理器其设计架构有本质区别。所以要在arm开发板上运行的程序,则必须要用专用的编译器来编译。
(1)在Source Right4.0软件中编写好C源代码文件,并保存到共享文件夹中。
如: 2048.c
(2)在Ubuntu系统的共享目录中,用arm-linux-gcc编译器对2048.c进行编译,使生成一个可执行程序。
arm-linux-gcc 2048.c –o 2048
(3)下载到开发板中
rz
(4)运行2048这个程序
chmod +x 2048
./ 2048
屏幕由y行且每行x个像素点的矩阵组成;在屏幕上显示图像,就是给每个像素点显示一种颜色,颜色值,可以量化:Color = xGreen + yBlue + zRed
我们向屏幕设备文件 /dev/fb0 中写入各点颜色值就可以让屏幕显示相应的图片了。
图4.3 在SecureCRT 下执行
通过添加代码,使得手指按不同方向滑动屏幕时显示不同数字,用来测试ARM开发板是否运行正确,如下图所示手指上滑打印数字1,下滑打印数字2,左滑打印数字3,右滑打印数字4,执行结果如下图所示。
根据运行结果可得,数字显示与手指滑动方向一致,即ARM开发板是良好的。
附录
1.2048小游戏项目程序代码:
#include
#include
#include
#include
#include
#include
#include
#include
#define LCD_WIDTH 800 //屏幕宽度
#define LCD_HEIGHT 480 //屏幕高度
#define ITEM_NUM 4 // 创建4行4列的矩阵
#define ITEM_WIDTH 100 // 图片宽100
#define ITEM_HEIGHT 100 // 图片高100
#define BLANK_SIZE 5
#define MATRIX_X0 (LCD_WIDTH - (ITEM_WIDTH + BLANK_SIZE)*ITEM_NUM)/2
#define MATRIX_Y0 (LCD_HEIGHT - (ITEM_HEIGHT + BLANK_SIZE)*ITEM_NUM)/2
void bmp_display(int x0, int y0,const char *bmp_file);
int *plcd = NULL;
int matrix_2048_bak[4][4];
int matrix_2048[4][4] = {
0, 0 , 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0
};
void print_matrix_2048()
{
int i,j;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4 ; j++)
{
printf("%d " ,matrix_2048[i][j]);
}
printf("\n");
}
}
int is_change()
{
int i, j ;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
if (matrix_2048[i][j] != matrix_2048_bak[i][j])
{
return 1;
}
}
}
return 0;
}
void LCD_Draw_Point(int x, int y, int color)
{
if (x >= 0 && x < 800 && y >= 0 && y < 480)
{
*(plcd + 800*y + x) = color;
}
}
//LCD_Draw_JuXing: 在屏幕点(x0,y0)处画一个长为w,高为h的矩形
void LCD_Draw_JuXing(int x0, int y0, int w, int h ,int color)
{
//假设矩形内任意点的坐标为(x,y)
int x, y;
for (y = y0; y < y0 + h; y++)
{
for (x = x0; x < x0 + w; x++)
{
LCD_Draw_Point(x, y, color);
}
}
}
void LCD_Draw_Matrix()
{
int i, j;
int x0, y0; //每个棋子矩形左上顶点的坐标
for (i = 0; i < ITEM_NUM; i++)
{
for (j = 0; j < ITEM_NUM ; j++)
{
y0 = MATRIX_Y0 + (ITEM_HEIGHT + BLANK_SIZE)*i;
x0 = MATRIX_X0 + (ITEM_WIDTH + BLANK_SIZE)*j;
if (matrix_2048[i][j] == 0)
{
LCD_Draw_JuXing(x0, y0, ITEM_WIDTH, ITEM_HEIGHT, 0xff0000);
}
else
{
char filename[32];
sprintf(filename, "m%d.bmp", matrix_2048[i][j]);
bmp_display(x0, y0, filename);
}
}
}
}
void bmp_display(int x0, int y0,const char *bmp_file)
{
int fd;
unsigned char buf[4];
int ret;
fd = open(bmp_file, O_RDONLY);
if (fd == -1)
{
printf("failed to open %s\n", bmp_file);
return ;
}
lseek(fd, 0 ,SEEK_SET);
read(fd, buf, 2);
if (buf[0] == 0x42 && buf[1] == 0x4d )
{
printf("BMP file\n");
}
else
{
printf("Not BMP file, GOOD BYE\n");
close(fd);
return ;
}
int width,height;
int depth;
lseek(fd, 0x12, SEEK_SET);
read(fd, buf, 4);
width = (buf[0]) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
lseek(fd, 0x16, SEEK_SET);
read(fd, buf, 4);
height = (buf[0]) | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
printf("%d X %d\n", width, height);
lseek(fd, 0x1c, SEEK_SET);
read(fd, buf, 2);
depth = (buf[0]) | (buf[1] << 8);
if (depth != 24 && depth != 32)
{
printf("Not Support\n");
close(fd);
return ;
}
int bytes_per_line = abs(width) * (depth / 8);
int laizi = 0;
if (bytes_per_line % 4 != 0)
{
laizi = 4 - bytes_per_line % 4;
}
int bytes_line = bytes_per_line + laizi;
int size = bytes_line * abs(height);
unsigned char *p = malloc(size);
lseek(fd, 54, SEEK_SET);
read(fd, p, size);
unsigned char b ,g, r ,a;
int color;
int i = 0;
int x;
int y;
for (y = 0; y < abs(height); y++)
{
for (x = 0 ;x < abs(width); x++ )
{
b = p[i++];
g = p[i++];
r = p[i++];
if (depth == 32)
{
a = p[i++];
}
else
{
a = 0;
}
color = (a << 24) | (r << 16) | (g << 8) | (b);
LCD_Draw_Point( width > 0 ? x0 + x : x0 + abs(width) - 1 -x,
height > 0 ? y0 + height - 1 - y : y0 + y,
color);
}
i = i + laizi;
}
free(p);
close(fd);
}
int get_zero_num()
{
int n = 0;
int i, j;
for (i = 0; i < ITEM_NUM ;i++)
{
for (j = 0; j < ITEM_NUM; j++)
{
if (matrix_2048[i][j] == 0)
{
n++;
}
}
}
return n;
}
void fill_random(void)
{
int zero_num = get_zero_num(); //获取数组中值为0的个数
int pos; //随机的位置的编号,应该要在[0, zero_num)
pos = random() % zero_num ; // => pos =>[0,zero_num)
int i,j;
int n = 0; //第几个0
for (i = 0; i < ITEM_NUM; i++)
{
for (j = 0; j < ITEM_NUM; j++)
{
if (matrix_2048[i][j] == 0)
{
if (n == pos)
{
matrix_2048[i][j] = 2;//a[index];
return ;
}
n++;
}
}
}
}
#define MOVE_UP 1
#define MOVE_DOWN 2
#define MOVE_LEFT 3
#define MOVE_RIGHT 4
int get_finger_movemenet(void)
{
int fd;
int ret;
fd = open("/dev/input/event0", O_RDONLY);
//fd = open("/dev/event0", O_RDONLY);
if (fd == -1)
{
printf("open /dev/event0 failed\n");
return -1;
}
int x1 = -1, y1 = -1; //在一次滑动过程中,第一个点的坐标
int x2, y2; //在一次滑动过程中 ,最后一个点的坐标
struct input_event ev;
while (1)
{
ret = read(fd, &ev, sizeof(ev));
if (ret != sizeof(ev))
{
continue;
}
if (ev.type == EV_ABS && ev.code == ABS_X)
{
if (x1 == -1)
{
x1 = ev.value;
}
x2 = ev.value;
}
if (ev.type == EV_ABS && ev.code == ABS_Y)
{
if (y1 == -1)
{
y1 = ev.value;
}
y2 = ev.value;
}
if (ev.type == EV_ABS && ev.code == ABS_PRESSURE && ev.value == 0)
{
int delt_x = abs(x2 - x1); // 左右
int delt_y = abs(y2 - y1); //上下
if (delt_x > 2*delt_y)
{
if (x2 > x1)
{
close(fd);
return MOVE_RIGHT;
}
else
{
close(fd);
return MOVE_LEFT;
}
}
else if (delt_y > 2*delt_x)
{
//上下
if (y2 > y1)
{
close(fd);
return MOVE_DOWN;
}
else
{
close(fd);
return MOVE_UP;
}
}
else
{
x1 = -1;
y1 = -1;
}
}
}
close(fd);
}
void move_left(void)
{
int i, j;
int x, y;
for (i = 0; i < ITEM_NUM; i++)
{
for (x = 0; x < ITEM_NUM; )
{
if (matrix_2048[i][x] != 0)
{
for (y = x + 1; y < ITEM_NUM; y++)
{
if (matrix_2048[i][y] != 0)
{
if (matrix_2048[i][x] == matrix_2048[i][y])
{
matrix_2048[i][x] += matrix_2048[i][y];
matrix_2048[i][y] = 0;
x = y + 1;
break;
}
else
{
x = y;
}
}
}
if (y >= ITEM_NUM)
{
break;
}
}
else
{
x++;
}
}
x = 0;
for (y = 0 ; y < ITEM_NUM; y++)
{
if (matrix_2048[i][y] != 0)
{
if (x != y)
{
matrix_2048[i][x] = matrix_2048[i][y];
matrix_2048[i][y] = 0;
}
x++;
}
}
}
}
void move_right(void)
{
int i, j;
int x, y;
for (i = 0; i < ITEM_NUM; i++)
{
for (x = ITEM_NUM; x >0; )
{
if (matrix_2048[i][x] != 0)
{
for (y = x-1; y>=0; y--)
{
if (matrix_2048[i][y] != 0)
{
if (matrix_2048[i][x] == matrix_2048[i][y])
{
matrix_2048[i][x] += matrix_2048[i][y];
matrix_2048[i][y] = 0;
x = y - 1;
break;
}
else
{
x = y;
}
}
}
if (y<0)
{
break;
}
}
else
{
x--;
}
}
x = ITEM_NUM-1;
for (y = ITEM_NUM-1 ; y >= 0; y--)
{
if (matrix_2048[i][y] != 0)
{
if (x != y)
{
matrix_2048[i][x] = matrix_2048[i][y];
matrix_2048[i][y] = 0;
}
x--;
}
}
}
}
void move_down(void)
{
int i, j;
int x, y;
for (i = 0; i < ITEM_NUM; i++)
{
for (x = 0; x < ITEM_NUM; )
{
if (matrix_2048[x][i] != 0)
{
for (y = x + 1; y < ITEM_NUM; y++)
{
if (matrix_2048[y][i] != 0)
{
if (matrix_2048[x][i] == matrix_2048[y][i])
{
matrix_2048[x][i] += matrix_2048[y][i];
matrix_2048[y][i] = 0;
x = y + 1;
break;
}
else
{
x = y;
}
}
}
if (y >= ITEM_NUM)
{
break;
}
}
else
{
x++;
}
}
x = 0;
for (y = 0; y < ITEM_NUM; y++)
{
if (matrix_2048[y][i] != 0)
{
if (x != y)
{
matrix_2048[x][i] = matrix_2048[y][i];
matrix_2048[y][i] = 0;
}
x++;
}
}
}
}
void move_up(void)
{
int i, j;
int x, y;
for (i = 0; i < ITEM_NUM; i++)
{
for (x = ITEM_NUM; x >=0; )
{
if (matrix_2048[x][i] != 0)
{
for (y = x - 1; y >= 0; y--)
{
if (matrix_2048[y][i] != 0)
{
if (matrix_2048[x][i] == matrix_2048[y][i])
{
matrix_2048[x][i] += matrix_2048[y][i];
matrix_2048[y][i] = 0;
x = y -1;
break;
}
else
{
x = y;
}
}
}
if (y<0)
{
break;
}
}
else
{
x--;
}
}
x = ITEM_NUM-1;
for (y = ITEM_NUM-1 ; y >= 0; y--)
{
if (matrix_2048[y][i] != 0)
{
if (x != y)
{
matrix_2048[x][i] = matrix_2048[y][i];
matrix_2048[y][i] = 0;
}
x--;
}
}
}
}
int is_gameover(void)
{
int x,y;
for(y=0;y { for(x=0;x { if(matrix_2048[x][y]==0) { return 0; } if(x { return 0; } if(y { return 0; } } } return 1; } //根据手指滑动方向变换矩阵 void change_matrix(int mv) { if (mv == MOVE_LEFT) { move_left(); } else if (mv == MOVE_RIGHT) { move_right(); } else if (mv == MOVE_UP) { move_down(); } else if (mv == MOVE_DOWN) { move_up(); } } int main() { //1. 打开文件 int fd = open("/dev/fb0", O_RDWR); if (fd == -1) { printf("failed to open /dev/fb0\n"); return -1; } printf("open /dev/fb0 successfully\n"); //2. 操作文件 plcd = mmap(NULL, 800*480*4, PROT_WRITE, MAP_SHARED, fd, 0); if (plcd == MAP_FAILED) { printf("failed to mmap\n"); return -1; } srandom( time(NULL)) ;//设置随机数种子 LCD_Draw_JuXing(0, 0, LCD_WIDTH, LCD_HEIGHT, 0X555555); fill_random(); //is_gameover(); LCD_Draw_Matrix(); while (1) { int mv = get_finger_movemenet(); printf("mv = %d\n", mv); change_matrix(mv); fill_random(); LCD_Draw_Matrix(); print_matrix_2048(); if (is_gameover()) { break; } } //3.关闭文件 munmap(plcd, 800*480*4); close(fd); }