ARM板实现触控幻灯片

1 篇文章 0 订阅

以前看到有些同学的项目,在ARM板上接着的LCD屏幕上播放动画,效果十分酷炫。后来自己也实现了,其基本无非就是控制LCD屏幕显示图片。以下就以24位图为例,介绍让LCD显示图片的方法。24位图是指由分别用8位二进制来表示图像B、G、R值的图片,亦即每个像素点都由24位组成。

环境:ARM Cortex开发板(预装有Linux系统),PC(ubuntu)

首先准备一张图片,可以菜单栏打开画图工具,调整图片大小至适合LCD尺寸,由于我手上的是800*480的LCD,故选择800*480的画布作图,并保存为24位图。


示例图片:


要注意的是,LCD屏幕显示是32位的,即αRGB(多了一个透明度),而我们所要显示的bmp位图是24位且为BGR的,这么一来,我们至少就要解决两个问题:

一个是思考 *如何将24位扩展到32位,另一个问题则是**如何将BGR调转顺序为RGB

按计算所用位图的文件大小本应该是800*480*4=1152000字节的,但是由于图片实际上还存储着文件头信息,所以实际大小要再多出54个字节,这是读取图片时需要注意的。文件头信息跟我们需要显示的像素点无关,故在读取图片信息并显示时我们需要思考***如何只截取像素点信息

另外,LCD的显示与图片的存储是上下颠倒的,所以还要****将图片上下调转再显示。

 

总体来说,实现思路如下:

①访问图片及LCD

②处理图片,包括截取有用的数据、扩展位、调换RGB存储顺序、上下调转

③将图片写入LCD

④回收图片及屏幕资源


首先从IO目录操作开始:(打开目录 -> 进入目录 -> 读取目录 -> 关闭目录)

需要调用到的IO函数:
目录IO         
opendir

       #include <sys/types.h>
       #include <dirent.h>

       DIR *opendir(const char *name);

closedir

       #include <sys/types.h>

       #include <dirent.h>

       int closedir(DIR *dirp);

chdir

       #include <unistd.h>

       int chdir(const char *path);

readdir

       #include <dirent.h>

       struct dirent *readdir(DIR *dirp);

rewinddir

       #include <sys/types.h>
       #include <dirent.h>

       void rewinddir(DIR *dp);

代码如下:

#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
	if(argc!=2)
	{
		printf("Usage: ./project dir\n"); //若输入参数错误,提示用法
		return -1;
	}
	
	
	DIR *dp = opendir(argv[1]);              //打开目录
	if(dp == NULL)                           //打印出错信息便于调试
	{
		printf("opendir error!\n");
		return -1;
	}
	
	int ret = chdir(argv[1]);               //进入目录,类似于cd,注意chdir的参数是路径而不是目录指针!!
	if(ret == -1)                           //打印出错信息便于调试
	{
		printf("chdir error!\n");
		return -1;
	}
	
	struct dirent *ep = NULL;
	while(1)                      
	{
		ep = readdir(dp);               //循环读取目录项
		
		if(ep == NULL)        
		{
			break;                  //读取完成,退出循环
		}
		
		if(ep->d_name[0] == '.')
		{
			continue;               //当前目录(.)以及上一级目录(..)不是我们想要的目录项,故跳过
		}
		printf("%s\n", ep->d_name);     //打印出需要的目录项(即我们要显示的图片)
		
	}
	
	closedir(dp);                           //关闭目录,回收资源
	return 0;
}
	


其次是尝试显示bmp图片:(设备资源使用系统IO操作,普通文件资源使用标准IO )

需要用到的IO函数有:

系统IO
open

       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>

       int open(const char *pathname, int flags);

close

       #include <unistd.h>

       int close(int fd);

write

       #include <unistd.h>

       ssize_t write(int fd, const void *buf, size_t count); 

标准IO
fopen

       #include <stdio.h>

       FILE *fopen(const char *path, const char *mode);

       FILE *fdopen(int fd, const char *mode);

fclose

       #include <stdio.h>

       int fclose(FILE *fp);

fseek

       #include <stdio.h>

       int fseek(FILE *stream, long offset, int whence);


代码如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
	int lcd;
	int ret;
	FILE *fp = NULL;
	char bmp_buf[800*480*3];
	int lcd_buf[800*480];
	
    	lcd = open("/dev/fb0",O_RDWR);              //以可读写方式打开lcd(系统IO)
	if(lcd < 0)
	{
		printf("open fb0 error!\n");    //打印出错信息便于调试
		return -1;
	}
		
	fp = fopen("1.bmp","r+");               //以可读写方式打开图片(标准IO)
	if(fp == NULL)
	{
		printf("fopen 1.bmp error!\n"); //打印出错信息便于调试
		return -1;
	}
	fseek(fp,54,SEEK_SET);                  //***跳过图片头信息前54个字节(标准IO)
	ret = fread(bmp_buf,sizeof(bmp_buf),1,fp);//读取图片信息(标准IO)
	if(ret != 1)
	{
		printf("fread error!\n");       //打印出错信息便于调试
		return -1;
	}
	
	int i,j,t;
	
	for(i = 0; i < 800*480; i++)
	{
                //*&**将每3个char型(共24位)通过移位、位或操作 调整RGB顺序后再存储到 每个int型(32位)中
		lcd_buf[i] = (bmp_buf[3*i])|(bmp_buf[3*i+1]<<8)|(bmp_buf[3*i+2]<<16);  
		
	}
	
	for(j = 0; j <800;j++)
		for(i =0;i<239;i++)
		{
			//****将图片上下调转
			t = lcd_buf[800*i+j];
			lcd_buf[800*i+j]=lcd_buf[(479-i)*800+j];
			lcd_buf[(479-i)*800+j]=t;
		}
	
	write(lcd,lcd_buf,800*480*4);            //将处理完成的图片写入lcd(系统IO)
	close(lcd);				 //关闭lcd,回收资源(系统IO)
	fclose(fp);                              //关闭图片,回收资源(标准IO)
	
	return 0;
}

