[Linux]基于SQLite数据库的停车管理系统

文章目录

  • 1 项目描述
  • 2 项目需求
  • 3 搭建环境
  • 4 技术描述
  • 5 概要设计
  • 6 主界面
  • 7 入场与出场
  • 8 月卡系统
  • 9 已入场车辆
  • 10 监控
  • 11 项目总结

1 项目描述

本次项目是基于Linux环境的交叉编译arm-linux-gcc,在GEC6818arm开发板上运行,通过摄像头监控,RFID模块识别卡号,判断该卡是否为月卡or临时卡,车辆入场or出场,记录或显示收费金额与车辆信息。运用SQLite数据库,创建表格存取月卡用户信息与出入车辆相关信息。增加语音播报功能,使项目更加人性化…

2 项目需求

(1)创建一个数据库, 内置你需要的所有信息, 如车牌信息、RFID卡信息、卡类、进场时间、车辆照片名等
(2) 在默认状态下,视频监控是处于打开状态的,并循环录制,1分钟视频,保存到本地。
(3)当检测到有RFID卡,关闭视频流,判断当前数据库中是否有该卡的入场信息:
如果已有该卡的入场信息,表示现在是出场;则直接计算出当前时间和入场时间差值,在屏幕上显示该车辆照片,显示车辆信息和应收费金额,停车总时间
如果没有该卡的入场信息,则在数据库中增加该车辆信息,并记录当前时间且拍照。
在检测到RFID卡3秒后 (alarm() SIGALRM信号), 系统会恢复打开视频流
(4)当车辆刷卡进场是,语音提示卡号,并说明卡的类别(临时卡,或包月卡),出场提示:费用与月卡剩余天数
(5)管理功能,负责把卡的类别进行修改,与数据库中的数据进行修改。
(6) 自行扩展: 添加一些自主功能。
(7)强测试代码,把BUG 去掉!!!!

3 搭建环境

开发环境:
Linux
开发工具:
arm-linux-gcc、Notepad++
其他工具:
SQLite数据库、MIFARE522、ffmpeg库、V4l2编程、ALSA库、mplayer开源多媒体库、jpeglib库、font库、讯飞语音
编程实现
通过开源代码编译器notepad++编写代码,利用arm-linux-gcc交叉编译,再通过LINUX平台的SSH服务器将编译生成的程序文件传输到开发板中,最后执行。

SQLite数据库
SQLite是目前最流行的开源嵌入式数据库,和很多其他嵌入式存储引擎相比(NoSQL),如
BerkeleyDB、MemBASE等,SQLite可以很好的支持关系型数据库所具备的一些基本特征,如标准SQL语法、事务、数据表和索引等。事实上,尽管SQLite拥有诸多关系型数据库的基本特征,然而由于应用场景的不同,它们之间并没有更多的可比性。
部分代码指令:

往表格中插入数据

语法格式: 
INSERT INTO [数据库名称].表名 VALUES(记录内容)
INSERT INTO [数据库名称].表名(字段列表) VALUES(对应字段内容)
例子:往一个表格中插入数据  (一次插入) 
insert   into  my_table  values("2019661130");
//指定字段的顺序 
insert into  my_table2(age,id)   values(123456,987654);

查询

查询表格中的数据 
select * from table; 
查找数据的多种方式:   
按照字段去查找数据: 
select  字段名  from  表明;   //只找出该字段的内容  
根据条件去找数据:  
select  字段名  from  表明  where  条件; //安装条件去找该字段中的数据 
select *  from my_table3  where  id=123;   //找到ID 为 123的所有数据。   
 多条件查询:
select 字段名  from 表明  where  条件1  or  条件2;   //或
select *  from my_table3  where  id=123 or id=456;  //找出表格中 id 为 123 或 456 的数据

修改

更新数据库中的数据:  
UPDATE [数据库名称].表名 SET 字段 1=字段 1 值,字段 2=字段 2 值… where 条件表达式
例子:更新ID 信息
update my_table3 set id=10086  where id=123; 

删除

