嵌入式6818开发板小游戏——五子棋

一、部分基础知识

1、操作6818开发板的一些基础理论

    1) LCD 屏幕原理

        在linux下面,万物皆文件,所以操作LCD屏幕,也就是

        操作LCD对应的文件

            **开发板LCD的文件名: /dev/fb0**

    开发板屏幕的分辨率为:800*480

            表示开发板由480行像素点,每一行有800个像素点组成

    什么是像素点?

            像素点就是能够显示某种颜色的点

            在屏幕上去显示图像,其实就是给对应的像素点赋一个相应的颜色即可

    颜色怎么保存的?

            计算机的三原色: 红(red) 蓝(blue) 绿(green),每种基色占1个字节,

            给基色的每一位赋不一样的值,就表现出不同的颜色

                将颜色值进行了量化处理(数量化)

                    red;0~255

                    blue:0~255

                    green:0~255

    问: 三种基色可以表示多少种颜色?

                    2^8 * 2^8 * 2^ 8 = 2^24  ~ 1600万

    2)LCD 像素点组成

        LCD 上,每个像素点都是由 ARGB组成,其中,A代表透明度(为0代表没有)

        一个像素点占4字节

            发现: LCD上一个像素点占4字节,我们可以用一个int 型的变量来存储一个像素点

    常见的一些颜色举例:

                红色:  int color = 0x00FF0000 = 0xff0000

                蓝色:            = 0x000000FF = 0XFF

                绿色:            = 0x0000FF00 = 0XFF00

                ....

    3)操作LCD显示屏

        //1.打开LCD显示屏文件

        //2.写入像素点信息

        //3.关闭文件

2、解决write函数效率问题

     ===> mmap函数(虚拟进程地址空间映射)

        SYNOPSIS

       #include <sys/mman.h>

       void *mmap(void *addr, size_t length, int prot, int flags,

                  int fd, off_t offset);

            参数列表:

                @addr:

                    指定虚拟映射空间的起始地址,一般让系统自己指定,填 NULL

                @length:

                    要映射区域的大小(单位:字节),800*480*4

                @prot:

                    映射的权限,一般跟打开文件的权限一样:

                        PROT_READ

                        PROT_WRITE

                        PROT_EXEC

                        要操作虚拟进程地址空间,必须要有可写的权限,那如果你需要多个权限,如:

                        PROT_READ | PROT_WRITE

                @flags:

                    映射标志,映射方式,有如下两种:

                        MAP_SHARED :共享映射,你对映射区域的操作,会立即反馈到文件或内核中

                        MAP_PRIVATE:私有映射,你对映射区域的操作,仅你自己可见

                @fd:

                    文件描述符,open函数的返回值

                @offset:

                    偏移量,表示你想要从文件的哪个位置开始映射,一般来说置0,表示不偏移

                        如果你想要指定偏移量,必须是4K的整数倍字节大小

            返回值:  

                成功返回虚拟映射进程空间的首地址,失败返回NULL,并且errno会设置

       int munmap(void *addr, size_t length);

            函数功能:

                解除虚拟映射

   

            参数列表:

                @addr:需要解除映射的空间首地址,mmap函数的返回值

                @length:要解除映射区域的大小 :800*480*4

#include"lcd.h"
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<string.h>
#include <stdlib.h>
#include <sys/mman.h>
/*
初始化LCD,开启映射
*/
void LCD_init(void)
{
    fd=open(LCD_path,O_RDWR);
    perror("");

    plcd=mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);//打开映射
    perror("");
   
   
}

/*
关闭LCD文件,关闭映射
*/
void LCD_free(void)
{
    close(fd);
    munmap(plcd,800*480*4);

}

/*
    给LCD开发板画颜色
    @fd:文件描述符
    @color:颜色
*/

void draw_color(int color)
{

    for(int i=0;i<480;i++)
    {
        for(int j=0;j<800;j++)
        {        
            *(plcd+800*i+j) = color;
        }
    }
   
}

//画点函数
//@x:画点的横坐标,对应LCD的列
//@y:画点的纵坐标,对应LCD的行
void LCD_draw_print(int x,int y,int color)
{
    if(x>=0&&x<800&&y>=0&&y<480)
    *(plcd+800*y+x)=color; 
    
   
}

