Linux简单项目--电子相册

引言:

        入门Linux系统学习也有一点时间了,需要做一些简单项目来巩固所学知识,这个项目较为简单,通过触摸屏实现手动播放相册,自动播放相册,控制LED亮灭,控制蜂鸣器发声或,不发声。

效果图:

分析:

首先电子相册第一个要点:利用显示屏显示

可以通过在显示屏的像素点写入颜色数据

//画点函数
void display_point(int x, int y,int color)
{
	if(x>=0 && x<800 && y>=0 && y<480)//防止越界
	{
		*(plcd + 800 * y + x) = color;
	}
}
    for (i=0;i<480;i++)
    {
        for(j=0;j<800;j++)
        {
            display_point(j,i,0xf0f0f0);
        }
    }

但是这种方法效率低下,刷新速度慢不说,还会出现一些像素点没刷到

所以我们需要mmap

mmap将磁盘上的文件映射到虚拟内存中,使得文件内容可以直接被CPU访问,而不需要复制到用户空间的缓冲区,我们称之为显存,这极大地提升了运行的效率。

//1.打开lcd屏幕文件并且映射
void open_lcd(void)
{
    fd = open("/dev/fb0",O_RDWR);
    if(fd == -1)
    {
        printf("open failed\n");
        return ;
    }

    plcd = mmap(NULL,800*480*4,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
    if(plcd == MAP_FAILED)
    {
        return ;
        printf("mmap failed\n");
    }
}

用完mmap后必须要解除映射

//2.解除映射,关闭文件
void close_lcd(void)
{
    munmap(plcd,800*480*4);

    close(fd);
}

第二个要点:显示图片

我们以BMP文件为例,BMP文件有着自己独有的格式,我们必须了解其格式才能得到数据,按照下图解析

解析代码:

/*
    bmp_display: 在屏幕的坐标(x0,y0)处显示一张指定的bmp图片
    @bmp_file: 要显示的bmp图片的文件名
    @x0: 显示位置左上顶点的x轴坐标
    @y0: 显示位置左上顶点的y轴坐标
    返回值:
        无。
*/
void bmp_display(const char * bmp_file, 
                int x0, int y0)
{
    int fd;


    fd = open(bmp_file, O_RDONLY);
    if (fd == -1)
    {
        perror("failed to open bmp_file");
        return ;
    }

    int width, height;
    short depth;
    

    lseek(fd, 0x12, SEEK_SET);
    read(fd, &width, 4);
    


    lseek(fd, 0x16, SEEK_SET);
    read(fd, &height, 4);
    

    lseek(fd, 0x1C, SEEK_SET);
    read(fd, &depth, 2);
   

    printf("%d x %d\n", width, height);

    if ( !(depth == 24 || depth == 32))
    {
        printf("Sorry, Not Supported Bmp Format!\n");
        close(fd);

        return ;
    }


    int valid_bytes_per_line; //每一行有效的数据字节数
    int laizi = 0; // 每一行末尾的填充的“赖子”数
    int total_bytes_per_line; //每一行实际的字节数.
    int total_bytes; //整个像素数组的字节数


    valid_bytes_per_line =  abs(width) * (depth / 8);
    if (valid_bytes_per_line % 4)
    {
        laizi = 4 - valid_bytes_per_line % 4;
    }
    total_bytes_per_line = valid_bytes_per_line + laizi;
    total_bytes = abs(height) * total_bytes_per_line;

    unsigned char * pixel = (unsigned char*) malloc( total_bytes );
    lseek(fd, 54, SEEK_SET);
    read(fd, pixel, total_bytes);

    // 解析像素数据,并在屏幕上显示
    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 = pixel[i++];
            g = pixel[i++];
            r = pixel[i++];
            if (depth == 32)
            {
                a = pixel[i++];
            }
            else
            {
                a = 0;
            }
            color = (a << 24) | (r << 16) | (g << 8) | b;

            int x1, y1; //该像素点在屏幕上显示的  坐标

            x1 = (width > 0) ? (x0 + x) : (x0 + abs(width) - 1 - x);
            y1 = (height > 0) ?  (y0 + height - 1 - y) : y0 + y;
            display_point(x1, y1, color); 
        }

        i += laizi; //跳过
    }

    free(pixel);

}

第三个要点:触摸

在触摸屏中点击某一点控制事件,

