Day8_ElectronicAlbum

[TOC]

实验要求

  1. 分别实现5个按钮:上一张下一张,随机播放,循环播放,停止循环播放
  2. 在屏幕里选择一块区域显示图片,该区域同时也可以使用滑动.

代码实现

lcd.h

#ifndef LCD_H
#define LCD_H

/*函数声明*/
int *Init_LCD(int *fd);
void Uninit_LCD(int fd,int *plcd);
void Lcd_draw_point(int x,int y,int color,int *plcd);
void Lcd_draw_matrx(int x,int y,int h,int w,int color,int *plcd);
int Bmp_display(const char *bmp_file,int x0,int y0,int *plcd);

#endif

lcd.c

/*头文件*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>

/*宏定义*/
#define FILE_PATH "/dev/fb0"

/*
	Init_LCD:初始化显示屏
	参数为空
	返回值 int*
		成功 返回映射区域的首地址
		失败 返回NULL
*/
int *Init_LCD(int *fd)
{
	//1.打开帧缓冲
	*fd = open("/dev/fb0",O_RDWR);
	if(-1 == *fd)
	{

		perror("open fail");
		return NULL;
	}
	//2.映射
	int *plcd = mmap(NULL,800*480*4
			,PROT_READ |  PROT_WRITE,
			MAP_SHARED,*fd,0);
	if(MAP_FAILED == plcd)
	{
		perror("mmap fail");
		return NULL;
	}
	return plcd;
}

/*
	Uninit_LCD:解初始化屏幕
	@fd:帧缓冲的文件描述符
	@plcd:
	返回值:无
*/
void Uninit_LCD(int fd,int *plcd)
{
	//1.解映射
	munmap(plcd,800*480*4);
	//2.关闭帧缓冲
	close(fd);
}

void Lcd_draw_point(int x,int y,int color,int *plcd)
{
    if(NULL == plcd)
    {
        printf("error:plcd == NULL\n");
        return ;
    }
    if(x>=0&&x<800&&y>=0&&y<480)
    {
   		*(plcd+800*y+x) = color;
	}
}
void Lcd_draw_matrx(int x,int y,int h,int w,int color,int *plcd)
{
	int i,j;
	if((x+w)>=0||(x+w)<=880||(y+h)>=0||(y+h)<=880)
		for(j=x;j<x+w;j++)
		{
			for(i=y;i<y+h;i++)
			{
				Lcd_draw_point(i,j,color,plcd);
			}
		}
}

/*
	Bmp_display:在屏幕的指定的位置显示bmp图片
	@bmp_file:图片的路径名
	@x0 y0 图片左上角在屏幕上的坐标
	@plcd:帧缓冲映射区域的首地址
	返回值:
		-1 失败
		0  成功
*/
int Bmp_display(const char *bmp_file,int x0,int y0,int *plcd)
{
	if(plcd == NULL || !(x0>=0&&x0<800&&y0>=0&&y0<480))
	{
		return -1;
	}
	//1.打开图片
	int fd = open(bmp_file,O_RDONLY);
	if(-1 == fd)
	{
		printf("%s",bmp_file);
		perror("open fail");
		return -1;
	}
	//2.判断到底是不是一张bmp图片
	char buf[4]={0};
	read(fd,buf,2);
	if(buf[0]!=0x42 || buf[1]!=0x4D)
	{
		printf("NOT BMP\n");
		close(fd);
		return -1;
	}
	//3.解析图片 宽 高 色深
	lseek(fd,0x12,SEEK_SET);
	read(fd,buf,4);
	int width = buf[3]<<24 | buf[2]<<16 | buf[1]<<8 | buf[0];

	lseek(fd,0x16,SEEK_SET);
	read(fd,buf,4);
	int height = buf[3]<<24 | buf[2]<<16 | buf[1]<<8 | buf[0];

	lseek(fd,0x1c,SEEK_SET);
	read(fd,buf,2);
	short depth = buf[1]<<8 | buf[0];

	if(!(depth == 24 || depth == 32))
	{
		printf("NOT SUPPORT!\n");
		close(fd);
		return -1;
	}

	printf("%s:%d*%d depth:%d\n",bmp_file,width,height,depth);
	//4.获取像素数组
	int line_vaild_bytes=abs(width)*depth/8;
	int line_bytes;//一行总字节数=有效字节数+赖子数
	int laizi = 0;

	if(line_vaild_bytes%4)
	{
		laizi = 4 - line_vaild_bytes%4;
	}
	line_bytes = line_vaild_bytes + laizi;
	int total_bytes = line_bytes*abs(height);//整个像素数组的大小

	//从文件中读取像素数组
	lseek(fd,54,SEEK_SET);
	unsigned char piexl[total_bytes];
	read(fd,piexl,total_bytes);
	//5.在屏幕的对应位置显示即可
	unsigned char a,r,g,b;
	int color;
	int i=0;
	int x,y;
	//遍历整个像素数组
	for(y=0;y<abs(height);y++)
	{
  		for(x=0;x<abs(width);x++)
  		{
			b=piexl[i++];
			g=piexl[i++];
			r=piexl[i++];
    		if(depth==32)
			{
				a=piexl[i++];
			}
    		else
			{
				a=0;//不透明
			}
    		color=a<<24|r<<16|g<<8|b;
    		Lcd_draw_point(width>0?x+x0:x0+abs(width)-x-1,
          	height>0?y0+abs(height)-y-1:y0+y,color,plcd);
		}
  		//每一行末尾可能存在赖子
  		i+=laizi;
	}
	close(fd);
	return 0;
}