3、获取屏幕信息

    像手指的点击、滑动、键盘的输入、鼠标的移动、点击....统称为 输入事件

        每次产生一个输入事件,都会保存到开发板的: /dev/input/event0 这个文件中

    /dev/input/event0这个文件中的所有内容都是以一个结构体保存的:

        头文件 : <linux/input.h>

        struct input_event

        {

            struct timeval time;

            _u16 type;//保存事件的类型,由宏定义定义:

                EV_KEY   按键事件

                EV_REL   鼠标点击事件

                EV_ABS   触摸事件

            _u16 code;//对事件的进一步描述,具体由type决定

                if(type == EV_KEY) --> code == 按键的键值

                if(type == EV_REL) --> code == 鼠标点击的坐标(REL_X 或 REL_Y)

                if(type == EV_ABS) --> code == 触摸点的绝对坐标(ABS_X 或 ABS_Y)

            _u32 value;//事件的值,对于事件的再进一步描述,具体由type决定

                if(type == EV_KEY) // value == 0 代表松开 ,value == 1 代表按下

                if(type == EV_REL) // value == 鼠标点击的横坐标 或 纵坐标

                重点:   我要获取触摸点的横坐标:if(type == EV_ABS && code == ABS_X) -->value 就是横坐标的值

                        我要获取触摸点的纵坐标: if(type == EV_ABS && code == ABS_Y) -->value 就是纵坐标的值

        };

#include "touch.h"
#include<linux/input.h>
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int x_start=-1,y_satart=-1;
int x_end=-1,y_end=-1;
/*
获取触摸屏坐标
*/
void get_touch()
{
    //1.打开文件
    int fd=open(TOUCH_PATH,O_RDONLY);
    perror("");
    //2.解析文件
        //2.1定义结构体变量,接收信息
        struct input_event ev;
        //2.2读文件信息
        while(1)
        {
            int ret=read(fd,&ev,sizeof(ev));
            //如果读的内容不完整,就跳过
            if(ret!=sizeof(ev))
            {
                continue;
            }
            //2.3解析内容      
              //2.3.1先读x的坐标
                if(ev.type==EV_ABS&&ev.code==ABS_X)//触摸事件
                {
                    if(x_start==-1)
                    x_start=ev.value;
                    x_end=ev.value;
                }
                    //2.3.2再读y的坐标
                if(ev.type==EV_ABS&&ev.code==ABS_Y)
                {
                    if(y_satart==-1)
                y_satart=ev.value;
                    y_end=ev.value;
                }
            if(ev.type==EV_KEY && ev.code==BTN_TOUCH && ev.value==0) //按键事件 ,按键松开
            {
                printf("start:<%d,%d>\n",x_start,y_satart);
                printf("end:<%d,%d>\n",x_end,y_end);
                x_start=-1,y_satart=-1;
                //break;
            }
        }
       
    
    //关闭文件
    close(fd);
}

//获取滑动方向
int get_dirction(void)
{
    //1.打开文件
    int fd=open(TOUCH_PATH,O_RDONLY);
    perror("");
    //2.解析文件
        //2.1定义结构体变量,接收信息
        struct input_event ev;
        //2.2读文件信息
        while(1)
        {
            int ret=read(fd,&ev,sizeof(ev));
            //如果读的内容不完整,就跳过
            if(ret!=sizeof(ev))
            {
                continue;
            }
            //2.3解析内容      
              //2.3.1先读x的坐标
            if(ev.type==EV_ABS&&ev.code==ABS_X)//触摸事件
            {
                if(x_start==-1)
                {
                    x_start=ev.value;
                }
                
                x_end=ev.value;
            }
                //2.3.2再读y的坐标
            if(ev.type==EV_ABS&&ev.code==ABS_Y)
            {
                if(y_satart==-1)
                {
                    y_satart=ev.value;
                }    
                y_end=ev.value;
            }
            if(ev.type==EV_KEY && ev.code==BTN_TOUCH && ev.value==0) //按键事件,按键松开
            {
                //按键松开是终止坐标
                printf("start:<%d,%d>\n",x_start,y_satart);
                printf("end:<%d,%d>\n",x_end,y_end);
                
                //确定滑动方向
                int x=abs(x_end-x_start);
                int y=abs(y_end-y_satart);
                //横向移动
                if(x>y)
                {
                    if(x_end-x_start>0)//向右
                    {
                        
                        close(fd);
                        return RIGHT;
                    }
                    else//向左
                    {
                       
                        close(fd);
                        return LEFT;
                    }
                }
                else if(x<y)
                {
                    if(y_end-y_satart>0)//向下
                    {
                       
                        close(fd);
                        return DOWN;
                    }
                    else//向上
                    {
                        close(fd);
                        return UP;
                    }
                }
                else
                {
                    //无效滑动
                    continue;
                }
                
            }
        }

}

