更多资料请点击:我的目录
本篇仅用于记录自己所学知识及应用,代码仍可优化,仅供参考,如果发现有错误的地方,尽管留言于我,谢谢。
设计目标:
①实现用户注册、用户名、密码输入登录功能
②实现bmp图片居中显示、左右切换、缩放
③实现音乐(MP3)的播放、暂停、切歌、播放模式设定
④实现视频(WMV)的播放、暂停、切换
后续更新:
LCD显示屏加入百叶窗特效显示BMP图片
部分效果如下:
视频操作部分
点击切换
划动切换与缩小
划动退出
**注意!注意!**编译命令是用 arm-linux-gcc,而不是gcc的
主头文件(各部分通用的函数、定义)
myhead.h
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/mman.h>
#include <linux/input.h>
#include <errno.h>
#include <dirent.h>
#ifndef MYHEAD_H
#define MYHEAD_H
struct input_event myevent; //定义输入子系统模型有关的结构体变量
int tsfd ; //触摸屏驱动
int dst; //显示屏驱动
int tx1 = 0,ty1 = 0,tx2 = 0,ty2 = 0; //触摸屏返回值
//重置触摸屏坐标返回值
void clear()
{
tx1 = 0, ty1 = 0,tx2 = 0,ty2 = 0;
}
//打开显示屏
int display_open()
{
dst = open("/dev/fb0",O_RDWR); //打开显示屏驱动
if(dst == -1)
{
printf("显示屏打开失败!\n");
return -1;
}
}
//关闭显示屏
int display_close()
{
close(dst);
}
//打开触摸屏
int touch_open()
{
tsfd=open("/dev/input/event0",O_RDWR); //打开触摸屏驱动
if(tsfd==-1)
{
perror("打开触摸屏失败!\n");
return -1;
}
return 0;
}
//关闭触摸屏
int touch_close()
{
close(tsfd);
return 0;
}
//显示任意位置大小缩放的BMP图片
bool showbmp(char *bmppath, int n)
{
int w = 0;
int h = 0;
int src = open(bmppath , O_RDWR);
lseek(src, 18 ,SEEK_SET); //获取BMP图片的宽w信息
read(src, &w, 4);
lseek(src, 22 ,SEEK_SET); //获取BMP图片的高h信息
read(src, &h, 4);
char bmpbuf[w*h*3];
int lcdbuf[w*h];
int tempbuf[w*h];
int lcdbuf1[] = {0};
lseek(src, 54, SEEK_SET); //跳过BMP图片头信息字节
int rubbish = (4-(w*3)%4)%4; //BMP图片字节不能被4整除时,加入的垃圾字节数
for(int i = 0; i < h; i++)
{
read(src, &bmpbuf[w*i*3],w*3);
lseek(src, rubbish, SEEK_CUR); //在字节读入时,跳过垃圾字节
}
for(int i = 0; i < w*h; i++) //将RGB转换成BGR
{
lcdbuf[i] = 0x00<<24 | bmpbuf[i*3+2]<<16 | bmpbuf[i*3+1]<<8 | bmpbuf[i*3];
}
for(int i = 0; i < w; i++)
{
for(int j = 0; j < h; j++)
{
tempbuf[(h-1-j)*w+i] = lcdbuf[j*w+i]; //BMP像素点上下反转
}
}
//内存映射
int *mmap_bmp = mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, dst, 0);
for(int i=0; i<h/n; i++) //图片的高度h / 缩放倍数n
{
for(int j=w*n*i,k=0; j<(w*n*i+w);j+=n,k++) //循环决定每行该取的像素点
{
//任意位置(480-h/n)/2)、(800-w/n)/2)、缩小倍数n
*(mmap_bmp+800*(((480-h/n)/2)+i)+((800-w/n)/2)+k) = tempbuf[j];
}
}
//解除内存映射
munmap(mmap_bmp, 800*480*4);
close(src);
}
int get_xy(int *x1, int *y1,int *x2, int *y2) //获取触摸屏的坐标值
{
int count = 0;
while(1)
{
//读取触摸屏的坐标
read(tsfd,&myevent,sizeof(myevent));
if(myevent.type==EV_ABS && count == 0) //判断触摸屏事件
{
if(myevent.code==ABS_X) //x坐标
{
*x1 = ((myevent.value*800)/1024); //初次碰到触摸屏时的x值
}
}
if(myevent.type==EV_ABS && count == 0) //判断触摸屏事件
{
if(myevent.code==ABS_Y) //y坐标
{
*y1 = ((myevent.value*480)/600); //初次碰到触摸屏时的y值
count++;
}
}
if(myevent.type==EV_ABS && count != 0) //判断触摸屏事件
{
if(myevent.code==ABS_X) //x坐标
{
*x2 = ((myevent.value*800)/1024); //离开触摸屏时的x值
}
}
if(myevent.type==EV_ABS && count != 0) //判断触摸屏事件
{
if(myevent.code==ABS_Y) //y坐标
{
*y2 = ((myevent.value*480)/600); //离开触摸屏时的y值
}
}
if(myevent.type==EV_KEY && myevent.code==BTN_TOUCH
&& myevent.value==0) //保存松开前的x2,y2
{
break; //退出循环
}
}
}
//设置节点
struct node
{
char *data;
struct node *next;
struct node *prev;
};
//初始化链表
struct node *list_init(char *newdata)
{
struct node *head = malloc(sizeof(struct node));
head->data = newdata;
head->next = head;
head->prev = head;
return head;
}
//创建新节点
struct node *newnode(char *newdata)
{
struct node *new = malloc(sizeof(struct node));
new->data = newdata;
new->next = NULL;
new->prev = NULL;
}
//加入新节点
int addnode(struct node *new,struct node *list)
{
struct node *p = list;
while(p->next != list)
{
p = p->next;
}
new->prev = list->prev;
new->next = list;
list->prev = new;
new->prev->next = new;
}
#endif
图像头文件(控制相册)
album.h
#include "myhead.h"
#ifndef ALBUM_H
#define ALBUM_H
//相册控制
int album_control()
{
printf("成功进入相册!!\n");
char buf[20];
label:
showbmp("firstp.bmp",1); //显示缩略图,控制缩小的参数:1为原大小,2为原图的1/2
get_xy(&tx1, &ty1,&tx2, &ty2); //获取触摸屏的坐标
int x_dif = tx2 - tx1;
int y_dif = ty2 - ty1;
if(tx1 > 0 && tx1 < 160) //缩略图对应范围第一列
{
if(ty1 > 0 && ty1 < 160)
{
showbmp("background.bmp",1);
sprintf(buf,"%s","bmp/001.bmp");
showbmp(buf,1);
}
if(ty1 > 160 && ty1 < 320)
{
showbmp("background.bmp",1);
sprintf(buf,"%s","bmp/006.bmp");
showbmp(buf,1);
}
if(ty1 > 320 && ty1 < 480)
{
showbmp("background.bmp",1);
sprintf(buf,"%s","bmp/011.bmp");
showbmp(buf,1);
}
}
if(tx1 > 160 && tx1 < 320) //缩略图对应范围第二列
{
if(ty1 > 0 && ty1 < 160)
{
showbmp("background.bmp",1);
sprintf(buf,"%s","bmp/002.bmp");
showbmp(buf,1);
}
if(ty1 > 160 && ty1 < 320)
{
showbmp("background.bmp",1);
sprintf(buf,"%s","bmp/007.bmp");
showbmp(buf,1);
}
if(ty1 > 320 && ty1 < 480)
{
showbmp("background.bmp",1);
sprintf(buf,"%s","bmp/012.bmp");
showbmp(buf,1);
}
}
if(tx1 > 320 && tx1 < 480) //缩略图对应范围第三列
{
if(ty1 > 0 && ty1 < 160)
{
showbmp("background.bmp",1);
sprintf(buf,"%s","bmp/003.bmp");
showbmp(buf,1);
}
if(ty1 > 160 && ty1 < 320)
{
showbmp("background.bmp",1);
sprintf(buf,"%s","bmp/008.bmp");;
showbmp(buf,1);
}
if(ty1 > 320 && ty1 < 480)
{
showbmp("background.bmp",1);
sprintf(buf,"%s","bmp/013.bmp");
showbmp(buf,1);
}
}
if(tx1 > 480 && tx1 < 640) //缩略图对应范围第四列
{
if(ty1 > 0 && ty1 < 160)
{
showbmp("background.bmp",1);
sprintf(buf,"%s","bmp/004.bmp");
showbmp(buf,1);
}
if(ty1 > 160 && ty1 < 320)
{
showbmp("background.bmp",1);
sprintf(buf,"%s","bmp/009.bmp");
showbmp(buf,1);
}
if(ty1 > 320 && ty1 < 480)
{
showbmp("background.bmp",1);
sprintf(buf,"%s","bmp/014.bmp");
showbmp(buf,1);
}
}
if(tx1 > 640 && tx1 < 800) //缩略图对应范围第五列
{
if(ty1 > 0 && ty1 < 160)
{
showbmp("background.bmp",1);
sprintf(buf,"%s","bmp/005.bmp");
showbmp(buf,1);
}
if(ty1 > 160 && ty1 < 320)
{
showbmp("background.bmp",1);
sprintf(buf,"%s","bmp/010.bmp");
showbmp(buf,1);
}
}
if(y_dif < -100) //上划退出相册
{
y_dif = 0 ;
printf("成功退出相册!\n");
return 0;
}
clear(); //重置触摸屏坐标返回值
struct node *list = list_init("010.bmp"); //初始化双向循环链表
char *path = "bmp";
DIR *dp = opendir(path);
struct dirent *p;
while(p = readdir(dp)) //遍历目录文件
{
if(p->d_type == DT_REG)
{
if(strstr(p->d_name,".bmp")) //判断是否为.bmp文件
{
struct node *new = newnode(p->d_name); //创建新节点
addnode(new,list); //插入新节点
}
}
}
struct node *head = list->next;
while(1)
{
clear();
get_xy(&tx1, &ty1,&tx2, &ty2); //获取触摸屏的坐标
x_dif = tx2 - tx1;
y_dif = ty2 - ty1;
if(x_dif > 100 || tx1 > 600) //右翻
{
x_dif = 0;
head = head->next;
bzero(buf,20);
sprintf(buf,"%s/%s",path,head->data);
showbmp("background.bmp",1); //背景图刷屏
showbmp(buf,1); //显示BMP图片
}
if(x_dif < -100 && x_dif > -600 || tx1 < 200) //左翻
{
x_dif = 0;
head = head->prev;
bzero(buf,20);
sprintf(buf,"%s/%s",path,head->data);
showbmp("background.bmp",1); //背景图刷屏
showbmp(buf,1); //显示BMP图片
}
if(y_dif > 100) //下划显示缩小后的图片
{
y_dif = 0 ;
showbmp("background.bmp",1);
showbmp(buf,2); //显示BMP图片,缩小为原图1/2
}
if(y_dif < -100) //上划退回缩略图
{
y_dif = 0 ;
goto label;
}
}
}
#endif
音频头文件(控制音频播放器)
music.h
#include "myhead.h"
#include "album.h"
#ifndef MUSIC_H
#define MUSIC_H
//音乐播放器控制
int music_play()
{
printf("成功打开音乐播放器!\n");
showbmp("background06.bmp",1); //音乐播放器界面-----默认自动播放
//system("madplay music/*.mp3 -z &"); //列表随机播放
system("madplay music/*.mp3 -r &"); //列表循环播放
struct node *list = list_init("1.mp3"); //初始化双向循环链表
char *path = "music";
DIR *dp = opendir(path);
struct dirent *p;
while(p = readdir(dp)) //遍历目录文件
{
if(p->d_type == DT_REG)
{
if(strstr(p->d_name,".mp3")) //判断是否为.mp3文件
{
struct node *new = newnode(p->d_name); //创建新节点
addnode(new,list); //插入新节点
}
}
}
char buf[20]; //用于存放拼接后的字符串
struct node *head = list->next;
for(;;)
{
get_xy(&tx1, &ty1,&tx2, &ty2); //获取触摸屏的坐标
if(ty1 > 260 && ty1 < 360 && tx1 > 350 && tx1 < 440) //恢复播放
{
clear();
system("killall -CONT madplay &");
}
if(ty1 > 115 && ty1 < 215 && tx1 > 350 && tx1 < 440) //暂停播放
{
clear();
system("killall -STOP madplay &");
}
if(tx1 > 470 && tx1 < 570 && ty1 > 115 && ty1 < 215) //下一首
{
clear();
system("killall -9 madplay");
head = head->next;
bzero(buf,20);
sprintf(buf,"madplay %s/%s &",path,head->data);
system(buf);
}
if(tx1 > 200 && tx1 < 300 && ty1 > 115 && ty1 < 215) //上一首
{
clear();
system("killall -9 madplay");
head = head->prev;
bzero(buf,20);
sprintf(buf,"madplay %s/%s &",path,head->data);
system(buf);
}
if(ty1 > 260 && ty1 < 360 && tx1 > 470 && tx1 < 570) //退出
{
system("killall -9 madplay");
printf("成功退出音乐播放器!\n");
break;
}
}
}
#endif
视频头文件(控制视频播放器)
video.h
#include "myhead.h"
#include "album.h"
#ifndef VIDEO_H
#define VIDEO_H
int video_control()
{
printf("成功打开视频播放器!\n");
int flag = 0;
showbmp("start.bmp",1);
struct node *list = list_init("02.wmv"); //初始化双向循环链表
char *path = "movie";
DIR *dp = opendir(path);
struct dirent *p;
while(p = readdir(dp)) //遍历目录文件
{
if(p->d_type == DT_REG)
{
if(strstr(p->d_name,".wmv")) //判断是否为.mp3文件
{
struct node *new = newnode(p->d_name); //创建新节点
addnode(new,list); //插入新节点
}
}
}
char buf[40];
struct node *head = list->next;
for(;;)
{
get_xy(&tx1, &ty1,&tx2, &ty2); //获取触摸屏的坐标
printf("你点击的坐标位置X坐标是:%d\n", tx1);
printf("你点击的坐标位置Y坐标是:%d\n", ty1);
if(tx1 > 360 && tx1 < 405 && ty1 > 410 && ty1 < 480)
{
if(flag == 0) //第一次开始播放
{
clear();
showbmp("stop.bmp",1);
system("mplayer movie/03.wmv -zoom -x 800 -y 420 &");
flag = 1;
continue;
}
if(flag == 1) //停止播放
{
clear();
showbmp("start.bmp",1);
system("killall -STOP mplayer");
flag = 2;
continue;
}
if(flag == 2) //继续播放
{
clear();
showbmp("stop.bmp",1);
system("killall -CONT mplayer");
flag = 1;
continue;
}
}
if(tx1>445 && tx1<500 && ty1>410 && ty1<480 ) //下一个
{
clear();
showbmp("stop.bmp",1);
system("killall -KILL mplayer");
head = head->next;
bzero(buf,40);
sprintf(buf,"mplayer %s/%s -zoom -x 800 -y 420 &",path,head->data);
system(buf);
}
if(tx1>255 && tx1<320 && ty1>410 && ty1<480) //上一个
{
clear();
showbmp("stop.bmp",1);
system("killall -KILL mplayer");
head = head->prev;
bzero(buf,40);
sprintf(buf,"mplayer %s/%s -zoom -x 800 -y 420 &",path,head->data);
system(buf);
}
if(tx1>700 && tx1<800 && ty1>410 && ty1 <480) //退出视频播放器
{
system("killall -KILL mplayer");
printf("成功退出视频播放器!\n");
break;
}
}
}
#endif
主函数(调用各部分函数)
main.c
#include "myhead.h"
#include "album.h"
#include "music.h"
#include "video.h"
FILE *dst1; //文件描述符
char name_buf[]= {0};
char name_buf1[]= {0};
char name_buf2[]= {0};
char name[30] = {0};
char keys[30] = {0};
int input(); //账号密码输入
int sign_in(); //登录
int logon(); //注册
int main()
{
display_open(); //打开显示屏
touch_open(); //打开触摸屏
showbmp("interface1.bmp",1); //登录界面
for(;;)
{
get_xy(&tx1, &ty1,&tx2, &ty2); //获取触摸屏的坐标
input(); //账号密码输入
sign_in(); //登录
logon(); //注册
}
touch_close(); //关闭触摸屏
display_close(); //关闭显示屏
}
//账号密码输入
int input()
{
char username[]= {0};
char password[]= {0};
for(;;)
{
if(tx1 > 240 && tx1 < 600 && ty1 > 160 && ty1 < 220) //用户名方框
{
clear();
printf("请输入用户名:\n");
scanf("%s",username);
get_xy(&tx1, &ty1,&tx2, &ty2); //获取触摸屏的坐标
}
if(tx1 > 240 && tx1 < 600 && ty1 > 260 && ty1 < 315) //密码方框
{
clear();
printf("请输入密码:\n");
scanf("%s",password);
}
bzero(name_buf1,30);
sprintf(name_buf1,"%s%s",username,password);
break;
}
}
//登录
int sign_in()
{
int flag = 0;
get_xy(&tx1, &ty1,&tx2, &ty2); //获取触摸屏的坐标
if(tx1 > 185 && tx1 < 300 && ty1 > 360 && ty1 < 425) //登录方框
{
clear();
dst1 = fopen("1.txt", "r"); //打开用户名密码文件
while(!feof(dst1))//遍历文件内容
{
fgets(name_buf2, 30, dst1);
if(strncmp(name_buf2,name_buf1,strlen(name_buf2) == 0))
{
printf("登陆成功!\n");
flag = 1;
break;
}
bzero(name_buf2, 30);
}
if(feof(dst1) && flag == 0)
{
printf("你输入的用户名与密码不匹配!\n请重新输入!\n\n");
flag = 0;
return 0;
}
label0:
showbmp("interface2.bmp",1);//跳转到主界面
while(1)
{
get_xy(&tx1, &ty1,&tx2, &ty2);//获取触摸屏的坐标
if(ty1 > 80 && ty1 < 180 && tx1 > 200 && tx1 < 300) //音乐播放器
{
music_play();//音乐播放器控制部分
goto label0;
}
if(ty1 > 80 && ty1 < 180 && tx1 > 470 && tx1 < 570) //视频播放器
{
video_control();//视频播放器控制部分
goto label0;
}
if(ty1 > 300 && ty1< 400 && tx1 > 200 && tx1 < 300) //相册
{
album_control();//相册控制部分
goto label0;
}
if(ty1 > 300 && ty1 < 400 && tx1 > 470 && tx1 < 570) //2048
{
goto label0;
}
}
}
}
//注册
int logon()
{
if( tx1 > 510 && tx1 < 615 && ty1 > 360 && ty1 < 425) //注册方框
{
printf("欢迎注册!!\n");
showbmp("interface3.bmp",1);//弹出注册窗口
get_xy(&tx1, &ty1,&tx2, &ty2);//获取触摸屏的坐标
for(;;)
{
if(tx1 > 280 && tx1 < 550 && ty1 > 160 && ty1 < 220)//用户名方框
{
clear();
printf("请输入用户名:\n");
scanf("%s",name);
dst1 = fopen("1.txt", "a+");//打开文件
fwrite(name,1,strlen(name),dst1);//写入内容
fclose(dst1);//关闭文件
get_xy(&tx1, &ty1,&tx2, &ty2);//获取触摸屏的坐标
}
if(tx1 > 280 && tx1 < 550 && ty1 > 260 && ty1 < 320)//密码方框
{
clear();
bzero(name_buf,30);
printf("请输入密码:\n");
scanf("%s",keys);
dst1 = fopen("1.txt", "a+");//打开文件
fwrite(keys,1,strlen(keys),dst1);//写入内容
fprintf(dst1,"\n");//换行
fclose(dst1);//关闭文件
get_xy(&tx1, &ty1,&tx2, &ty2);//获取触摸屏的坐标
}
if(tx1 > 565 && tx1 < 665 && ty1 > 355 && ty1 < 405)//确定
{
clear();
printf(" !注册成功 !\n");
printf("请登录!\n\n");
showbmp("interface1.bmp",1);//登录界面
return 0;
}
if(tx1 > 420 && tx1 < 520 && ty1 > 355 && ty1 < 405)//取消
{
clear();
("interface1.bmp",1);//登录界面
return 0;
}
}
}
}
总结:
最终效果也算是中规中矩,并没有什么特别效果、新奇的算法,只是最普通的实现功能。这里记录一下全过程的想法:
①注册登录部分:运行程序显示登录界面,点击注册方框,跳出注册方框,点击用户名方框输入字符串到char型数组name中,通过文件IO的读写,将用户名字符串写入txt文本,再点击密码方框输入字符串到keys数组中,同样通过文件IO的读写功能,将密码字符串追加到txt文本的同一行,再通过fprintf(dst1,"\n");进行换行操作。点击确定方框又回到登录界面,分别点击用户名、密码进行键盘输入,将输入的字符串分别存放于两个数组中,通过sprintf()函数将两个数组的字符串拼接在一起,最后点击登录方框时,使用fgets()函数(单行读取)循环读取txt文本内容,然后会通过strcmp将文本读出的每一行内容与拼接后的字符串相比较,完全相同则登录成功,进入到主界面。
②音频部分:主界面显示三个图标,设置好对应位置,当点击音频图标位置,会跳转到音频界面(默认列表循环自动播放)。歌曲的列表是通过双向循环链表存放目录文件下 所有(.MP3 )文件实现。同样的音频界面也设置好对应的按钮位置,当点击暂停按钮,就会通过system(“killall -STOP madplay &”); 输入命令,暂停当前歌曲的播放。点击开始按钮,会继续播放刚暂停了的歌曲(暂停位置开始)。而上一首、下一首的切换时,我是通过命令关闭播放器,再重新打开播放器,播放下一首、上一首歌曲。点击终止按钮则退回到主界面。
③视频部分:与音频部分基本相似,当点击视频图标位置,会跳转到视频频界面。视频的列表也是通过双向循环链表存放目录文件下所有(.WMV )文件实现。同样的视频界面也设置好对应的按钮位置,点击开始按钮会播放视频,当点击暂停按钮则暂停当前视频的播放,再点击开始按钮会继续播放刚暂停了的视频(暂停位置开始)。而上一个、下一个视频的切换,我也是通过命令关闭播放器,再重新打开播放器,播放上一个、下一个视频。点击终止按钮则退回到主界面。
④BMP相册部分:当点击相册图标时,则会跳转到"缩略图"页面,点击其中一个“缩略图”就会打开对应的BMP原图,然后可以通过左右点击或者左右划屏进行图片上一张、下一张的切换,下滑可以缩小图片(大小为原图的1/2),缩小倍数通过传参给函数设置,而上划则退回到“缩略图”页面,再上划则退回主界面。
转载:https://blog.csdn.net/weixin_43793181/article/details/107720839