touch.h

#ifndef __TOUCH_H__
#define __TOUCH_H__


/*头文件*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/input.h>//输入子系统

#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4
#define TOUCH_ERROR -1

/*宏定义*/
#define TOUCH_FILE "/dev/input/event0"

//获取坐标

int Init_touch(void);
void  Uninit_touch(int touch_fd);
int get_usr_input_pro(int touch_fd,int *x1,int *y1,int *x2,int *y2);
int Get_slip_direction(int x1,int y1,int x2 ,int y2);

void get_touch();


/*
    get_usr_touch: 获取用户触摸屏输入的坐标值
    @x :保存 x轴的坐标值
    @y :保存 y轴的坐标值
        返回值 :
*/
void get_usr_touch(int *x,int *y);

/*
    功能 : 获取方向返回
        返回值 :
        -1 失败
        UP 1
        DOWN 2
        LEFT 3
        RIGHT 4
*/
int getway();




#endif

touch.c

#include "touch.h"

/*
    触摸屏初始化:Init_touch
    参数为空
    返回值:int
        touch_fd:触摸屏的文件描述符
*/
int Init_touch(void)
{
    //1.打开触摸屏
    int touch_fd = open(TOUCH_FILE,O_RDONLY);
    if(-1 == touch_fd)
    {
        perror("open touch fail");
        return -1;
    }
    return touch_fd;
}

/*
    关闭触摸屏:Uninit_touch
    @touch_fd
    返回值:void
*/
void  Uninit_touch(int touch_fd)
{
    if(-1 == touch_fd)
    {
        return ;
    }
    close(touch_fd);
}

/*
    get_usr_input_pro:获取用户的对触摸屏的输入
    @x1 y1 
    @x2 y2
    @touch_fd
    返回值:int 
        -1  失败
        0   成功
*/
int  get_usr_input_pro(int touch_fd,int *x1,int *y1,int *x2,int *y2)
{
    if(-1 == touch_fd)
    {
        return -1;
    }
    struct input_event ev;//保存读取出来的信息
    *x1 = *y1 = *x2 =*y2 = -1;
    while(1)
    {
        //1 读取输入事件
        int res = read(touch_fd,&ev,sizeof(ev));
        if(res != sizeof(ev)) // 判断结构体数据不符合要求 重新读
        {
            continue;//跳过本次循环,执行下一次循环
        }

        //2.2 通过判断结构体里面的成员坐标值
        if(ev.type == EV_ABS && ev.code == ABS_X) //获取x轴的坐标
        {
            if(-1 == *x1)
            {
                *x1 = ev.value;  //只获取一次
                *x2 = ev.value;
            }
            *x2 = ev.value;         
        }

        if(ev.type == EV_ABS && ev.code == ABS_Y) //获取x轴的坐标
        {
            if(-1 == *y1)
            {
                *y1 = ev.value;  //只获取一次
                *y2 = ev.value;
            }
            *y2 = ev.value;
           
        }

        if(ev.type == EV_KEY && ev.code == BTN_TOUCH && ev.value == 0 ) //手指松开
        {
            break;//一次获取
        }
    }
    return 0;
}