接下来是触屏部分,我们设定点击屏幕左半边为上一张,右半边为下一张。事件的结构体在头文件linux/input.h中已有定义,我们通过读取这个结构体中的信息来分析当前发生的事件,如是否触摸中、当前触摸坐标等。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

#include <linux/input.h>                        //定义了事件结构体的头文件

int main()
{
	
	struct input_event buf;                 // 定义事件变量
	int x;
	
	int ts = open("/dev/event0",O_RDWR);    //打开触摸屏节点
	if(ts < 0)
	{		
		printf("open ts error!\n");     //打印出错信息便于调试
	}
	
	while(1)
	{
		read(ts,&buf,sizeof(buf));      //循环不断读取触摸屏信息
	
		/*
		if(buf.type == EV_ABS && buf.code == ABS_PRESSURE && buf.value == 0)  //通过读取对触摸屏的压力判断是否触摸中
		{
			printf("you leave LCD!\n");
		}
		*/
		
		if(buf.type == EV_ABS && buf.code == ABS_X)                           //因为我们设计通过判定触摸左右边屏幕进行控制,所以这里读取x坐标
		{
			//printf("x = %d\n",buf.value);
			x = buf.value;
		}
		
		
		if(buf.type == EV_ABS && buf.code == ABS_PRESSURE && buf.value == 0)  //当且仅当离开触摸屏时,判断离开前的x坐标
		{
			if(x<400)
			{
				printf("left!\n");                                    
			}
		
			if(x>400)
			{
				printf("right!\n");
			}
		}	
	}
	
	close(ts);
	return 0;
}


那么对以上代码进行整合修改,即可实现触控幻灯片:

#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
#include <stdlib.h>

 
 int show_bmp(char *name)
{
	int lcd;
	int ret;
	FILE *fp = NULL;
	char bmp_buf[800*480*3];
	int lcd_buf[800*480];
	
    lcd = open("/dev/fb0",O_RDWR);
	if(lcd < 0)
	{
		printf("open fb0 error!\n");
		return -1;
	}
	
	fp = fopen(name,"r+");
	if(fp == NULL)
	{
		printf("fopen error!\n");
		return -1;
	}
	fseek(fp,54,SEEK_SET);
	ret = fread(bmp_buf,sizeof(bmp_buf),1,fp);
	if(ret != 1)
	{
		printf("fread error!\n");
		return -1;
	}
	
	int i,j,t;
	
	for(i = 0; i < 800*480; i++)
	{
		lcd_buf[i] = (bmp_buf[3*i])|(bmp_buf[3*i+1]<<8)|(bmp_buf[3*i+2]<<16);
		
	}
	
	for(j = 0; j <800;j++)
		for(i =0;i<239;i++)
		{
			
			t = lcd_buf[800*i+j];
			lcd_buf[800*i+j]=lcd_buf[(479-i)*800+j];
			lcd_buf[(479-i)*800+j]=t;
		}
	
	write(lcd,lcd_buf,800*480*4);
	close(lcd);
	fclose(fp);

}

 
int main(int argc,char *argv[])  
{
	if(argc != 2)
	{
		printf("arg error!\n");
		printf("Usage: ./test $path\n");
		return -1;
	}
	
	int count = 0;
	int ret, i;
	struct dirent *ep = NULL;
	struct input_event buf;
	int x;

	DIR * dp = opendir(argv[1]);
	if(dp == NULL)
	{
		printf("opendir error!\n");
		return -1;
	}
	
	ret = chdir(argv[1]);
	if(ret == -1)
	{
		printf("chdir error!\n");
	}
	
	
	for(count = 0;(ep = readdir(dp))!=NULL;count++)
	{		
	}	
	printf("Total_count = %d\n",count-2);
	
	char *pic_name[count-2];	
	rewinddir(dp);
	
	for(i=0;i<count-2;)
	{
		ep = readdir(dp);
		
		if(ep->d_name[0] == '.')
		{
			continue;
		}
		
		pic_name[i++] = ep->d_name;
	}
	
	//显示第一张
	show_bmp(pic_name[i=0]);
	while(1)
	{

		int ts = open("/dev/event0",O_RDWR);
		if(ts < 0)
		{		
			printf("open ts error!\n");
		}
	
		while(1)
		{
			read(ts,&buf,sizeof(buf));
		
			if(buf.type == EV_ABS && buf.code == ABS_X)
			{
				//printf("x = %d\n",buf.value);
				x = buf.value;
			}
		
		
			if(buf.type == EV_ABS && buf.code == ABS_PRESSURE && buf.value == 0)
			{
				if(x<400 && i>0)
				{
					printf("previous\n");
				
					show_bmp(pic_name[--i]);
					printf("%s\n",pic_name[i]);
				}
		
				if(x>400 && i<count-3)
				{
					printf("next\n");
				
					show_bmp(pic_name[++i]);
					printf("%s\n",pic_name[i]);
				}						
			}	
		}	
	close(ts);
	}			
	closedir(dp);
	return 0;
}


  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值