![9d8e8e4499840d48b00ed7803284f517.png](https://i-blog.csdnimg.cn/blog_migrate/8157f785d2f0bfccb5b0db0abee16e5e.jpeg)
图控大叔
构图传递思想
阅读从未如此简单!!!
01
前言
前些天分享了LCD屏实现图片移动的代码分享,但是上次未加入触摸效果,本次推文在上次效果的基础上增加了触摸效果,其实主要是获取LCD触摸屏函数的应用!
02
干货
实现思路(可能很low):
1、设置全局变量存储图片左上角位置点(x、y)
2、通过某函数获取得到触摸坐标
3、得到的触摸坐标放在全局变量中
4、将全局变量放入图片显示函数中
5、来个死循环嗨一下
注:该图片显示函数已经经过多次调试,进行了优化,极大程度上避免了段错误的出现。
注:小编的思路可能很low,但是小编把代码分享出来,是希望作为一个参考方案,而不是标准答案,至于复杂功能的开发,则需要大家的深入学习。
注:由于小编忘记了Linux环境下,多个.c文件如何编译,因此把全部函数放在了一个.c文件中。后期小编再整合吧,目前先这样分享出来!
例程代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LCD_H 480
#define LCD_W 800
#define TS_DEV "/dev/input/event0"//"/dev/ubuntu_event"
#define TS_MODE 1
#include
//1表示坐标范围为:x:0~1023, y:0~599
//0表示坐标范围为:x:0~799 y:0~479
/*
#define LCD_H 480
#define LCD_W 800
此处宏定义将规范图片显示的范围
*/
int show_bmp(int x, int y, int bmp_w, int bmp_h, char *bmp_path);
int single_color(int x1, int y1,int x2, int y2, unsigned int color, unsigned int *addr);
int bmp_color(int star_w, int star_h,int bmp_w, int bmp_h, unsigned int *color, unsigned int *addr);
int get_xy(int x, int y);
int mouse_x = 0;
int mouse_y = 0;
/*
int mouse_x = 0;
int mouse_y = 0;
此处为全局变量,
作为触摸屏坐标获取值的存储变量
也作为图片显示函数的起始点
*/
int main(int argc, const char **argv){
show_bmp(0, 0, 400, 300, "./1.bmp");
return 0;
}
int show_bmp(int x, int y, int bmp_w, int bmp_h, char *bmp_path){
//char *bmp_path = "/gz2030/1.bmp";
if(x+bmp_w > 800 || y+bmp_h > 480)
{
printf("bmp: %s too big", bmp_path);
return -1;
}
printf("bmp_path:%s\n", bmp_path);
//1》打开bmp文件bmp_w*bmp_h
FILE *bmp_fp = fopen(bmp_path, "r");
if(bmp_fp == NULL)
{
fprintf(stderr, "fopen %s failed: %s\n", bmp_path, strerror(errno));
return -1;
}
else
{
printf("showing %s bmp_w: %d bmp_h : %d\n", bmp_path, bmp_w, bmp_h);
}
//2》跳过54个字节文件头
//lseek(bmp_fp->_fileno, 54, SEEK_SET);
fseek(bmp_fp, 54, SEEK_SET);
unsigned char bmp_buf[bmp_w*bmp_h*3];
bzero(bmp_buf, bmp_w*bmp_h*3);
//3》读取bmp文件像素点数据bmp_w*bmp_h*3
fread(bmp_buf, bmp_w*bmp_h*3, 1, bmp_fp);
//4》关闭bmp文件
fclose(bmp_fp);
//5》打开LCD屏幕文件
int lcd_fd = open("/dev/fb0", O_RDWR);
if(lcd_fd == -1)
{
perror("open /dev/fb0 failed");
return -1;
}
//6》内存映射
unsigned int *addr = mmap(NULL, 800*480*4, PROT_READ | PROT_WRITE, MAP_SHARED , lcd_fd, 0);
if(addr == MAP_FAILED)
{
perror("mmap /dev/fb0 failed");
return -1;
}
unsigned int lcd_buf[bmp_w*bmp_h];
bzero(lcd_buf, bmp_w*bmp_h*4);
unsigned int lcd_buf_2[800*480];
bzero(lcd_buf_2, 800*480*4);
int i, j,k,m;
//7》把bmp像素点数据转化成LCD类型的像素点数据
for(j=0; j {
for(i=0; i {
lcd_buf[i+j*bmp_w] = bmp_buf[0+3*i+j*bmp_w*3] | (bmp_buf[1+3*i+j*bmp_w*3]<<8) | (bmp_buf[2+3*i+j*bmp_w*3]<<16);
}
}
//白色清屏
single_color(0,0,480,800,0xffffff,addr);
//8》把像素点数据通过指针赋值的方式写入到文件
//多组数据以便观察
usleep(1000*50);
bmp_color(0,0,400,300,lcd_buf,addr);
while(1)//死循环
{
get_xy(mouse_x, mouse_y);
bmp_color(mouse_x,mouse_y,400,300,lcd_buf,addr);
}
//9》关闭文件和接触内存映射
close(lcd_fd);
munmap(addr, 800*480*4);
return 0;
}
int single_color(int x1, int y1,int x2, int y2, unsigned int color, unsigned int *addr){
int i, j;
for(j=x1; j {
for(i=y1; i {
*(addr+800*j+i) = color;
}
//usleep(1000*2);//此处加入延迟便于观察,可注释掉
//printf("j is %d\n",j);
}
return 0;
}
/*
bmp_color:静态图片实现位置变化
star_h、star_w:移动起始点
bmp_h、bmp_w:图片宽度、长度
color:图片像素点(以数组形式出现)
*addr:内存映射地址
异常情况说明:
因为现实中LCD屏尺寸不一
本次使用的LCD屏尺寸为:480*800
因此对star_h、star_w、bmp_h、bmp_w的数值填充时
需要理性填写,不要给自己挖坑
另外,该函数对于不合理的数组进行判别
如:图片尺寸不合理时,打印错误;
图片尺寸合理,但是移动起点不合理时,
自动判别处理,重新赋值移动起点
记录于:2020/7/4
*/
int bmp_color(int star_w, int star_h,int bmp_w, int bmp_h, unsigned int *color, unsigned int *addr){
int i,j;
//判断数值是否合理
if( (bmp_h>LCD_H) || (bmp_w>LCD_W) )
{
printf("the photo is too big\n");
}
else if( LCD_H-star_h {
star_h = LCD_H -star_h + bmp_h;
if( star_h < LCD_H )
star_h = LCD_H-star_h;
else
star_h = star_h-LCD_H;
if( LCD_W-star_w {
star_w = LCD_W - bmp_w;
//printf("star_w is %d\n",star_w);
}
//先将屏幕以白色清屏
single_color(0,0,480,800,0xffffff,addr);
for(j=0; j {
for(i=0; i {
//显示到指定坐标位置,正立的
*(addr+i+(bmp_h-1-j)*800+800*star_h+star_w) = color[i+j*bmp_w] ;
}
//usleep(1000);//此处加入延迟便于观察,可注释掉
}
}
else if( LCD_W-star_w {
star_w = LCD_W - bmp_w;
if( LCD_H-star_h {
star_h = LCD_H -star_h + bmp_h;
if( star_h < LCD_H )
star_h = LCD_H-star_h;
else
star_h = star_h-LCD_H;
}
//先将屏幕以白色清屏
single_color(0,0,480,800,0xffffff,addr);
for(j=0; j {
for(i=0; i {
//显示到指定坐标位置,正立的
*(addr+i+(bmp_h-1-j)*800+800*star_h+star_w) = color[i+j*bmp_w] ;
}
//usleep(1000);//此处加入延迟便于观察,可注释掉
}
}
else
{
//先将屏幕以白色清屏
single_color(0,0,480,800,0xffffff,addr);
for(j=0; j {
for(i=0; i {
//显示到指定坐标位置,正立的
*(addr+i+(bmp_h-1-j)*800+800*star_h+star_w) = color[i+j*bmp_w] ;
}
//usleep(1000);//此处加入延迟便于观察,可注释掉
}
}
return 0;
}
int get_xy(int x, int y){
int pressure;
//1、打开触摸屏设备文件: /dev/input/event0
int ts_fd = open(TS_DEV, O_RDWR );
if(ts_fd == -1)
{
fprintf(stderr, " open %s failed:%s\n", TS_DEV, strerror(errno));
return -1;
}
struct input_event ts_buf;
bzero(&ts_buf, sizeof(ts_buf)); //清空结构体
while(1) //要多次的读取事件的值
{
//2、读取触摸屏文件里面的数据:struct input_event
//每读取一次,触摸屏数据,只能获取到x.y轴、压力值中的一个
//阻塞等待手指点击屏幕,手指没有点击屏幕它是不会往下执行
read(ts_fd, &ts_buf, sizeof(ts_buf));
//3、分析处理触摸屏数据获取你要的值:x、y轴、压力值
//判断事件类型是否为EV_ABS事件
if(ts_buf.type == EV_ABS)
{
usleep(1000*5);
//进一步判断事件类型是否为x轴事件
if(ts_buf.code == ABS_X)
{
//获取x轴坐标值
x = ts_buf.value;
#if TS_MODE
x = (x) * 800/1024;
mouse_x = x;//赋值给全局变量
#endif
printf("*x1: %d\n", x);
}
else if(ts_buf.code == ABS_Y)
{
//获取y轴坐标值
y = ts_buf.value;
#if TS_MODE
y = (y) * 480/600;
mouse_y = y;//赋值给全局变量
#endif
printf("*y1: %d\n\n", y);
}
}
//判断事件类型是否为EV_KEY,手指离开屏幕,压力值为0,就停止坐标捕捉
if(ts_buf.type == EV_KEY && ts_buf.code == BTN_TOUCH && ts_buf.value == 0)
{
printf("*y2: %d\n", y);
printf("*x2: %d\n\n", x);
//赋值给全局变量
mouse_x = x;
mouse_y = y;
break; //跳出死循环
}
}
//4、关闭触摸屏文件
close(ts_fd);
}
演示效果
03
结尾
本次推文的内容到这里就要结束了,小编发现自己还是有很多不足,比如说连简单的多个.c文件同时编译都忘记了,害,慢慢整理出来吧!
《图控大叔》,与你一起进步!