/*  
    获取滑动的方向:Get_slip_direction
    @x1 y1 
    @x2 y2
    返回值:int
        LEFT RIGHT UP DOWN TOUCH_ERROR
*/
int Get_slip_direction(int x1,int y1,int x2 ,int y2)
{
    if(-1 == x1 || -1 == y1 || -1 == x2 || -1 == y2)
    {
        return TOUCH_ERROR;
    }
    int direction; //方向
    if(abs((y2-y1)/(x2-x1)) >= 1) //上 或者 下
    {
        if(y2 > y1)
        {
            return DOWN;
        }
        else
        {
            return UP;
        }
    }
    else
    {
        if(x2 > x1)
        {
            return RIGHT;
        }
        else
        {
            return LEFT;
        }
    }

}


//打印坐标  测试
void get_touch()
{
    //1.打开触摸屏
    int fd = open("/dev/input/event0",O_RDONLY);
    if(-1 == fd)
    {
        perror("open touch fail");
        return ;
    }
    //2.操作
    
    struct input_event ev;//保存读取出来的信息

    while(1)
    {
        read(fd,&ev,sizeof(ev));
        printf("type =%d,code=%d,value=%d\n",ev.type,ev.code,ev.value);

        int x ,y ;
        if(ev.type == EV_ABS && ev.code == ABS_X )//触摸屏的x轴
        {
            x = ev.value *(1.0*800/1040);
        }

        if(ev.type == EV_ABS && ev.code == ABS_Y )//触摸屏的y轴
        {
            y = ev.value*(1.0*480/600);
        }

        printf("( %d , %d )\n",x,y);

        if(ev.type == EV_KEY && ev.code == BTN_TOUCH && ev.value == 0 ) //手指松开
        {
            break;//一次获取
        }

        
    }

    //3.关闭
    close(fd);

}

/*
    get_usr_touch: 获取用户触摸屏输入的坐标值
    @x :保存 x轴的坐标值
    @y :保存 y轴的坐标值
        返回值 :
*/
void get_usr_touch(int *x,int *y)
{
    //1.打开触摸屏
    int fd = open("/dev/input/event0",O_RDONLY);
    if(-1 == fd)
    {
        perror("open touch fail");
        return ;
    }
    //2.操作
    
    struct input_event ev;//保存读取出来的信息

    while(1)
    {

      
        //2.1 读取输入事件
        int res = read(fd,&ev,sizeof(ev));
        int flag_x = 0, flag_y = 0;

        if(res != sizeof(ev)) // 判断结构体数据不符合要求 重新读
        {
            continue;//跳过本次循环,执行下一次循环
        }

        //2.2 通过判断结构体里面的成员获取坐标值
        if(ev.type == EV_ABS && ev.code == ABS_X) //获取x轴的坐标
        {
          
            *x = ev.value*(1.0*800/1040);
            flag_x = 1 ;
            if(flag_y)
            {
                break;
            }
        }

        if(ev.type == EV_ABS && ev.code == ABS_Y) //获取y轴的坐标
        {
            *y = ev.value*(1.0*480/600);
            flag_y = 1 ;
            if(flag_x)
            {
                break;
            }
        }

        if(ev.type == EV_KEY && ev.code == BTN_TOUCH && ev.value == 0 ) //手指松开
        {
            break;//一次获取
        }
    }

    //3.关闭触摸屏
    close(fd);

}


/*
    功能 : 获取方向返回
        返回值 :
        -1 失败
        UP 1
        DOWN 2
        LEFT 3
        RIGHT 4

*/
int getway()
{
    //1.打开触摸屏
    int fd = open("/dev/input/event0",O_RDWR);
    if(-1 == fd)
    {
        perror("open touch fail");
        return -1;
    }
    //2.操作
    
    struct input_event ev;//保存读取出来的信息
    int x0 = -1 ,y0 = -1 ;//初始坐标,把自身作为判断
    int x1 ,y1;

    while(1)
    {
        //2.1 读取输入事件
        int res = read(fd,&ev,sizeof(ev));
       

        if(res != sizeof(ev)) // 判断结构体数据不符合要求 重新读
        {
            continue;//跳过本次循环,执行下一次循环
        }

        //2.2 通过判断结构体里面的成员坐标值
        if(ev.type == EV_ABS && ev.code == REL_X) //获取x轴的坐标
        {
            if(-1 == x0)
            {
                x0 = ev.value;  //只获取一次
            }
            x1 = ev.value;
           
        }

        if(ev.type == EV_ABS && ev.code == REL_Y) //获取x轴的坐标
        {
            if(-1 == y0)
            {
                y0 = ev.value;  //只获取一次
            }
            y1 = ev.value;
           
        }

        if(ev.type == EV_KEY && ev.code == BTN_TOUCH && ev.value == 0 ) //手指松开
        {
            break;//一次获取
        }
    }

    printf("start ( %d , %d ) , leave ( %d , %d )\n",x0,y0,x1,y1);
    

    int way; //方向
    if(abs((y1-y0)/(x1-x0)) >= 1) //上 或者 下
    {
        if(y1 > y0)
        {
            printf("DOWN\n");
            way = DOWN;
        }
        else
        {
            printf("UP\n");
            way = UP;
        }
    }
    else
    {
        if(x1 > x0)
        {
            printf("RIGHT\n");
            way = RIGHT;
        }
        else
        {
            printf("LEFT\n");
            way = LEFT;
        }
    }

    close(fd);

    return way;
}

