实验目的
利用粤嵌LinuxGEC6818开发板实现电子相册,要求如下: 实验操作必须在Linux操作系统下完成源代码模块化设计实现水平或者垂直滑动切换图片实验步骤
因为操作需要在Linux下运行,所以首先安装VM虚拟机,此次安装的系统是Ubuntu18,这里不再进行介绍。涉及ARM编译,gcc编译的可执行文件,它只适合在X86架构上运行的linux上运行,并不能在ARM架构上的linux上运行。所以需要采用交叉开发。交叉开发
有些产品(或设备)并不适合编辑编译代码。比如:51单片机,STM32…把编辑编译和运行分开,我们在X86的机器上(电脑)编辑编译代码,再把可执行文件传输到产品(或设备)上运行。gcc编译的可执行文件,它只适合在X86架构上运行的linux上运行。并不能在ARM架构上的linux上运行。
arm-linux-gcc编译的文件只适合在arm架构上的linux上运行。 因为需要让屏幕显示内容,必须先对屏幕进行坏点测试,排除屏幕坏点问题,全屏显示蓝色,程序如下:
#include "lcd.h"/*宏定义*/#define BLUE 0x0000FF#define LCD_PATH "/dev/fb0"//全局变量int fd = -1;int *plcd = NULL;//lcd初始化int lcd_init(){ //1.打开屏幕文件 fd = open(LCD_PATH,O_RDWR);//可读可写打开 if(fd<0) { perror("open fail"); return -1; } //2.映射 plcd = mmap(NULL, 800*480*4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if(plcd == MAP_FAILED) { perror("MAP fail"); return -1; } return 0;}//LCD关闭void lcd_close(){ munmap(plcd,800*480*4); close(fd);}//指定的点上显示指定的颜色void display_point(int x,int y,int color) //x为高,y为宽{ if(x >= 0 && x < 800 && y >= 0 && y < 480) { *(plcd + 800 * y + x) = color; }}//LCD测试void lcd_test(){ lcd_init(); int x,y; for(y=0;y<480;y++)//遍历每一行 { for(x=0;x<800;x++)//遍历每一列 { display_point(x,y,BLUE); } } // //写数据 // write(fd,color,480*800*4); lcd_close(fd);}
确认屏幕没有坏点后,可以将图片写入屏幕中,让屏幕显示图片,在主函数中调用show_bmp(char * filename,int x0,int y0)
,即可显示让屏幕图片,filename为文件名,x0跟y0是屏幕显示的起始坐标,左上角为起始位(0,0)。程序如下: #include "Bmp.h"#include "lcd.h"//显示图片int show_bmp(char * filename,int x0,int y0){ //1.打开bmp图片 int fd = open(filename,O_RDWR); //判断读入图片是否错误 if (-1 == fd) { printf("Open %s Fail!\n",filename); perror("--->"); return -1; } //2.判断到底是不是一张bmp图片unsigned char buf[4];read(fd,buf,2);if(buf[0]!= 0x42 || buf[1]!= 0x4d)//若果不是B M 的ASCII码{printf("NOT BMP\n");goto ERROR_END;} //3.读取数据 int width,height; short depth;lseek(fd,0x12,SEEK_SET);read(fd,buf,4);width=(buf[3]<<24)| (buf[2]<<16)| (buf[1]<<8)| (buf[0]);lseek(fd,0x16,SEEK_SET);read(fd,buf,4);height=(buf[3]<<24)| (buf[2]<<16)| (buf[1]<<8)| (buf[0]);lseek(fd,0x1c,SEEK_SET);read(fd,buf,2);depth=(buf[1]<<8)| (buf[0]);//只支持色深为24和32的if(!(depth == 24 || depth == 32)){printf("NOT Support!\n");goto ERROR_END;}printf("%s:%d*%d depth=%d\n",filename,width,height,depth);//4.获取像素数组int line_valid_bytes = abs(width)*depth/8;//一行有效字节数int line_bytes;//一行总字节数=有效字节数+赖子数 int laizi = 0;if(line_valid_bytes%4){laizi = 4-line_valid_bytes%4;}line_bytes = line_valid_bytes + laizi;int total_bytes = line_bytes*abs(height);//整个像素数组的大小//开辟一块动态内存unsigned char *piexl = (unsigned char *)malloc(total_bytes); //用完后需要释放内存lseek(fd,54,SEEK_SET);read(fd,piexl,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++){//a r g b 0xargb 小端模式 b g r ab = 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);//在屏幕对应的位置显示display_point(width>0?x0+x:x0+abs(width)-x-1, height>0?y0+abs(height)-y-1:y0+y,color);}//每一行的末尾 有可能填充几个赖子i += laizi;} //释放内存 free(piexl); //关闭显示close(fd); ERROR_END:close(fd);return -2;}//图片数组// char * bmpname[] = {"1.bmp","2.bmp","3.bmp","4.bmp","5.bmp","6.bmp"};//循环显示图片void bmp_player(int i){// int i = 0;// while (1)// { //循环显示 // show_bmp(bmpname[i],0,0); // 延时5s // sleep(5); // i++; // if (6 == i) // { // i = 0; // } // } }
接下来获取手指触摸触摸坐标,程序如下: #include "touch.h"#define UP 1#define DOWN 2#define LEFT 3#define RIGHT 4//宏定义//设备文件#define TOUCH_PATH "/dev/input/event0"int GetDirection(){ //1.打开触摸屏 lcd_init(); int fd = open(TOUCH_PATH,O_RDONLY);//只读打开 if(fd<0) { perror("open fail"); return 0; } int x_start=-1,y_start=-1;//坐标的初值 int x_end = -1,y_end = -1; //坐标终点 struct input_event ev; while(1) { //2.不停地从文件中读取数据 read(fd, &ev, sizeof(struct input_event)); //3.解析数据 if(ev.type == EV_ABS) //触摸事件 { if(ev.code == ABS_X) { if (-1 == x_start) //x轴 { x_start = ev.value;//起点 } x_end = ev.value; //终点 } if(ev.code == ABS_Y)//y轴 { if (-1 == y_start) { y_start = ev.value; } y_end = ev.value; //终点 } if(ev.code ==ABS_PRESSURE && ev.value == 0) { if(x_start != -1 && y_start != -1) { break; } } } if(ev.type == EV_KEY && ev.code == BTN_TOUCH && ev.value == 0) //按键事件 { if(x_start != -1 && y_start != -1) { break; } } if (abs(x_end - x_start) > (y_end - y_start)) { if (x_end - x_start > 0) { return 4; } else { return 3; } } if (abs(x_end - x_start) < (y_end - y_start)) { if (y_end - y_start > 0) { return 2; } else { return 1; } } } //打印坐标 printf("%d , %d\n", x_end, y_start); //4.关闭触摸屏 lcd_close();}
获得手指滑动坐标后,终点坐标减去手指滑动起始坐标,即可判断手指是左滑、右滑还是上滑、下滑,随即再做下切换的图片的指令即可,程序如下: #include "lcd.h"#include"Bmp.h"#include "touch.h"char * bmpname[] = {"1.bmp","2.bmp","3.bmp","4.bmp","5.bmp","6.bmp"};//主函数int main(int argc, char const *argv[]){ int rs = 0; int i = 0; //打开屏幕 lcd_init(); //单独显示一张图片 // show_bmp("1.bmp",0,0); //触摸 while (1) { // bmp_player(i); rs = GetDirection(); printf("%d\n",rs); if (1 == rs || 3 == rs) { if (5 == i) { i = 0; } else ++i; show_bmp(bmpname[i],0,0); // bmp_player(i); } // show_bmp(bmpname[3],0,0); else if (2 == rs || 4 == rs) { if (0 == i) { i = 5; } else --i; // bmp_player(i); show_bmp(bmpname[i],0,0); } } //循环显示 // bmp_player(); //关闭屏幕 lcd_close(); return 0;}
总结
整个工程可以正常运行,已上板测试验证,现实中图片是很清楚的,只是网站限制了只能上传5M以内,压缩了画质。GIF如下:![水平切换图片](http://zhangshiyu.com/zb_users/upload/2023/03/20230313184904167870454442968.gif)
![垂直切换图片](http://zhangshiyu.com/zb_users/upload/2023/03/20230313184905167870454593455.gif)
提取码:iejv