粤嵌6818开发板项目

时间:2024-11-09 22:53:41

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

前言

一、前期准备

二、项目内容

1.实现代码

2.上课笔记

总结


前言

        最近接触了一块新的板子,是粤嵌公司自主研发的6818开发板,这块板子有很多有趣的功能,特别是有触摸屏,可以帮助我们实现用手来对其直接的操作,于是,我们开发了一款五子棋的游戏。


提示:以下是本篇文章正文内容,下面案例可供参考

一、前期准备

        GEC6818开发板一块,USB转串口线一根,pc,远程控制终端SecureCRT,安装ubuntu虚拟机,Source Insight 4.0。

        用USB转串口线将开发板的串口与电脑的USB口进行连接。

        为电脑widows系统和虚拟机linux系统创建一个共享文件夹share,我们在widows上的Source Insight 4.0有利于进行代码的编写,把编写完成的代码放到共享文件夹中,可以在虚拟机上对其进行编译。因为最终程序要在6818开发板上运行,所以编译时用arm-linux-gcc编译器,确保在板子上可以运行。

        用SecureCRT连接开发板,点击运行程序->选择菜单文件->快速连接,在弹出的窗口中,协议选择Serial,端口可按win+x打开设备管理器中的端口进行查看,波特率选择115200,其他默认,右边的√全部取消,然后点击连接即可。成功后,在家目录或者根目录下建立自己的一个文件夹,方便找到后续的文件传输位置。

二、项目内容

1.实现代码

代码如下:

#ifndef __TEST_H__
#define __TEST_H__

#include <>
#include <sys/>
#include <sys/>
#include <>
#include <>
#include <sys/>

extern unsigned int *plcd;
int Display(int color, int x, int y);
int Lcd_Init();
void Dis_wh();
int Dis_pic(char *pic);

void lineation();
void background();
void black(int a, int b);
void white(int a, int b);



#endif

#include ""

unsigned int *plcd = NULL;

/*
	Display:对应像素点画规定颜色
	参数:
		@color:想要的颜色
		@x:横坐标
		@y:纵坐标
	返回值:无
*/
void Display(int color, int x, int y)
{
	if(x >=0 && x<=800 && y>=0 && y<=480)
	{
		*(plcd +(800*y +x))= color;
	}
}

/*
	Lcd_Init:LCD屏初始化
	参数:无
	返回值:
		-1:初始化失败
*/
int Lcd_Init()
{
	int fd = open("/dev/fb0", O_RDWR);
	if(fd == -1)
	{
		perror("open error");
		return -1;
	}
	plcd = mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

}


/*
	Dis_pic:显示图片
	参数:
		pic:图片路径
	返回值:
		-2:打开图片失败
*/
int Dis_pic(char *pic)
{
	int fd = open(pic, O_RDONLY);
	if(fd == -1)
	{
		perror("open error");
		return -2;
	}
	
	int width,heigh;
	short depth;
	lseek(fd, 0x12, SEEK_SET);
	read(fd, &width, 4);
	read(fd, &heigh, 4);
	lseek(fd, 0x1c, SEEK_SET);
	read(fd, &depth, 2);
	printf("%d %d %d\n", width,heigh,depth);

	int laizi = (4 - (width * depth / 8) % 4) % 4;
	unsigned char color_buf[heigh * (width * depth /8 + laizi)];//32 24
	char color_a = 0, color_r, color_g, color_b;//颜色分量
	unsigned int color;
	char *p = color_buf;
	lseek(fd, 0x36, SEEK_SET);
	int r;
	while(r != heigh * (width * depth /8 + laizi))
	{
		r = read(fd, color_buf, heigh * (width * depth /8 + laizi));
		printf("%d  %d\n", r,heigh * (width * depth /8 + laizi));
	}
	for(int i=heigh-1; i>=0; i--)
	{
		for(int j=0; j<width; j++)
		{
			color_b = *p++;
			color_g = *p++;
			color_r = *p++;
			if(depth ==32){color_a = *p++;}
			color = color_a << 24 | color_r << 16 | color_g << 8 | color_b;//屏幕需要的颜色
			Display(color, j, i);
		}
		p += laizi;
	}
	
}



#ifndef __EV_H__
#define __EV_H__