main.c

#include <stdio.h>
#include "touch.h"
#include "lcd.h"

int main()
{
    int touch_fd = Init_touch();
    int fd=-1;
	int* plcd = Init_LCD(&fd);

	//int x,y;
	// for(y=0;y>=10&&y<420;y++)
	// {
	// 	for(x=0;x<=790&&x>=10;x++)
	// 	{
	// 		Lcd_draw_point(x,y,0x000000,plcd);
	// 	}
	// }

	Bmp_display("./bmp/shang.bmp",20,420,plcd);
	Bmp_display("./bmp/xiay.bmp",174,420,plcd);
	Bmp_display("./bmp/sui.bmp",328,420,plcd);
	Bmp_display("./bmp/xun.bmp",482,420,plcd);
	Bmp_display("./bmp/ting.bmp",636,420,plcd);
	char *file_name[] = {"./bmp/1.bmp","./bmp/2.bmp","./bmp/3.bmp","./bmp/4.bmp","./bmp/5.bmp","./bmp/6.bmp","./bmp/7.bmp","./bmp/8.bmp","./bmp/9.bmp","./bmp/10.bmp"};	//存放图片地址和名字
    int x1=-1,y1=-1,x2=-1,y2=-1;
	int i=0;//存放图片顺序
	int x,y; //存放坐标值
    while(1)
    {
		get_usr_touch(&x,&y);
        //显示区域
		if(x >= 10 && x <= 790 && y >= 10 && y<= 410)
		{
			//测试滑动			
			if(-1 == get_usr_input_pro(touch_fd,&x1,&y1,&x2,&y2))
			{
				continue;
			}
			int direction;
			switch (direction = Get_slip_direction(x1,y1,x2,y2))
			{
				case UP:
					printf("UP\n");
					if(9 == i)
					{
						i = -1;
					}
					printf("%d\n",i);
					Bmp_display(file_name[++i],10,10,plcd);
					break;
				case DOWN:
					printf("DOWN\n");
					if(0 == i)
					{
						i = 10;
					}
					Bmp_display(file_name[--i],10,10,plcd);
					break; 
				case RIGHT:
					printf("RIGHT\n");
					if(0 == i)
					{
						i = 10;
					}
					Bmp_display(file_name[--i],10,10,plcd);					
					break; 
				case LEFT:
					printf("LEFT\n");
					if(9 == i)
					{
						i = -1;
					}
					printf("%d\n",i);
					Bmp_display(file_name[++i],10,10,plcd);					
					break; 
				default:
					break;
        	}
		}
        //上一张
		else if(x >= 20 && x <= 164  && y >= 420 && y<= 470)
		{
			Bmp_display("./bmp/shang1.bmp",20,420,plcd);
			usleep(500);
			Bmp_display("./bmp/shang.bmp",20,420,plcd);
			if(0 == i)
			{
				i = 10;
			}
			printf("return\n");
            Bmp_display(file_name[--i],10,10,plcd);
		}
        //下一张
		else if(x >= 174 && x <= 318 && y >= 420 && y<= 470)
		{
			if(9 == i)
			{
				i = -1;
			}
			printf("next\n");
            Bmp_display(file_name[++i],10,10,plcd);
		}
        //随机播放
		else if(x >= 328 && x <= 472 && y >= 420 && y<= 470)
		{
			i = random()%10;
			Bmp_display(file_name[i],10,10,plcd);
		}
        //循环播放
		else if(x >= 482 && x <= 626 && y >= 420 && y<= 470)
		{
			while(1)
			{
				if(9 == i)
				{
					i = -1;
				}
				Bmp_display(file_name[++i],10,10,plcd);
				sleep(1.5);
			}
		}
        //停止循环播放
		else if(x >= 420 && x <= 636 && y >= 470&& y<=780  )
		{
			printf("停止循环播放");
		}
    }
    Uninit_touch(touch_fd);
    Uninit_LCD(fd,plcd);
    return 0;
}