删除整个表格; 
DROP TABLE  表名;
DROP TABLE tbl_student_info
删除表格中的数据:   
DELETE FROM [数据库名称].表名 where 条件表达式 
例子:删除表格中的数据  
delete from  my_table3   where  id = 123; 

MIFARE522
RFID模块:本模块以命令——响应的方式工作,在系统中模块是处于从属地位,不会主动发出数据(自动检测卡片除外)。通常主机首先发出命令,然后等待模块响应。
实体图如下:[Linux]基于SQLite数据库的停车管理系统_第1张图片
ffmpeg库:
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。
FFmpeg在Linux平台下开发,但它同样也可以在其它操作系统环境中编译运行,包括Windows、Mac OS X等。

V4l2编程:
V4L2(Video For Linux Two) 是内核提供给应用程序访问音、视频驱动的统一接口。V4L2 的相关定义包含在头文件 中.
本次项目中利用官方V4L2接口对摄像头进行解码,每一帧生成JPG图片,摄像头实体图如下:
[Linux]基于SQLite数据库的停车管理系统_第2张图片

其他工具和库:
参考此篇(3 搭建环境):ALSA库、mplayer开源多媒体库、jpeglib库、font库、讯飞语音

4 技术描述

基本:

  • C语言
  • 文件IO
  • 系统编程
  • Mplayer指令
  • 触摸屏
  • font库的使用
  • jpeglib库的使用
  • 链表
  • JOSN数据处理
  • 语音识别
  • ALSA库

核心

  • SQLite数据库
  • v4l2编程(摄像头信息采集)
  • ffmpeg库(视频合成)
  • RFID

5 概要设计

整体项目框架设计图如下:
[Linux]基于SQLite数据库的停车管理系统_第3张图片

6 主界面

主要实现:
1.准备入场车辆链表头节点,当车辆入场时,链表节点保存入场图片
2.打开数据库,创建表格:(1)入场车辆;(2)月卡信息
3.初始化摄像头,开启捕捉,实时监控
4.打开串口RFID模块,实时等待读取卡号
5.打开触摸屏,实现其他界面跳转
具体效果和代码如下:
实体效果

部分代码

struct double_list  *head  = malloc(sizeof(struct double_list));   //已入场车辆相册头节点
						 head->next = head;  
						 head->prev = head;  
						head->pic_name[200]=0;
	 //打开数据库
	int ret=sqlite3_open("./my.db",&sql);

	//创建表格:车牌信息,、RFID卡信息、卡类、进场时间、车辆照片名
	char *sql_cmd="create table my_table(car_id text primary key,card_id text unique,card_style text,date text,car_photo text);";
    ret=sqlite3_exec(sql,sql_cmd,NULL,NULL,NULL);
	if(ret==SQLITE_ERROR){printf("表格已经存在\n");}
    else if(ret==SQLITE_OK){printf("表格创建成功\n");	}
    	
	//创建表格..月卡数据库:车牌信息,、RFID卡信息、车主名字,注册月份,注册日期;
	char *sql_cmd1="create table month_card(car_id text primary key,card_id text unique,name text,month int(3),day int(3));";
    ret=sqlite3_exec(sql,sql_cmd1,NULL,NULL,NULL); 
	
	struct jpg_data video_buf;
	//定义结构体变量
	lcd_open();
	mmap_lcd();
	linux_v4l2_yuyv_init("/dev/video7");	//初始化摄像头
	linux_v4l2_start_yuyv_capturing();    	//开启摄像头捕捉
	
	pthread_create(&tid,NULL,get_card_id,NULL);//读卡
	pthread_create(&tid1,NULL,get_video,NULL);//监控
	pthread_create(&tid2,NULL,get_time,NULL);//当前时间
    lcd_fd=open("/dev/input/event0",O_RDWR);//打开触摸屏
	
	int video_open=0;//摄像头标志位

	while(1)
	{
	    show_pohoto("jiemian.bmp");//显示界面
		while(1)
		{
			read(lcd_fd,&xy,sizeof(xy));
			if(xy.type == EV_ABS  && xy.code == ABS_X ) //处理信息  {x=xy.value;}
			if(xy.type == EV_ABS  && xy.code == ABS_Y)	{y=xy.value;	 }	
			
			if(xy.type == EV_KEY && xy.code == BTN_TOUCH && xy.value == 0)
				{	 
					if(y>315 &&y<360 && x>640 && x<800)//摄像头开关
					{
						if(video_open==0)//关闭摄像头
						{
							//...省略
						}
						else if(video_open==1)打开摄像头
						{
						   //...省略
						}
					}
					if(y>60 &&y<110 && x>640 && x<800)//月卡管理系统
					{
					   //...省略
					}
			        if(y>145 &&y<195 && x>640 && x<800)//相册:显示已入场车辆
					{
                       //...省略
			        }
					if(y>230 &&y<280 && x>640 && x<800)//显示备份视频
					{
					  //...省略
					}
				}
		}
	}
	pthread_join(tid,NULL);
	return 0;