4、获取一个随机数

    rand

    SYNOPSIS

       #include <stdlib.h>

       int rand(void);

            函数功能:

                产生一个随机数返回

            实现:

                需要系统提供一个随机数因子,用来产生随机数,电脑开机之后,默认随机数因子是固定的

                这个时候你获取到的随机数是一个“伪随机数”,为了解决这个 ---> srand()来提供一个随机数因子

       void srand(unsigned int seed);

            函数功能:

                根据参数来生成一个随机数因子,如果默认参数,那么srand()函数只会默认产生一个1的随机因子

                也达不到效果,所以,想到以系统时间作为参数,那么获取到的因子也会随时间的变化而变化 --> time(NULL)来获取时间

        获取随机数步骤:

            1> 获取随机数因子

                srand(time(NULL));

            2> 生成随机数

                int ret = rand();

5、BMP图片显示

    1.读取图片的像素点信息

    2.写入到LCD文件中

    1>读取图片信息

        BMP图片的组成:

            BITMAP文件头

            DIB头

            调色板

            像素数组

        BMP图片的像素组成:

            BGRA -----》需要转换成 ARGB的数据(位操作)

                ==》 A << 24 | R << 16 | G << 8 | B

```


 

注:图片像素不能超过 800*480 !!!

显示图片之前,先确定两点:

    1) 你的图片是bmp图片

    2)图片像素合格

 BMP图片格式

#include"bmp.h"
#include"lcd.h"
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include<linux/input.h>
/*
    显示图片内容
    @x:图片的显示起始横坐标
    @y:图片的显示起始纵坐标
    @pathname:要显示的图片的路径名

*/

void show_bmp(int x,int y,const char* pathname)
{
    //1.读取图片的像素点信息
        //1.1打开图片
        int fd=open(pathname,O_RDONLY);
        perror("open_bmp:");
        //1.2计算图片的大小
        //1.2.1读取图片的宽度,高度,色深
        int width;//保存宽度
        int heigh;//保存高度
        short depth;//色深

        /*图片信息以小端模式保存,读取后需要用位运算偏移的到正确结果*/
        //读取宽度
        unsigned char buf[4]={0};//保存图片的信息
        lseek(fd,0x12,SEEK_SET);//从头开始偏移0x12个字节到宽度地址
        read(fd,buf,4);
        width=buf[3]<<24|buf[2]<<16|buf[1]<<8|buf[0];

        //读取高度,因为宽度后面的地址就是高度,地址连续可以不用手动偏移
        read(fd,buf,4);
        heigh=buf[3]<<24|buf[2]<<16|buf[1]<<8|buf[0];

        //读色深
        lseek(fd,0x2,SEEK_CUR);//以当前位置偏移两个字节到色深的地址
        read(fd,buf,2);
        depth=buf[1]<<8|buf[0];
printf("wigth:%d,heigh:%d,depth:%d\n",width,heigh,depth);
        //1.2.2计算图片的一行字节大小,判断是否需要填充
        int line_size=abs(width)*depth/8;
        int laizi=0;//填充
        if(line_size%4)//要把图片字节长度填充位4的倍数
        {
            laizi=4-line_size%4;
        }
        //1.2.3计算图片一行的最终大小
        int line_r_size=line_size+laizi;
        //1.2.4图片的最终大小
        int bmp_size=line_r_size*abs(heigh);

        //1.3读取图片的像素信息
        lseek(fd,0x36,SEEK_SET);//偏移0x36个字节到像素数组
        char* p=malloc(bmp_size);//动态分配空间,保存图片的像素信息
        read(fd,p,bmp_size);

    //2.将图片信息写入到LCD文件
    //图片里的像素点保存方式:BGRA -------在开发板中位ARGB
        //2.1提取出每一个像素点的实际数据
        int color;//保存像素点的信息
        unsigned char a,r,g,b;
        int m=0;//遍历动态空间
        for(int i=0;i<abs(heigh);i++)//遍历行
        {
            for(int j=0;j<abs(width);j++)//遍历列
            {
                b=p[m++];
                g=p[m++];
                r=p[m++];
                if(depth==32)//色深位32则表示有透明度
                {
                    a=p[m++];
                }
                else
                {
                    a=0;
                }
                color=a<<24|r<<16|g<<8|b;//一个像素点实际写入LCD的内容
                LCD_draw_print(width>0?j+x:abs(width)-1-j+x,
                heigh>0?abs(heigh)-1-i+y:y+i,color);
               
            }
            m=m+laizi;
        }
        //3.关闭图片
    close(fd);
}

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值