//获取触摸屏点击事件
void get_ts_point(ts_point* p)
{
    int ret;
    int fd;

    fd = open("/dev/input/event0", O_RDONLY);
    if (fd == -1)
    {
        perror("failed to open /dev/input/event0");
        return ;
    }

    int x1 = -1, y1 = -1; //记录点击事件中第一个点的坐标
    int x2, y2; //记录点出事件中最后一个点的坐标

    while (1)
    {
        struct input_event ev;
        ret = read(fd, &ev, sizeof(ev));
        if (ret != sizeof(ev))
        {
            continue;
        }

        // printf("type: %x  code: %x  value: %x\n", ev.type, ev.code, ev.value);

        //触摸屏的x轴事件
        if (ev.type == EV_ABS && ev.code == ABS_X)
        {
            if (x1 == -1)
            {
                x1 = ev.value;
            }
            x2 = ev.value;
        }


        
        //触摸屏的y轴事件
        if (ev.type == EV_ABS && ev.code == ABS_Y)
        {
            if (y1 == -1)
            {
                y1 = ev.value;
            }
            y2 = ev.value;
        }

        //触摸屏弹起事件
        if ( (ev.type == EV_KEY && ev.code == BTN_TOUCH &&  ev.value == 0) ||
             (ev.type == EV_ABS && ev.code == ABS_PRESSURE && ev.value ==0) )
        {
            x1 = x1 * 800.0 / 1024;
            x2 = x2 * 800.0 / 1024;

            y1 = y1 * 480.0 / 600;
            y2 = y2 * 480.0 / 600;

            p->x = x2;
            p->y = y2;
            break;
        }
    }


    close(fd);
}

上下滑动切换图片,利用当前点与下一点作比较,当Y轴移动明显大于X轴时判断向上移动还是向下移动,同理判断左右移动

//获取手指在触摸屏上的滑动方向
move_dir_t get_ts_direction(void)
{
    int ret;
    int fd;
    move_dir_t dir = MOVE_UNKNOWN;

    fd = open("/dev/input/event0", O_RDONLY);
    if (fd == -1)
    {
        perror("failed to open /dev/input/event0");
        return -1;
    }

    int x1 = -1, y1 = -1; //记录点击事件中第一个点的坐标
    int x2, y2; //记录点出事件中最后一个点的坐标

    while (1)
    {
        struct input_event ev;
        ret = read(fd, &ev, sizeof(ev));
        if (ret != sizeof(ev))
        {
            continue;
        }

        // printf("type: %x  code: %x  value: %x\n", ev.type, ev.code, ev.value);

        //触摸屏的x轴事件
        if (ev.type == EV_ABS && ev.code == ABS_X)
        {
            if (x1 == -1)
            {
                x1 = ev.value;
            }
            x2 = ev.value;
        }


        
        //触摸屏的y轴事件
        if (ev.type == EV_ABS && ev.code == ABS_Y)
        {
            if (y1 == -1)
            {
                y1 = ev.value;
            }
            y2 = ev.value;
        }
        //触摸屏弹起事件
        if ( (ev.type == EV_KEY && ev.code == BTN_TOUCH &&  ev.value == 0) ||
             (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)
                {
                    dir = MOVE_RIGHT;
                }
                else
                {
                    dir = MOVE_LEFT;
                }

                break;
            }
            else if (delt_y >= 2 * delt_x)
            {
                if (y2 > y1)
                {
                    dir = MOVE_DOWN;
                }
                else
                {
                    dir = MOVE_UP;
                }
                break;
            }
            else 
            {
                //方向不明,请继续
                x1 = -1;
                y1 = -1;
            }
        }
    }


    close(fd);

    return dir;
}

最后将所有功能结合

int main()
{
    open_lcd();
    
    int i = 0;
    int k,j;
    char * bmp[3] = {"./1.bmp","./2.bmp","./3.bmp"};
    ts_point *p = (ts_point*) malloc(sizeof(p));

    while(1)
    {   
        get_ts_point(p);
        if(p->x<200&&p->x>=0&&p->y>=0&&p->y<480)
        {
            
                bmp_display("./1.bmp",0,0);
                sleep(2);
                
                bmp_display("./2.bmp",0,0);
                sleep(2);

                bmp_display("./3.bmp",0,0);
                sleep(2);

                bmp_display("./1.bmp",0,0);
                sleep(2);
                
                bmp_display("./2.bmp",0,0);
                
                
        }

        if(p->x<400&&p->x>=200&&p->y>=0&&p->y<480)
        {
            bmp_display(bmp[i],0,0);
            move_dir_t dir =  get_ts_direction();
            if(dir == MOVE_DOWN)
            {
                if(i == 0)
                {
                     i = 2;
                }
                else
                {
                    i--;
                }
                bmp_display(bmp[i],0,0);
            }   
            if(dir == MOVE_UP)
            {
                if(i == 2)
                {
                    i = 0;
                }
                else
                {
                    i++;
                }
                bmp_display(bmp[i],0,0);
            } 
        }
        //led
        if(p->x<600&&p->x>=400&&p->y>=0&&p->y<480)
        {
            int fd = open("/sys/kernel/gec_ctrl/led_all",O_RDWR);
            if(fd == -1)
            {
                printf("open failed led\n");
                return -1;
            }
            k = !k;
            write(fd,&k,4);
            close(fd);
        }
        //beep
        if(p->x<800&&p->x>=600&&p->y>=0&&p->y<480)
        {
            int fd = open("/sys/kernel/gec_ctrl/beep",O_RDWR);
            if(fd == -1)
            {
                printf("open failed beep\n");
                return -1;
            }
            j = !j;
            write(fd,&j,4);
            close(fd);
        }
        
    }
    
    
    

    close_lcd();

    return 0;
}

效果视频:

Linux--电子相册视频

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

糕手li

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值