7 入场与出场

主要实现
创建线程,实时监测RFID模块状态,当有卡靠近时,读取卡号,先判断该卡号为临时卡还是月卡用户且过期与否,再判断该卡号车辆入场还是出场。根据不同的情况实现不同功能。具体过程如下图:
[Linux]基于SQLite数据库的停车管理系统_第4张图片
实体效果
月卡出场
[Linux]基于SQLite数据库的停车管理系统_第5张图片
临时卡出场
[Linux]基于SQLite数据库的停车管理系统_第6张图片
部分代码

while(1)
	{
	           //...省略部分读取卡号过程
				printf("该卡号为=%x\n",cardid); 
				//转换类型
				char buf[24]="0";
				sprintf(buf,"%x",cardid);
			
				int a=seek_card(buf);//判断数据库是否已存在卡号						
				if(a == 0)//数据库中无改卡号,为入场
				{
					int month_tmp=decide_card(buf);//判断该卡是否为月卡
					if(month_tmp == 1)//1为月卡
					{
						monthcard_day=decide_day(buf);//判断该月卡是否过期
						printf("注册总天数:%d\n",monthcard_day);
						if(monthcard_day<=30)//月卡未过期
						{			
							char *month_chepai=get_chepai(buf,"month_card");//获取月卡车牌号
							strcpy(chepai,month_chepai);
							printf("该月卡的车牌号为:%s\n",month_chepai);	
							add_message(month_chepai,buf,"月卡");//信息添加进数据库
			                sprintf(sound,"车牌%s,月卡为%s已录入,入场成功",month_chepai,buf);
							make_wav(sound);//语音播报	
							get_picture_flag = 1;//标志位,实现抓拍					
						}
						else
						{
                            make_wav("该月卡已经过期,请续费");
                            sleep(3);							
							month_tmp=0;
						}
					}
					if(month_tmp==0)//0为临时卡
					{
						printf("请输入车牌号:\n");
						make_wav("您使用的为临时卡,请输入车牌号");
						scanf("%s",chepai);
						add_message(chepai,buf,"临时卡");//入场信息添加进数据库				
						get_picture_flag = 1;//标志位,实现抓拍						
					}
				}	
			
				else if(a==1)//数据库中已经存在该卡号,为出场
				{
					char show_card[16];//月卡或临时卡									
					int add_min=count_min(buf);//获取停车总时间
					printf("停车时长为%d分钟\n",add_min);					
					int card_type=get_cardtype(buf);//查看数据库中卡的类型			
					if(card_type==1)//月卡计费每分钟0.2元
					{		
                        printf("月卡计费每分钟0.2元\n");
                        strcpy(show_card,"月卡");						
						money=0.2*add_min;//计算总费用	
					}
					else//临时卡计费每分钟0.3元
					{
						printf("临时卡计费每分钟0.3元\n");
						strcpy(show_card,"临时卡");
						money=0.3*add_min;//计算总费用
					}					
					printf("共需要缴纳金额为%0.2f元\n",money);

					get_picture_card=1;//标志位 暂停监控,显示车辆出场信息
					usleep(200000);
					//===============================图片显示=============================
					//printf("\n");
					show_pohoto("chefei.bmp");//显示计费图片									
					char *out_chepai=get_chepai(buf,"my_table");//出场卡号的车牌号
					printf("车牌为:%s\n",out_chepai);								
					sprintf(tmp,"/mnt/sd/protect3/tingchechang/%s.jpg",out_chepai);
					lcd_draw_jpg(0,0,tmp);//显示车辆图片

					//===============================字库显示=============================
					show_date(out_chepai,640,45);//车牌号
					show_money(money,660,180);//金额
					show_time(add_min,660,100);//停车总时长
					show_date(show_card,640,230);//卡类型

					//===============================语音播报=============================
					if(strcmp(show_card,"月卡")==0)
					{
						monthcard_day=decide_day(buf);//判断该月卡是否过期
						monthcard_day=30-monthcard_day;
						printf("月卡剩余天数:%d\n",monthcard_day);
						
						sprintf(sound,"停车时长%d分钟,共%0.2f元,月卡剩余天数为%d天",add_min,money,monthcard_day);
						make_wav(sound);						
					}
					else
					{		
						sprintf(sound,"停车时长%d分钟,共%0.2f元,为临时卡",add_min,money);
						make_wav(sound);					
					}

					//===============================删除数据=============================
					delete_message(buf);//从数据库中删除该车辆信息			
					sprintf(delete_pic,"rm %s",tmp);//删除车牌图片
					system(delete_pic);					
				}
								
			}	
			else
			{
				printf("读卡失败\n");
				make_wav("读卡失败");
				
			}			
			sleep(2);		
		
	}