#include <>
#include <sys/>
#include <sys/>
#include <>
#include <>
#include <linux/>

int Get_ev(int *x,int *y);
void local_init();
void judge();


#endif

#include ""
#include ""
/*
	position数组用来记录棋盘对应位置上是否落子
*/
int position[700][480];

/*
	win_black:黑子胜
	win_white:白子胜
	win:有一方胜
*/
int win_black,win_white,win;

/*
	local_init:棋盘上各点初始化(没有落子)
	参数:无
	返回值:无
*/
void local_init()
{	
	for(int i=40;i < 480; i+=40)
	{
		for(int j=40 ;j < 700; j+=40)
		{
			position[j][i]=0;
		}
	}
}

/*
	judge:判断是否胜利
	参数:无
	返回值:无
*/
void judge()
{
	for(int i=40;i < 480; i+=40)
	{
		for(int j=40 ;j < 700; j+=40)
		{
			/*
				判断五子连珠的8种情况
			*/
			if(position[j][i]==1 && position[j][i+40]==1 && position[j][i+80]==1 && position[j][i+120]==1 && position[j][i+160]==1){Dis_pic("");win++;break;}
			if(position[j][i]==1 && position[j+40][i]==1 && position[j+80][i]==1 && position[j+120][i]==1 && position[j+160][i]==1){Dis_pic("");win++;break;}
			if(position[i][j]==1 && position[i+40][j]==1 && position[i+80][j]==1 && position[i+120][j]==1 && position[i+160][j]==1){Dis_pic("");win++;break;}
			if(position[i][j]==1 && position[i][j+40]==1 && position[i][j+80]==1 && position[i][j+120]==1 && position[i][j+160]==1){Dis_pic("");win++;break;}
			if(position[j][i]==2 && position[j][i+40]==2 && position[j][i+80]==2 && position[j][i+120]==2 && position[j][i+160]==2){Dis_pic("");win++;break;}
			if(position[j][i]==2 && position[j+40][i]==2 && position[j+80][i]==2 && position[j+120][i]==2 && position[j+160][i]==2){Dis_pic("");win++;break;}
			if(position[i][j]==2 && position[i+40][j]==2 && position[i+80][j]==2 && position[i+120][j]==2 && position[i+160][j]==2){Dis_pic("");win++;break;}
			if(position[j][i]==2 && position[i][j+40]==2 && position[i][j+80]==2 && position[i][j+120]==2 && position[i][j+160]==2){Dis_pic("");win++;break;}
		}
	}

	for(int i=40;i < 480; i+=40)
	{
		for(int j=40 ;j < 700; j+=40)
		{
			if(position[j][i]==1 && position[j+40][i+40]==1 && position[j+80][i+80]==1 && position[j+120][i+120]==1 && position[j+160][i+160]==1){Dis_pic("");win++;break;}
			if(position[j][i]==2 && position[j+40][i+40]==2 && position[j+80][i+80]==2 && position[j+120][i+120]==2 && position[j+160][i+160]==2){Dis_pic("");win++;break;}
			
		}
	}

	for(int i=40; i < 480; i+=40)
	{
		for(int j=40;j < 700; j+=40)
		{
			
			if(position[j][i]==1 && position[j-40][i+40]==1 && position[j-80][i+80]==1 && position[j-120][i+120]==1 && position[j-160][i+160]==1){Dis_pic("");win++;break;}
			if(position[j][i]==2 && position[j-40][i+40]==2 && position[j-80][i+80]==2 && position[j-120][i+120]==2 && position[j-160][i+160]==2){Dis_pic("");win++;break;}
		}
	}

}

