项目框架
触摸屏电子相册
1、密码登录 (9键 6位密码登陆、36键 6位随机验证码)
2、电子相册功能(有自动浏览,手动浏览,上一张,下一张、 划屏操作 )
1、密码登录 (9键 6位密码登陆、36键 6位随机验证码)
2、电子相册功能(有自动浏览,手动浏览,上一张,下一张、 划屏操作 )
指定运用方法(用链表将当前目录下面的图片连接起来,链表采用双向循环,或者内核链表)
3、音乐播放功能(播放、暂停、上一首、下一首)
其他:全触摸操作,链表链接,不许用线程。
运用知识:linux C, 文件IO,数据结构,Bmp24图片解码,jpeg图片解码,在任意位置显示24位位图图片
项目感想
1)项目框架很重要,早早的想好项目框架,对写代码有明显的辅助作用。而且能够看到自己开发过程,每完成一个功能有激励的效果。
2)准备工作很重要,在写之前列好各种需要用到的函数原型,不需要在写的过程中还在想,这个函数怎么用。
3)每写一个函数的时候,一定要想好这个函数的功能是什么,不能写过超出这个函数功能之外的东西,因为函数是被方便多次调用的,而不是只用一次,只用一次的函数,没有存在的意义。
4)每一个功能,一个全局变量,定义名字的时候一定要有代表性,有含义,不要瞎定义,有时定义一个i ,搞得自己都不知道他是干嘛的了。
5)关键的地方一定要备注,很重要,有时灵光一闪想到的算法,过了一两天,我居然看不懂了。
6)写代码的时候,不能一次写出超过两个函数以上的功能,两个以上的时候,找BUG会非常繁琐,浪费时间,建议每写一个小功能要调试一次,只有把地基打牢,才能建起高楼,特别是在写到自己不太熟练的,一定要想好,调试好。
7)习惯写调试信息,没有一个正确的反馈根本不知道自己出错在哪。而且用完以后也不要删除,注释就好,可能后面还要用呢。
8)刚开始的时候写的时候,不要把初始的功能想的太复杂,越复杂的东西越难实现,只要结果能够达到初始所设计的目标就够了。想要更智能需要重新构思。我在刚开始写26键密码按钮的时候,耗了很多时间,看到别人把9键都已经做出来了,压力更大了,也没信心写了,后来改回简单的9键,做完整个项目再慢慢加上去,觉得特别的轻松。
9)有那么一刻觉得,自己的代码是完美的,绝对是系统出错了。经过无数次打脸后,得出一个结果,永远不要怪系统出错,就是自己的错误,电脑发展至今,就是经历了无数程序员的修改,完善,不可能自己的一时想法,就超越了这么多的前人。
10)永远不要对自己的代码感到满足。同时也要对自己的代码充满信心。
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h>
#include <stdlib.h>
#include <netdb.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "tslib.h"
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <strings.h>
#include "list.h"
#include <time.h>
#define DEV_NAME "/dev/event0"
#define USR_PW "./setting/password"
int g_y=0; //字母弹框
int g_x=1; //操作教程
int g_lcd_fd; //触摸屏显示
unsigned long *g_fd_men;//显示屏的 内存映射
char num[6]; //密码
char numm[6]; //验证码
char bmp[][40]; //图片
char mmp3[][40]; //音乐
void picture_or_music(void); //声明选项
//链表--------------OPEN----------------------
//设计节点 双向链表
typedef struct node
{
char bmpp[40];
struct node *prev;
struct node *next;
}listnode,*double_list; //listnode = struct node ,double_list = struct node *
//2、初始化空链表
double_list init_list(void)
{
double_list head = malloc(sizeof(listnode)); //开辟节点空间
if(head == NULL)
{
printf("malloc node failed!\n");
return NULL;
}
head->prev = head->next = head;
return head;
}
//3、插入节点
void insert_node(double_list new,double_list p)
{
if(new == NULL || p == NULL)
return;
new->prev = p; //第一步
new->next = p->next; //第二步
p->next = new; //第三步
new->next->prev = new; //第四步
}
//3、显示链表操作
void show(double_list head)
{
if(head == NULL)
return;
double_list p = head->next;
while(p!=head)
{
printf("%s\n",p->bmpp);
p = p->next;
}
}
//链表--------------END--------------------
//读文件路径 id=1 读图片 id=2 读音乐
int dir(int id)
{
DIR *dir;
int i=0;
struct dirent *tmp;
struct dirent *tmp2;
//打开目录
if(id==1)
dir = opendir("/coolAlbum/picture");
if(id==2)
dir = opendir("/coolAlbum/music");
if(dir == NULL)
{
perror("opendir!\n");
return -1;
}
//读目录 计算数量
while((tmp = readdir(dir))!=NULL )
{
if(tmp->d_type==4) //跳过系统类型文件
continue;
if(id==1)
{
if(strstr(tmp->d_name,"bmp")!=NULL)
{
i++; //计算图片数量
}
}
if(id==2)
{
if(strstr(tmp->d_name,"mp3")!=NULL)
{
i++; //计算音乐
}
}
}
//根据数量 分配空间
bzero(bmp,i*40);
//打开目录
if(id==1)
dir = opendir("/coolAlbum/picture");
if(id==2)
dir = opendir("/coolAlbum/music");
if(dir == NULL)
{
perror("opendir!\n");
return -1;
}
i=0;
//读文件路径
while((tmp2 = readdir(dir))!=NULL )
{
if(id==1)
{
if(strstr(tmp2->d_name,"bmp")!=NULL)
{
sprintf(bmp[i++],"/coolAlbum/picture/%s",tmp2->d_name);
}
}
if(id==2)
{
if(strstr(tmp2->d_name,"mp3")!=NULL)
{
sprintf(mmp3[i++],"madplay /coolAlbum/music/%s &\n",tmp2->d_name);
}
}
}
return i;
}
//初始化显示屏
int lcd_init(void)
{
g_lcd_fd = open("/dev/fb0",O_RDWR);//打开设备
g_fd_men = (unsigned long *)mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,g_lcd_fd,0);//建立内存映射
if(g_fd_men == NULL)
{
printf("mmap g_fd_men failed!\n");
return -1;
}
return 0;
}
int lcd_uninit(void) //关闭显示屏
{
munmap(g_fd_men,800*480*4);
}
/*任意位置显示24位bmp图片
unsigned long *g_fd_men :显存映射地址
int x :图片起点x
int y :图片起点y
int w :图片的宽
int h :图片的高
const char *pathname :图片路径
*/
int show_shape(unsigned long *g_fd_men,int x,int y,int w,int h,const char *pathname)
{
int bmp_fd,i,j;
char bmp_buffer[w*h*3];
int lcd_buffer[w*h];
//打开图片
bmp_fd = open(pathname,O_RDONLY);
if(bmp_fd == -1)
{
printf("open failed!\n");
return -1;
}
//跳过54个字节头 54个是BMP 文件的信息
lseek(bmp_fd,54,SEEK_SET);
read(bmp_fd,bmp_buffer,sizeof(bmp_buffer));
for(i=0;i<w*h;i++)
{
lcd_buffer[i] = bmp_buffer[3*i] | bmp_buffer[3*i+1]<<8 | bmp_buffer[3*i+2]<<16;
}
for(i=0;i<h;i++)
for(j=0;j<w;j++)
{
*(g_fd_men+(y+i)*800+x+j) = lcd_buffer[(h-1-i)*w+j];
}
close(bmp_fd);
return 0;
}
//划屏
int ts_row(void)
{
struct tsdev *ts;
struct ts_sample samp;
int ret;
int sub=0;
//打开触摸屏
ts = ts_open(DEV_NAME,0);
if(ts == NULL)
{
printf("open ts failed!\n");
}
//配置触摸屏,配置插件
ret = ts_config(ts);
if(ret == -1)
{
printf("ts_config failed!\n");
ts_close(ts);
}
while(1)
{
ts_read(ts,&samp,1);
printf("samp.x = %d,samp.y = %d,samp.pressure = %d\n",samp.x,samp.y,samp.pressure);
if(samp.y>400&&samp.x<100&&samp.x>0&&samp.y>0)
{
return 0;
}
if(samp.y>0&&samp.y<240&&samp.x>700&&samp.x<800)
{
return 1;
}
if(samp.y>240 && samp.y<480 && samp.x>700 && samp.x<800)
{
return 2;
}
//划屏幕的起点
sub=samp.x;
ts_read(ts,&samp,1); //阻止在划屏时 触摸下一张
ts_read(ts,&samp,1);
if(samp.x && samp.pressure==0)
{
if(samp.x && samp.pressure==0)
{
printf("%d - %d = %d\n",samp.x,sub,samp.x-sub);
sub =samp.x-sub ;
if(sub>0) //左划
{
return 1;
}
if(sub<0) //右划
{
return 2;
}
}
}
}
}
//判断触摸的有效性
struct ts_sample ts_touch(int i)
{
struct tsdev *ts;
struct ts_sample samp;
int ret;
int sub=0;
//打开触摸屏
ts = ts_open(DEV_NAME,0);
if(ts == NULL)
{
printf("open ts failed!\n");
}
//配置触摸屏,配置插件
ret = ts_config(ts);
if(ret == -1)
{
printf("ts_config failed!\n");
ts_close(ts);
}
if(i==1)//判断触摸的有效性
{
while(1)
{
ts_read(ts,&samp,1);
if(samp.pressure==200)
{
ts_read(ts,&samp,1);
if(samp.pressure==0)
{
ts_read(ts,&samp,1);
if(samp.pressure==0)
{
printf("ok\n");
//输出触摸区域
return samp;
}
}
}
}
}
}
//弹字母 9个数字键 代表36个选择 点一个数字键 显示对应的4种选择
char tancuang(int i)
{
int j,k=4;
char AA[36]={"1ABC2DEF3GHI4JKL5MNO6PQR7STU8VWX9YZ0"};
char tan[40];
if(i==9)
k=3;
if(i==0)
{
sprintf(tan,"./setting/keyboard2/%c.bmp",AA[35]);
show_shape(g_fd_men,g_y*55+30,85,51,50,tan);
g_y++;
if(g_y==6)
g_y=0;
return AA[35];
}
--i;
for(j=0;j<k;j++)
{
sprintf(tan,"./setting/keyboard2/%c.bmp",AA[i*4+j]);
show_shape(g_fd_men,j*133 +50,150,51,50,tan);
}
j=ts_pw(8);
sprintf(tan,"./setting/keyboard2/%c.bmp",AA[i*4+j]);
show_shape(g_fd_men,g_y*55+30,85,51,50,tan);
g_y++;
if(g_y==6)
g_y=0;
return AA[i*4+j];
}
int ts_pw(int function)//N多功能触摸 按键确认
{
struct ts_sample samp;
int i=0,j=0,k=0;
if(function ==1) //数字密码判断
{
while(i<6)
{
samp=ts_touch(1);
printf("okkokokokoko \nsamp.x = %d,samp.y = %d,samp.pressure = %d\n",samp.x,samp.y,samp.pressure);
if(samp.x>20&&samp.x<620&&samp.y<460&&samp.y>230)//输入密码的有效位置
if(samp.y<340)
{ if(samp.x<150)
{
printf("1\n");
show_shape(g_fd_men, i*102 +20 ,40,100,100,"./setting/keyboard/1.bmp");
num[i]='1';
i++;
continue;
}
if(samp.x<270)
{
printf("2\n");
show_shape(g_fd_men, i*102 +20 ,40,100,100,"./setting/keyboard/2.bmp");
num[i]='2';
i++;
continue;
}
if(samp.x<380)
{
printf("3\n");
show_shape(g_fd_men, i*102 +20 ,40,100,100,"./setting/keyboard/3.bmp");
num[i]='3';
i++;
continue;
}
if(samp.x<500)
{
printf("4\n");
num[i]='4';
show_shape(g_fd_men, i*102 +20 ,40,100,100,"./setting/keyboard/4.bmp");
i++;
continue;
}
else
{
printf("5\n");
show_shape(g_fd_men, i*102 +20 ,40,100,100,"./setting/keyboard/5.bmp");
num[i]='5';
i++;
continue;
}
}
else
{
if(samp.x<150)
{
printf("6\n");
show_shape(g_fd_men, i*102 +20 ,40,100,100,"./setting/keyboard/6.bmp");
num[i]='6';
i++;
continue;
}
if(samp.x<270)
{
printf("7\n");
show_shape(g_fd_men, i*102 +20 ,40,100,100,"./setting/keyboard/7.bmp");
num[i]='7';
i++;
continue;
}
if(samp.x<380)
{
printf("8\n");
show_shape(g_fd_men, i*102 +20 ,40,100,100,"./setting/keyboard/8.bmp");
num[i]='8';
i++;
continue;
}
if(samp.x<500)
{
printf("9\n");
show_shape(g_fd_men, i*102 +20 ,40,100,100,"./setting/keyboard/9.bmp");
num[i]='9';
i++;
continue;
}
else
{
printf("0\n");
show_shape(g_fd_men, i*102 +20 ,40,100,100,"./setting/keyboard/0.bmp");
num[i]='0';
i++;
}
}
}
return 1;
}
if(function ==2) //登陆确认键
{
while(1)
{
samp=ts_touch(1);
printf("samp.x = %d,samp.y = %d,samp.pressure = %d\n",samp.x,samp.y,samp.pressure);
if(samp.x>620&&samp.y>230)
return 2;
}
}
if(function ==3) //相册 与 音乐 与 返回 按键确认
{
while(1)
{
samp=ts_touch(1);
printf("samp.x = %d,samp.y = %d,samp.pressure = %d\n",samp.x,samp.y,samp.pressure);
if(samp.x>111&&samp.y>130&&samp.x<340&&samp.y<300)
{
return 3;
}
if(samp.x>470&&samp.y>130&&samp.x<700&&samp.y<300)
{
return 4;
}
if(samp.y>350&&samp.x<150)
{
return 0;
}
}
}
if(function ==4) //测试触摸反应结果
{
while(1)
{
samp=ts_touch(1);
return 6;
}
}
if(function ==6)//音乐播放按键
{
while(1)
{
samp=ts_touch(1);
if(samp.y>350&&samp.x<150)
return 0;
if(samp.y>175&&samp.x>180&&samp.x<650&&samp.y<280)
{
if(samp.x<300)
return 1;
if(samp.x<420)
return 2;
if(samp.x<540)
return 3;
else
return 4;
}
}
}
if(function ==7)//验证码按键
{
while(i<6)
{
samp=ts_touch(1);
if(samp.x>20&&samp.x<620&&samp.y<460&&samp.y>230)//输入密码的有效位置
if(samp.y<340)
{ if(samp.x<150)
{
//弹窗
numm[i]=tancuang(1);
i++;
continue;
}
if(samp.x<270)
{
numm[i]=tancuang(2);
i++;
continue;
}
if(samp.x<380)
{
numm[i]=tancuang(3);
i++;
continue;
}
if(samp.x<500)
{
numm[i]=tancuang(4);
i++;
continue;
}
else
{
numm[i]=tancuang(5);
i++;
continue;
}
}
else
{
if(samp.x<150)
{
numm[i]=tancuang(6);
i++;
continue;
}
if(samp.x<270)
{
numm[i]=tancuang(7);
i++;
continue;
}
if(samp.x<380)
{
numm[i]=tancuang(8);
i++;
continue;
}
if(samp.x<500)
{
numm[i]=tancuang(9);
i++;
continue;
}
else
{
numm[i]=tancuang(0);
i++;
}
}
}
}
if(function ==8)//相框右侧 按键
{
samp=ts_touch(1);
if(samp.x>20&&samp.x<500&&samp.y<230&&samp.y>125)//输入密码的有效位置
{
if(samp.x<150)
{
return 0;
}
if(samp.x<270)
{
return 1;
}
if(samp.x<380)
{
return 2;
}
if(samp.x<500)
{
return 3;
}
}
}
}
void verification(void)//验证码生成与输入确认
{
int i,j=0;
char yz[6];
char v_bmp[6][40];
bzero(v_bmp,6*40);
char input_pasd[6];
//验证码式的警告
show_shape(g_fd_men,0,0,800,480,"./setting/warning2.bmp");
sleep(2);
show_shape(g_fd_men,0,0,800,480,"./setting/password.bmp");
srand((int)time(0));//设置时间种子
//生成随机的验证码 //在界面上生成对应的图片
while(j<6)
{
i = 1 + (int) (2.0 * rand() / (RAND_MAX + 1.0));
if(i==1)
{
i = 0 + (int) (9.0 * rand() / (RAND_MAX + 1.0));
yz[j]='0'+i;
}
if(i==2)
{
i = 0 + (int) (25.0 * rand() / (RAND_MAX + 1.0));
yz[j]='A'+i;
}
sprintf(v_bmp[j],"./setting/keyboard2/%c.bmp",yz[j]);
show_shape(g_fd_men, j*55+30, 30 ,51,50,v_bmp[j]);
j++;
}
printf("%s\n",yz);
i=0;
ts_pw(7);
stpcpy(input_pasd,numm); //接收触摸屏密码
if( ts_pw(2)==2 && (strcmp(yz,input_pasd)==0))//点击go,判断密码正确
{
usr_password();
}
else
verification();
}
int usr_password(void)//开机密码输入
{
int fd;
char ch;
char usrpasd[7];
char input_pasd[6];
int i=0;
//打开文件
fd = open(USR_PW,O_RDONLY);
if(fd == -1)
{
printf("open ps file failed!\n");
return -1;
}
read(fd,usrpasd,6);
usrpasd[6]='\0'; //若是不赋值零的话 他可能会以为字符没读完,而越界了
printf("usrpd = %s\n",usrpasd);
i=0;
while(1)
{
//输入密码页面
show_shape(g_fd_men,0,0,800,480,"./setting/password.bmp");
printf("please input passwd!\n");
ts_pw(1);
stpcpy(input_pasd,num); //接收触摸屏密码
printf("%s\n%s\n",usrpasd,input_pasd);
if( ts_pw(2)==2 && strcmp(usrpasd,input_pasd)==0 )//点击go,判断密码正确
{
sleep(1);
//登陆成功
printf("compare correct!\n");
//进入 电子相册 和 MP3 选择页面
picture_or_music();
break;
}
i++;
if(i==3)
{
//第三次输入错误,死机 或者 开启验证码输入
printf("you haven't no change input!\n");
//进入验证码模式
verification();
}
//输入错误警告
show_shape(g_fd_men,0,0,800,480,"./setting/warning.bmp");
sleep(1);
}
close(fd);
return 0;
}
void picture_or_music(void);
void picture(void)//电子相册 页面
{
int i,j;
//初始化链表
double_list head_list = init_list();
double_list new;
//读取路径导入到链表
i=dir(1);
if(i==-1)
{
printf("picture read dir fail\n",i);
}
for(i-=1;i>=0;i--)//插入链表
{
new = init_list();
stpcpy(new->bmpp,bmp[i]);
printf("%s\n",new->bmpp);
insert_node(new,head_list);
}
if(g_x==1)//相册介绍使用教程
{
show_shape(g_fd_men,0,0,800,480,"/coolAlbum/setting/picture.bmp");
sleep(1);
}
double_list p =head_list->next;
show_shape(g_fd_men,0,0,800,480,p->bmpp);
while(1)
{
j=ts_row();//判断滑动状态
g_x=0;
if(j==1)
{
p = p->prev;
if(p==head_list)//判断是不是头节点 因为头节点没有数据
p=p->prev;
show_shape(g_fd_men,0,0,800,480,p->bmpp);
}
if(j==2)
{
p = p->next;
if(p==head_list)
p=p->next;
show_shape(g_fd_men,0,0,800,480,p->bmpp);
}
if(j==0)
{
picture_or_music();
}
}
}
void mp3(void)//音乐播放页面
{
int i,j,x,z=0;
//初始化链表
double_list head_list = init_list();
double_list new;
//读取路径导入到链表
i=dir(2);
if(i==-1)
{
printf("picture read dir fail\n",i);
}
printf("i=%d\n",i);
for(i-=1;i>=0;i--)
{
new = init_list();
stpcpy(new->bmpp,mmp3[i]);
printf("------%s----\n",new->bmpp);
insert_node(new,head_list);
}
show_shape(g_fd_men,0,0,800,480,"/coolAlbum/setting/music.bmp");
double_list p =head_list;
while(1)
{
j=ts_pw(6);
if(j==1)
{
//上一首
system("killall -KILL madplay\n");
p = p->prev;
if(p==head_list)
p=p->prev;
system(p->bmpp);
}
if(j==2)
{
p = p->next;
system("killall -STOP madplay&\n"); //停止音乐
z=1;
}
if(j==3)
{
//system(p->bmpp); //启动音乐
if(z==0)
system("madplay /coolAlbum/music/sd.mp3&\n"); //启动音乐
if(z==1)
system("killall -CONT madplay&\n"); //继续播放
}
if(j==4)
{
//下一首
system("killall -KILL madplay\n");
p = p->next;
if(p==head_list)
p=p->next;
printf(" %s\n ",p->bmpp);
system(p->bmpp);
}
if(j==0)
{
picture_or_music();
}
}
}
void picture_or_music(void) //触摸选择 电子相册 MP3 返回
{
int i;
//加载登陆后的图片 带返回
show_shape(g_fd_men, 0,0,800,480,"./setting/picture_or_mp3.bmp");
i=ts_pw(3);//触摸选择区域 电子相册 MP3 返回
if(3== i)
{
picture();
}
if(4== i)//进入MP3
{
mp3();
}
if(0== i)//返回到输入页面
{
usr_password();
}
}
int main(void)
{
int i=10;
lcd_init(); //屏幕初始化
show_shape(g_fd_men,0,0,800,480,"./setting/logo.bmp");//开启画面
system("madplay /coolAlbum/music/sd.mp3&\n"); //开机音乐
sleep(3);
usr_password();//密码输入
lcd_uninit();
return 0;
}