8 月卡系统

主要实现:(增删查改)
1.当用户想要登入月卡系统时,进入语音识别(程序设定好特定语句),只有用户念出指定口令才能登入系统,口令错误则无法登陆
2.登入系统后,程序从数据库月卡表格中读取并显示所有月卡用户信息(车牌号、卡号、用户名、注册时间)
3.增加用户:用户输入车牌号与注册时间,将信息录入月卡表格中
4.删除用户:输入用户名,删除月卡表格中该用户的所有信息
5.续费:输入用户名,若为月卡用户则继续输入续费时间,更新表格中该用户信息
6.修改用户资料:输入用户名,若为月卡用户则重新输入车牌号、卡号或用户名更新表格中该用户信息
具体效果和代码如下:
实体效果
[Linux]基于SQLite数据库的停车管理系统_第7张图片
部分代码

int monthcard_system()//月卡管理系统
{
	printf("\n");
	show_pohoto("system.bmp");

	p=speech_recognition();//语音识别,返回字符串地址
	printf("%s\n",p);
	
	if(strcmp(p,"你打球真像蔡徐坤")!=0 )
	{
		make_wav("口令错误");
		return 1;
	}
	make_wav("口令正确,成功登陆");
	while(1)
	{
		all_card();//字库显示所有月卡的用户信息
		while(1)
		{
			read(lcd_fd,&xy,sizeof(xy));
			 //处理信息  
			if(xy.type == EV_ABS  && xy.code == ABS_X ){x=xy.value;}
			if(xy.type == EV_ABS  && xy.code == ABS_Y) {y=xy.value;}	
			if(xy.type == EV_KEY && xy.code == BTN_TOUCH && xy.value == 0)
			{	 
				 printf("x=%d,y=%d\n",x,y);
				if(y>60 &&y<110 && x>640 && x<800)//增加用户
				{ 	
                    show_system("\n\n请依次录入需要注册月卡用户的信息:\n  (车牌 卡号 名字 注册月 注册日)",65,65,40);				
					printf("请依次录入需要注册月卡用户的信息:(车牌 卡号 名字 注册月 注册日)\n");
					scanf("%s %s %s %s %s",car,card,name,month,day);
					add_month_system(car,card,name,month,day);//将用户信息添加进数据库	
				    break;	
				}
		        if(y>140 &&y<190 && x>640 && x<800)//删除用户
				{
					printf("请输入需要删除的用户名:\n");
					show_system("\n\n--请输入需要删除的用户名--",65,65,55);
					scanf("%s",tmp_name);
					delete_month_system(tmp_name);//将用户信息从数据库中删除
					break;				
				}
				if(y>230 &&y<280 && x>640 && x<800)//续费
				{			
					printf("请输入需要续费的用户名\n");
					show_system("\n\n-请输入需要续费的用户名-",65,65,55);
					scanf("%s",tmp_name);
					int num=decide_name(tmp_name);//判断月卡数据库中是否存在该用户
					if(num==1)//月卡系统中有该用户
					{
						printf("请分别输入续费的月、日\n");
						show_system("\n\n-请分别输入续费的月、日-",65,65,55);
						scanf("%s %s",month,day);
                        update_month_system(month,day,tmp_name);//续费
						break;
					}
					else if(num==0)//月卡系统中无该用户,跳出重新注册
					{
					    show_system("\n\n       ---系统无该用户---",65,65,60);
						sleep(2);							
					    break;
					}			
				}
				if(y>315 &&y<365 && x>640 && x<800)//修改资料
				{
					printf("请输入需要修改资料的用户名\n");								
					scanf("%s",tmp_name);
					int num=decide_name(tmp_name);//判断月卡数据库中是否存在该用户
					if(num==1)//月卡系统中有该用户
					{
					    show_system("\n\n请依次录入需要修改的用户信息:\n     (车牌 卡号 名字 )",65,65,40);				
					    printf("请依次录入需要修改的用户信息:(车牌 卡号 名字)\n");
					    scanf("%s %s %s",car,card,name);
					   	update_system(car,card,name,tmp_name);//更新信息
						break;			
					}
					else if(num==0)//月卡系统中无该用户,跳出重新注册
					{
					    show_system("\n\n       ---系统无该用户---",65,65,60);
						sleep(2);							
					    break;
					}			
				}
		       if(y>425 &&y<480 && x>725 && x<800)//返回监控
				{
	                return 1;
				}
			}
    	}
	}
}