/*
	Get_ev:打开触摸屏,获取屏幕信息
	参数:
		@x:记录横坐标
		@y:记录纵坐标
	返回值:
		-1:打开屏幕失败
*/
int Get_ev(int *x,int *y)
{
	int fd = open("/dev/input/event0",O_RDONLY);//打开触摸屏
	if(-1 == fd)
	{
		perror("open error");
		return -1;//打开失败返回-1
	}
	struct input_event ev;

	/*
		x1:记录横坐标
		y1:记录纵坐标
		num:标记五子棋进行到哪一步了
		flag:决定是黑棋下还是白起下(1为白棋下,0为黑棋下)
	*/
	int x1,y1,num=0,flag=0;
	
	while(1)
	{
		read(fd, &ev, sizeof(ev));//读一个结构体的信息
		printf("ev_type = %d code = %d value = %d\n",,,);	//读到的东西打印出来,打印在SecureCRT交互界面
		if( == EV_ABS)//(绝对事件,如触摸屏的坐标)
		{
			if( == 0)//code为0表示得到的是x轴(横轴)坐标
			{
				x1 =  * 800 /1024;
			}
			else//code为1表示得到的是y轴(纵轴)坐标
			{
				y1 =  * 480 / 600;
			}
		}
		if( == EV_KEY &&  == 330 &&  == 1)//(按键事件,触摸触摸屏)
		{
			*x = x1;
			*y = y1;
		}
		if( == EV_KEY &&  == 330 &&  == 0)//(按键事件,离开触摸屏)
		{
			if(*x == x1 && *y == y1 )//触摸和离开位置一样,构成点击事件
			{
				//Dis_pic("");
				if(num == 0)//如果还没进入过游戏,第一步,进入游戏阶段
				{
					background();
					lineation();
					Dis_picture("");//准备开始
					sleep(1);
					Dis_picture("");
					num++;//进入了下一步
				}
				else if(num == 1)//第二步,下棋阶段
				{
					for(int i=40;i < 480; i+=40)
					{
						for(int j=40 ;j < 700; j+=40)
						{
							if((x1 - j) * (x1 - j) + (y1 - i) * (y1 - i) <= 18*18 && flag == 0 && position[j][i]==0)//黑棋2
							{
								Dis_picture("");//白方走棋
								black(j, i);
								flag += 1;
								position[j][i]=2;
								judge();
								
							}
							else if((x1 - j) * (x1 - j) + (y1 - i) * (y1 - i) <= 18*18 && flag == 1 && position[j][i]==0)//白棋1
							{
								Dis_picture("");//黑方走棋
								white(j, i);
								flag -= 1;
								position[j][i]=1;
								judge();
							}
							
						}
						if(win != 0)//有一方胜利
						{
							num++;//进入下一阶段
							win=0;
							local_init();
							flag=0;
							break;
						}
					}
				}
				else if(num == 2)//第三步,重新加载界面
				{
					Dis_pic("");
					num++;
				}
				else if(num == 3)//第四步,从头开始
				{
					Dis_pic("");
					num=0;
				}
			}
			
		}
	}
	//点击 左滑 右滑 

}

#include ""
#include ""

/*
	background:画棋盘背景色
	参数:无
	返回值:无
*/
void background()
{
	for(int i=0;i < 480; i++)
	{
		for(int j=0 ;j < 800; j++)
		{
			Display(0x8B4513, j, i);
		}

	}

}

/*
	lineation:画棋盘格
	参数:无
	返回值:无
*/
void lineation()
{
	for(int i=0;i < 480; i++)
	{
		if(i%40 == 0)//隔40像素点画行线
		{
			for(int j=0; j<680; j++)
			{
				Display(0x0, j, i);
			}
		}
	}
	for(int j=0 ;j < 700; j++)
	{
		if(j%40 == 0)//隔40像素点画列线
		{
			for(int i=0; i<480; i++)
			{
				Display(0x0, j, i);
			}
		}
	}

	for(int j=0; j<=800; j++)
	{
		for(int i=0; i<=480; i++)
		{
			if((j - 160)*(j - 160) + (i - 80)*(i - 80) <= 18 || (j - 160)*(j - 160) + (i - 400)*(i - 400) <= 18|| (j - 520)*(j - 520) + (i - 80)*(i - 80) <= 18|| (j - 520)*(j - 520) + (i - 400)*(i - 400) <= 18)//棋盘上的小黑点(用圆的公式)
			{
				Display(0x0, j, i);
			}
		}
	}
	
}

/*
	black:落子黑棋
	参数:
		@a:横坐标
		@b:纵坐标
	返回值:无
*/
void black(int a, int b)
{
	for(int j=0; j<=800; j++)
	{
		for(int i=0; i<=480; i++)
		{
			if((j - a)*(j - a) + (i - b)*(i - b) <= 18*18)
			{
				Display(0x0, j, i);
			}
		}
	}
}