9 已入场车辆

主要实现
获取车辆入场时拍下的图片保存进节点,实现左右滑动查看入场车辆与相应车牌号。再与月卡系统中的数据对比,若入场车辆为月卡用户则显示出车主照片。
具体效果和代码如下:
实体效果
[Linux]基于SQLite数据库的停车管理系统_第8张图片
部分代码

int show_pic(struct double_list *head)//相册:显示已入场车辆
{
	DIR *dir_p=opendir("/mnt/sd/protect3/tingchechang");//打开照片目录
	struct dirent *msg;								
    while(msg=readdir(dir_p))//遍历目录内的文件
	{
		if( strstr(msg->d_name,".jpg")!=NULL)
		{
			inser_list(head,msg->d_name);//将目录中的视频名字依次保存在节点中
		}	
	}
	if(head->next==head)
	{
		make_wav("车场无车辆");
		return 1;
	}
	char buf[24];//语音播报车库中有多少辆车
	sprintf(buf,"停车场中有%d辆车",len);
	make_wav(buf);//语音播报
	show_pohoto("bili.bmp");//显示界面
	struct double_list  *tmp =  head->next;
	int xx,yy,xxx,yyy;  
	char tmp_buf[64];
	sprintf(tmp_buf,"/mnt/sd/protect3/tingchechang/%s",tmp->pic_name);
	lcd_draw_jpg(0,0,tmp_buf);//显示车辆图片
	strcpy(tmp_buf,tmp->pic_name);
	strtok(tmp_buf,".");
	show_date(tmp_buf,640,50);//字库显示车牌
	seek_chepai(tmp_buf);//判断显示车辆车主图片
	while(1)
		{
			while(1)
			{		
		        read(lcd_fd,&xy,sizeof(xy));
				 //处理信息  
				if(xy.type == EV_ABS  && xy.code == ABS_X ){x=xy.value;}
				if(xy.type == EV_ABS  && xy.code == ABS_Y) {y=xy.value;}	
			    if(xy.type == EV_KEY && xy.code == BTN_TOUCH )															
				{												
			 		if( xy.value == 1)  
				    {						
						 xx = x;
						 yy = y;					
				    }       								    
                    else
					{						
						if(y>420 &&y<480 && x>720 && x<800)//退出
						{
                            delete_list(head);                   
						    return 1;							
						} 
						xxx=x-xx;
						yyy=y-yy;						
						break;
					}				
				}
	        }							
			if(yyy>=-30&&yyy<=30&&xxx>20)  //向右滑动,下一张图片
			{	
				tmp=tmp->next;								 
				if(tmp==head)
				{
					tmp=tmp->next;
				}
                sprintf(tmp_buf,"/mnt/sd/protect3/tingchechang/%s",tmp->pic_name);
				lcd_draw_jpg(0,0,tmp_buf);//显示车辆图片
				strcpy(tmp_buf,tmp->pic_name);
				strtok(tmp_buf,".");
				show_date(tmp_buf,640,50);
				seek_chepai(tmp_buf);//判断显示车辆车主图片
			}
			if(yyy>=-30&&yyy<=30&&xxx<-20)  //向左滑动,上一张图片
			{		
				tmp=tmp->prev;					 
				if(tmp==head)
				{
					tmp=tmp->prev;														 
				} 
				sprintf(tmp_buf,"/mnt/sd/protect3/tingchechang/%s",tmp->pic_name);
				lcd_draw_jpg(0,0,tmp_buf);//显示车辆图片	
                strcpy(tmp_buf,tmp->pic_name);
				strtok(tmp_buf,".");
				show_date(tmp_buf,640,50);
				seek_chepai(tmp_buf);//判断显示车辆车主图片
			}		
		}
}