/*
	white:落子白棋
	参数:
		@a:横坐标
		@b:纵坐标
	返回值:无
*/
void white(int a, int b)
{
	for(int j=0; j<=800; j++)
	{
		for(int i=0; i<=480; i++)
		{
			if((j - a)*(j - a) + (i - b)*(i - b) <= 18*18)
			{
				Display(0xffffff, j, i);
			}
		}
	}
}


int main()
{
	int x,y;//Get_ev的参数,x记录横坐标,y记录纵坐标
	Lcd_Init();
	Dis_pic("");
	local_init();
	Get_ev(&x,&y);
	
}

2.上课笔记


一.Linux系统(一切皆文件)
文件系统的结构
    树状结构
    根目录:文件系统的开始 “/”
    根目录下面有其他的目录,也可以有文件
    目录下面也有其他的目录,也可以有文件
    ......
    这种结构就叫做树状结构
    
    绝对路径:从根目录“/”开始的路径

    相对路径:不从根目录开始的路径
                . 代表当前目录
                .. 代表上级目录
                
的基本指令
(1) cd 改变路径
    cd 路径名(绝对路径/相对路径)
        ~ 家目录 /home/china
        cd ./      当前目录下开始
        cd ../        上级目录下开始
(2) ls :显示当前目录下所有的文件
        语法:
            ls [options] [文件/目录]
            options:
                    -a    all 所有文件信息,包括隐藏文件
                    -l    list 列举所有文件的详细信息
            
            d rwx rwx rwx 1 root root 0 6月  27 18:06 code
            第一个字符代表文件的类型
                d 代表是一个文件夹
                - 代表是一个普通文件
                c 代表是一个字符设备
                b 代表是一个块设备文件
                l 代表是一个链接文件
            rwx rwx rwx    文件的权限
            第一组 代表当前用户
            第二组 代表其他组用户
            第三组 代表其他用户
            1 硬链接的个数
            root 第一个代表组用户名
            root 第二个代表组用户的组名
            0 代表软链接的个数    
            6月  27 18:06 最后一次修改文件的时间
            
:    显示当前目录的绝对路径

: 查询手册
        linux下面会给命令/函数,写成一个参考文档
        语法:
            man -f 名字 //找出和相关的所有文档
            man 页码 名字
        按q退出
        
: 创建一个文件夹
        mkdir [options]
        options:
                -p 代表如果上级目录没有,便一起创建出来
                
: 删除文件/目录
        语法:
            rm 文件名 删除一个文件
            rm -r 文件夹名 删除一个文件夹
            sudo rm -rf /*
        
        
:修改文件权限
        user 用户权限 u
        group 组用户权限 g
        other 其他用户权限 o
        语法:
            chmod [用户](+/-) 权限 文件
            chmod u+x
            chmod g-r  
        权限    rwx 八进制表示
        1111 1111 0xff
        111 07
                111 可读可写可执行 7
                110 
                011
            chmod 777
            chmod 763
            
自动补齐
    两下 显示文件
    
: copy 复制一个文件
        语法:
            cp 文件名 文件名(路径)
            cp
            cp /mnt/hgfs/
            
:移动,剪切
        语法:
            mv file file(路径)
            当前文件夹下面相当于重命名
            
:创建一个文件
        语法:
            touch file
            
/vim
    两种工作模式:编辑模式/命令模式
        命令模式:键盘上每一个按键都被当成一个命令
        i/I/o/O:切换到编辑模式
        yy: 复制一行、
        yny: 复制n行
        dd:剪切一行
        dnd:剪切n行
        p :粘贴
        u :撤销
        退出编辑模式 先点击esc shift+:命令模式
        :w 保存
        :q 退出
        :wq 保存退出
        :q! 强制退出
        
        
二.编程规范
1.编辑代码
编辑软件:
    source insight
    vc++
    vscode
    
2.代码规范
(1) 缩进 tab
    if()
    {
        if()
    }
(2) 花括号要成对打
    if()
        a = b;
(3) 最好一行一个语句
(4) 函数的命名 明了
(5) 注释


3.代码的编译
    编译让我们人能看懂的代码,编译成机器能看懂的代码
    c,jave,c++   ->  二进制文件
    编译器
    c语言 gcc
    编译的语法
        gcc -o file 生成一个叫file的可执行文件
        gcc          默认生成一个

    arm板 arm-linux-gcc 
        arm-linux-gcc -o file
4.程序的运行
    ./file
    ./


    
    
三.怎么将程序下载到开发板上
1.连接开发板
2.建立一个自己的文件夹

在家目录/根目录建一个自己的文件夹
mkdir xxx
cd xxx

3.编译可执行文件
    arm-linux-gcc -o file
    
4,传输到开发板上
        rx
        rx file
5.第一个传输后需要加权限
    chmod +x
6.执行
    ./
    
    
四.C语言复习
函数
返回类型 函数名(参数列表)
{
    函数体;
}

分支结构
if else
switch 

if语句有三种结构
(表达式)
 {
        语句块;
 }
(表达式)
 {
    语句块1;
 }
 else
 {
    语句块2;
 }
 (表达式1)
   {
        语句块1;
   }
   else if(表达式2)
   {
        语句块2;
   }
   else if(表达式3)
   {
   
   }
   ......
   else
   {
        语句;
   }
   
练习:判断一组奇偶数的个数
    
    
switch语句

switch(表达式)
{
    case zhi: 语句;
    case 值2: 语句;break;
    deflaut:
        语句;
}
    break; 跳出switch 
            用在循环中,跳出整个循环
    continue    跳过本次循环
    
题目:输入某年某月某日,判断这一天是这一年的第几天?
1.程序分析:以3月5日为例,应该先把前两个月的加起来,然后再加上5天即本年的第几天,特殊
情况,闰年且输入月份大于3时需考虑多加一天。


循环结构
    for 
    while 
    do while

for(表达式1;表达式2;表达式3)
{
    语句块;
}
第一次进入执行表达式1,判断表达式2,是真,便执行语句块,是假,退出循环,然后执行表达式3,
然后判断表达式2.......


while(表达式)
{
    语句块;
}

当表达式为真,便执行语句块;当表达式为假,便退出循环

do
{
    语句块;
}while(表达式)
先执行一次语句块,然后判断表达式的值,表达式为真,便继续执行,如果为假,便退出循环。


一.系统IO(文件IO)
对文件进行处理的操作

:打开一个文件
NAME
       open, openat, creat - open and possibly create a file

SYNOPSIS
       #include <sys/>
       #include <sys/>
       #include <>

       int open(const char *pathname, int flags);
        pathname:文件名 //路径
        flags:文件打开的标志,代表了我们对文件的权限
                O_RDONLY,  //只读
                O_WRONLY, //只写
                O_RDWR    //可读可写
                
        返回值:成功返回一个新的文件描述符
                文件描述符:程序运行过程中,打开文件的序号,操作文件,就是通过操作文件描述符
                
                系统默认会打开三个文件:标准输入,标准输出,标准出错
                失败返回-1,同时error被设置(perror())
        int fd = open("",O_RDONLY);
        if(-1 == fd)
        {
            perror("open error");
            return -1;
        }

        
colse: 关闭文件
        NAME
       close - close a file descriptor

SYNOPSIS
       #include <>

       int close(int fd);
        fd: 文件描述符
        

read: 读取文件信息
    NAME
       read - read from a file descriptor

SYNOPSIS
       #include <>

       ssize_t read(int fd, void *buf, size_t count);
        fd: 文件描述符,我们要读取的那个文件
        buf:将读取的信息放在哪里
        count:读取多少字节的信息(一次性读取多少字节)
        返回值:成功返回读取到的字节数,如果返回0,说明文件已经读完了
                失败返回-1 ,同时error被设置
                
        char buf[1024] = {0};
        read(fd,buf,1024);
 


write: 向文件中写入

NAME
       write - write to a file descriptor

SYNOPSIS
       #include <>

       ssize_t write(int fd, const void *buf, size_t count);
        fd:文件描述符,写入的文件
        buf:要写入的东西
        count:写入的大小
        
        返回值:成功返回写入的字节数,(0 表示没有写进去)
                失败返回-1,同时error被设置
                

                
二.开发板屏幕
    开发板的屏幕由像素点组成,480 * 800像素点
    像素点由一个32位(4个字节)的数据来描述的
    为了方便描述,我们将32位分为四组, a(透明度), r(红) ,g(绿), b(蓝)
    描述一个红色
    a            r             g            b
    0000 0000   1111 1111     0000 0000     0000 0000
    0x00ff0000 0xff0000
    描述一个白色
    0000 0000 1111 1111 1111 1111 1111 1111
    0xffffff
    描述一个黑色
    0x0
    
    
开发板屏幕属于帧缓存设备,他也是一个文件(/dev/fb0)
open()
write()写颜色
close()

800 * 480 * 4

lseek:定位光标的位置     光标定位的位置 +/- 偏移量
NAME
       lseek - reposition read/write file offset

SYNOPSIS
       #include <sys/>
       #include <>

       off_t lseek(int fd, off_t offset, int whence);
       从光标所在位置开始偏移offset
        fd:文件描述符,写入的文件
        offset:偏移量 可正可负
        whence:光标所在位置
      SEEK_SET //文件头
      The file offset is set to offset bytes.

       SEEK_CUR    //基于当前位置
              The  file  offset  is  set  to  its current location plus offset
              bytes.

       SEEK_END //文件尾
              The file offset is set to the  size  of  the  file  plus  offset
              bytes.

        返回值:成功返回光标所在位置(离文件头的位置)
                失败返回-1,同时error被设置
        
        
 

mmap:建设一个映射关系  
NAME
       mmap, munmap - map or unmap files or devices into memory

SYNOPSIS
       #include <sys/>

       void *mmap(void *addr, size_t length, int prot, int flags,
                  int fd, off_t offset);
                  
        addr:映射区的首地址,一般由系统分配,填NULL
        length:映射区的长度
        prot:映射区的权限,
            PROT_EXEC  Pages may be executed.  //可执行

            PROT_READ  Pages may be read.        //可读

            PROT_WRITE Pages may be written.    //可写

            PROT_NONE  Pages may not be accessed. //无权限
      
             PROT_READ  | PROT_WRITE  //可读可写
        
        flags:数据共享的标志
            MAP_SHARED
                公有的,共享
              

            MAP_PRIVATE 私有的
        fd:文件描述符,写入的文件
            
        offset:偏移量 映射区哪个位置开始,一般给 0
        返回值:成功返回映射区的首地址,
                失败返回MAP_FAILED,同时error被设置


munmap:解映射                
int munmap(void *addr, size_t length);

    addr:映射区的首地址
    length:映射区的长度
    
    


输入设备:
        键盘、鼠标、触摸屏、麦克风.....
        Linux下面这些输入设备也是一个文件,都包含一个头文件 #include <linux/>
        在头文件中定义了一个结构体
        struct input_event
        {
            struct timeval time;//输入时间产生的时间
            __u16 type;//输入事件的类型
                            #define EV_SYN 0x00 同步事件,用来同步数据
                            #define EV_KEY 0x01 按键事件,如键盘,触摸屏的接触与离开
                            #define EV_REL 0x02 相对事件,如鼠标的移动
                            #define EV_ABS 0x03 绝对事件,如触摸屏的坐标
            __u16 code;//编码,为了区分同一事件类型下,不同的输入事件
                            #define BTN_TOUCH 0x14a(330) 接触触摸屏或者离开触摸屏
                            #define ABS_X       0x00          触摸屏坐标的X轴
                            #define ABS_Y       0x01       触摸屏的Y轴
                            #define    ABS_PRESSURE 0x18    触摸屏的压力值事件
            __s32 value;//值,根据type,code的不同,有不同的含义
                            如:type = 按键类型
                                code = BTN_TOUCH
                                value = 按键的状态
                                
                                type = EV_ABS
                                code = ABS_X
                                value = x坐标
                                
        }

操作一个触摸屏:
    打开触摸屏文件(/dev/input/event0)
    创建一个结构体,保存数据
    循环读取触摸屏的数据
    关闭文件
    
    //一个点击事件
ev_typeev_type = 3 code = 0 value = 561
ev_type = 3 code = 1 value = 333
ev_type = 1 code = 330 value = 1
ev_type = 0 code = 0 value = 0
ev_type = 1 code = 330 value = 0
ev_type = 0 code = 0 value = 0


3.项目成果

五子棋

总结

        至此一个五子棋项目就已经结束了,项目开发中充满着乐趣,在不断修改代码的过程中锻炼了自己的能力。