10 监控

主要实现
通过VAL2摄像头截取每一帧图片,保存到目录中,当截取的图片数量达到500张时,利用ffmpeg指令将所有图片合成视频,当用户进入监控界面时,利用Mplayer指令播放该合成的视频,实现监控功能。
具体效果和代码如下:
实体效果
[Linux]基于SQLite数据库的停车管理系统_第9张图片
部分代码

录制视频

//=========================================录制视频====================================
		    //创建一个新的文件
			bzero(picture, 20);
			
			
			sprintf(picture, "%d.jpg",a);
			
			fd = open(picture, O_RDWR | O_CREAT, 0777);
			if(-1 == fd)
			{
				perror("create jpg failed");
				continue;
			}
			//保存图片
			write(fd, video_buf.jpg_data, video_buf.jpg_size);			
			close(fd);	
		    sprintf(buf,"mv %s /mnt/sd/protect3/video_jpg",picture);//每一帧图片移动到指定文件夹		   	
		    system(buf);
		    
		    a++;
			if(a==500)//当保存500张图片时,将所有图片合成视频
			{
				printf("视频合成中\n");
				system("rm video.avi");//删除前一分钟录制的视频,防止系统提示是否删除,是程序能通畅执行
				system("ffmpeg -f image2 -i /mnt/sd/protect3/video_jpg/%d.jpg video.avi");//ffmpeg合成视频指令
				printf("视频合成完毕\n");	
               a=1;				
			}	

显示视频

 int show_video()//显示备份视频
    {
    	pid_t pid;
    	pid =fork();
    	if(pid == 0)  //子进程
    	{	
    		printf("\n");
    		show_pohoto("shiping.bmp");	
                	
    		int fd = open("/pipe1",O_RDWR);//打开通信的管道文件
    		if(fd < 0)
    		{
    			perror("fail:");
    			exit(0); //退出进程
    		}
    		dup2(fd,1);//重定向标准输出设备描述符 
    		//=======进行触摸屏操作========
    		pthread_t tid3;
    		pthread_create(&tid3,NULL,finger,NULL);
    	    pthread_detach(tid3);						
    	    system("mplayer -slave -quiet -input  file=/pipe  -geometry  0:0 -zoom -x 750 -y 410   /mnt/sd/protect3/video.avi"); 
    		
    	}	         		
        wait(NULL);
    }

11 项目总结

此次项目主要考验对SQLite数据库增删查改的使用,视频监控的录制,RFID读卡,摄像头截取图片,ffmpeg指令,字符串的精确提取,停车时间的计算…
在获取网络时间中,提取JOSN数据中指定数据花费了较多时间…
对出入场时间的计算也是一个较为复杂的过程(运用较多切割函数strtok)…
多次运用了提取数据库信息的函数…
在图片截取与视频录制合成过程中需要避免其他因素干扰…

你可能感兴趣的:(项目)