公交卡系统

一、设计目标

该公交刷卡项目利用GEC6818开发板、读卡器、卡片实现一个功能强大,性能稳定、安全可靠、用户界面友好,便于管理的公交卡管理系统,为用户提供便捷的公交出行服务,同时也为后台管理提供高效的管理工具。

二、功能描述

(1)点击首界面的刷卡缴费系统,然后进行公交刷卡,刷卡成功后,蜂鸣器“滴”一声提示;

(2)首界面左下角是查询公交卡的消费记录与支出记录的按键,可以了解充卡与支出金额的记录;

(3)点击首界面后台管理系统,触屏输入账号与密码登录该系统后,可以进行充值,金额充值到公交卡里;

(4)后台管理系统可以修改乘车缴费金额。

三、设计方案

本设计方案旨在构建一个公交卡设备系统,选用RFID读卡器作为刷卡设备,能够快速准确读取公交卡信息,设计合理的数据库表结构,包括公交卡表(卡号、余额)、消费记录等信息,实现功能完善、安全可靠的公交卡系统。

四、系统框架

五、部分源码

font.c

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

#include "font.h"
#include "font_libs.h"

static int *tmp;
static int lcd_width;
static int lcd_height;

void Font_init(void *fb_addr,int w,int h)
{
	tmp = (int *)fb_addr;
	lcd_width = w;
	lcd_height = h;
}

//画黑色方框,X Y 起点坐标,width宽度,height高度
int  Create_LineEdit(int X,int Y,int width,int height,unsigned long color)
{
	int x,y;

	for(y=Y;y<Y+height && y<lcd_height;y++)
	{
		for(x=X;x<X+width && x<lcd_width;x++)
		{				
			tmp[y*lcd_width+x]  = color;
		}

	}	
	
	return 0;		
}

//区域填充color,X Y 起点坐标,width宽度,height高度
int  Clean_Area(int X,int Y,int width,int height,unsigned long color )
{
	int x,y;

	for(y=Y;y<Y+height && y<lcd_height;y++)
	{
		for(x=X;x<X+width && x<lcd_width;x++)
		{				
			tmp[y*lcd_width+x]  =  color;
		}

	}	
	
	return 0;		
}

/**画点***/
int  Draw_Text16(unsigned int x,unsigned int y,unsigned long color,const unsigned char ch[])
{
	unsigned short int i,j;
	unsigned char mask,buffer;

	for(i=0;i<16;i++)
	{
		mask =0x80;				//掩码
		buffer =ch[i*2];		//提取一行的第一个字节
		for(j=0;j<8;j++)
		{
			if(buffer &mask)
			{
				tmp[(y+i)*lcd_width+x+j]= color;	//为画笔上色
			}
			mask =mask >>1;
		}
		mask =0x80;
		buffer =ch[i*2+1];
		for(j=0;j<8;j++)
		{
			if(buffer &mask)
			{
				tmp[(y+i)*lcd_width+x+j+8]= color;
			}
			mask =mask>>1;	
		}		
	}
	
	return 0;
}

int  Draw_TextX(unsigned int x,unsigned int y,unsigned long color,const unsigned char ch[],int size)
{
	unsigned short int i,j,k,m;
	unsigned char mask,buffer;
	
	for(i=0;i<16;i++)
	{
		mask =0x80;				//掩码
		buffer =ch[i*2];		//提取一行的第一个字节
		for(j=0;j<8;j++)
		{
			if(buffer &mask)
			{
				for(k=0;k<size;k++)	
			  	{
			  		for(m=0;m<size;m++)
			  		{
					  tmp[(y+i*size+m)*lcd_width+x+j*size+k]= color;
			  		}
			  	}
			}
			mask =mask >>1;
		}
		mask =0x80;
		buffer =ch[i*2+1];
		for(j=0;j<8;j++)
		{
			if(buffer &mask)
			{
				for(k=0;k<size;k++)
			  	{	
					for(m=0;m<size;m++)
			  		{	
					   tmp[(y+i*size+m)*lcd_width+x+(j+8)*size+k]= color;
			  		}
			  	}
			}
			mask =mask>>1;	
		}		
	}

	return 0;
}

int  Draw_ASCII(unsigned int x,unsigned int y,unsigned long color,const unsigned char ch[])
{
    unsigned short int i,j;
    unsigned char mask,buffer;
 
    for(i=0;i<16;i++)
    {
        mask=0x80;
        buffer=ch[i];
        for(j=0;j<8;j++)
        {                   
            if(buffer&mask)
            {
                tmp[(y+i)*lcd_width+(x+j)]= color;
            }
            mask=mask>>1;                   
        }
    }

	return 0;
}

int  Draw_ASCIIX(unsigned int x,unsigned int y,unsigned long color,const unsigned char ch[],int size)
{
	unsigned short int i,j,k,m;
	unsigned char mask,buffer;

	for(i=0;i<16;i++)
	{
		mask=0x80;
		buffer=ch[i];
		for(j=0;j<8;j++)
		{                   
			if(buffer&mask)
			{
				for(k=0;k<size;k++)
				{
					for(m=0;m<size;m++)
					{
						tmp[(y+i*size+m)*lcd_width+(x+j*size+k)]= color;
					}
				}
	
			}
			mask=mask>>1;                   
		}
	}
	
	return 0;
}

//显示字符,中文的函数
int  Display_character(unsigned int x,unsigned int y,unsigned int len,unsigned char *string,unsigned long color)
{
	int k, xx;
	unsigned char qh,wh;
	const unsigned char *mould;
	unsigned int length =len;
	
	for(k=0,xx=x;k<length-1;k++)
	{
		if(string[k]&0x80)   //中文字符
		{
			qh =string[k]-0xa0;			//区号
			wh =string[k+1]-0xa0;		//位号
			mould =&__CHS[((qh-1)*94+wh-1)*32];
			Draw_Text16(4+xx,y,color,mould);
			xx+=16;
			k++;
		}
		else
		{
			mould =&__ASCII[string[k]*16];
			Draw_ASCII(4+xx,y,color,mould);
			xx+=8;
		}
	}
	
	return 0;
}

int  Display_characterX(unsigned int x,unsigned int y,unsigned int len,unsigned char *string,int size,unsigned long color)
{
	int k, xx;
	unsigned char qh,wh;
	const unsigned char *mould;
	unsigned int length =len;
	
	for(k=0,xx=x;k<length-1;k++)
	{
		if(string[k]&0x80)   //中文字符
		{
			qh =string[k]-0xa0;			//区号
			wh =string[k+1]-0xa0;		//位号
			mould =&__CHS[((qh-1)*94+wh-1)*32];
			Draw_TextX(4*size+xx,y,color,mould,size); //加4为了让每个中文之间有一定的间隙
			xx+=16*size;//当前的中文字模为32*32,每次显示下一个中文时横向偏移32个bit
			k++; //加载下一个中文,两次++操作,偏移2个字节
		}
		else
		{
			mould =&__ASCII[string[k]*16];
			Draw_ASCIIX(4*size+xx,y,color,mould,size);
			xx+=8*size;//当前的ASCII字模显示为8*16,每次显示下一个中文时横向偏移8个bit
		}
	}
	return 0;
}

int  Display_characterXX(unsigned int x,unsigned int y,unsigned int len,unsigned char *string,int size,unsigned long color)
{
	int k, xx;
	unsigned char qh,wh;
	const unsigned char *mould;
	unsigned int length =len;
	
	for(k=0,xx=x;k<length-1;k++)
	{
		if(string[k]&0x80)   //中文字符
		{
			qh =string[k]-0xa0;			//区号
			wh =string[k+1]-0xa0;		//位号
			mould =&__CHS[((qh-1)*94+wh-1)*32];
			Draw_TextX(4*size+xx,y,color,mould,size); //加4为了让每个中文之间有一定的间隙
			xx+=16*size;//当前的中文字模为32*32,每次显示下一个中文时横向偏移32个bit
			k++; //加载下一个中文,两次++操作,偏移2个字节
		}
		else
		{
			mould =&__ASCII[string[k]*16];
			Draw_ASCIIX(4*size+xx,y,color,mould,size);
			xx+=8*size;//当前的ASCII字模显示为8*16,每次显示下一个中文时横向偏移8个bit
		}
	}
	return 0;
}

/*
int Roll_Dispaly(unsigned char *str)
{
	int x;
	
	for(x=600;x>20;x--)
	{
	  Display_characterXX(x,45,strlen(str)+1,str,4,0xFF0000);
	  usleep(50000);
	  Display_characterXX(x+1,45,strlen(str)+1,str,4,0xFFFFFFFF); 
    }
	
	Display_characterXX(x+1,45,strlen(str)+1,str,4,0xFFFFFFFF);
	
	return 0;
}

*/

demo2.c

/*


C语言代码实现了基于SQLite数据库的公交卡管理功能,包括打开数据库连接、创建表、插入、查询和更新公交卡记录。下面是各部分详细解释:

BusCard 结构体定义了公交卡的基本属性:card_id 和 balance 分别代表公交卡的唯一标识和当前余额。

open_database 函数负责打开或创建名为 db_name 的SQLite数据库,返回值指示操作是否成功。如果打开失败,则打印错误信息并返回非零错误码;否则输出提示信息并返回0。

create_table 函数创建名为 BusCards 的表,包含 CardID 和 Balance 两列,其中 CardID 是主键。使用 sqlite3_exec 执行SQL创建表语句。

insert_card 函数负责向数据库中插入一条公交卡记录。它使用预编译的SQL语句,通过 sqlite3_prepare_v2 准备SQL插入语句,并通过 sqlite3_bind_... 函数绑定相应的参数值。执行插入操作后,根据返回状态打印插入结果。

query_card 函数根据给定的 card_id 从数据库中查询公交卡记录,并将查询结果填充到 BusCard 结构体中返回。同样使用预编译SQL查询语句和参数绑定,根据查询结果的不同状态输出信息。

update_card_balance 函数用于更新公交卡在数据库中的余额。同样采用预编译SQL更新语句,根据公交卡ID更新对应的余额值。

main 函数中,按照上述功能顺序组织了一系列操作:打开数据库 -> 创建表 -> 插入公交卡记录 -> 查询公交卡记录 -> 更新公交卡余额 -> 关闭数据库连接。每个操作都按照异常处理的原则进行了适当的错误检查和信息输出。最后,程序正常结束并返回0。

       余额不足设置,刷卡信息设置

*/

// // 引入标准输入输出头文件,用于打印错误信息等
// #include <stdio.h>

// // 引入SQLite3数据库操作头文件
// #include "sqlite3.h"

#include "demo2.h"
#include "sqlite3.h"

char *c[100]={"0"};
char *k[100]={"0"};
char *id_i[100]={"0"};
char *id_k[100]={"0"};

int ck = 0;
int ck_1=0;
int ck_id = 0;



// 定义一个函数,用于打开数据库连接并返回状态
int open_database(sqlite3 **db, const char *db_name) {
    // 使用sqlite3_open打开或创建指定名称的数据库
    int rc = sqlite3_open(db_name, db);
    
    // 如果打开数据库失败,则打印错误信息并返回错误码
    if (rc) {
       fprintf(stderr, "无法打开数据库: %s\n", sqlite3_errmsg(*db));
       return rc;
    }
    
    // 打开成功则输出提示信息,并返回0表示成功
    printf("成功打开数据库\n");
    return 0;
}

// 定义一个函数,用于创建公交卡表
void create_table(sqlite3 *db) {
    // SQL语句:如果不存在则创建名为BusCards的表,包含CardID和Balance两列
    const char *sql_create_table =
    "CREATE TABLE IF NOT EXISTS BusCards ("
    "    CardID INTEGER PRIMARY KEY,"
    "    Balance REAL"
    ");";

    // 执行SQL语句,若出错则打印错误信息
    char *errmsg;
    if (sqlite3_exec(db, sql_create_table, NULL, NULL, &errmsg)) {
       fprintf(stderr, "创建表时出错: %s\n", errmsg);
       sqlite3_free(errmsg);
    } else {
       printf("公交卡表创建成功\n");
    }
}

// 定义一个函数,用于向数据库中插入一条公交卡记录
void insert_card(sqlite3 *db, const BusCard *card) {
    // 准备插入数据的SQL语句,使用问号作为占位符
    const char *sql_insert =
    "INSERT INTO BusCards(CardID, Balance) VALUES (?, ?);";

    sqlite3_stmt *stmt;
    // 准备SQL语句并绑定公交卡结构体中的值
    if (sqlite3_prepare_v2(db, sql_insert, -1, &stmt, NULL) == SQLITE_OK) {
       sqlite3_bind_int(stmt, 1, card->card_id);
       sqlite3_bind_double(stmt, 2, card->balance);

       // 执行插入操作
       if (sqlite3_step(stmt) != SQLITE_DONE) {
          //fprintf(stderr, "插入数据时出错: %s\n", sqlite3_errmsg(db));
       } else {
          printf("成功插入卡号为%X,余额为%.2f的公交卡记录\n", card->card_id, card->balance);
       }

       // 清理准备好的语句资源
       sqlite3_finalize(stmt);
    }
}

// 定义一个函数,用于从数据库中查询公交卡记录并返回结构体
BusCard query_card(sqlite3 *db, int card_id) {
    // 初始化查询结果结构体
    BusCard result = {0};

    // 准备查询数据的SQL语句,使用问号作为占位符
    const char *sql_query = "SELECT CardID, Balance FROM BusCards WHERE CardID = ?;";

    sqlite3_stmt *stmt;
    // 准备SQL语句并绑定要查询的卡号
    if (sqlite3_prepare_v2(db, sql_query, -1, &stmt, NULL) == SQLITE_OK) {
       sqlite3_bind_int(stmt, 1, card_id);

       // 执行查询操作
       if (sqlite3_step(stmt) == SQLITE_ROW) {
          // 从查询结果中提取公交卡信息并填充到结果结构体中
          result.card_id = sqlite3_column_int(stmt, 0);
          result.balance = sqlite3_column_double(stmt, 1);
          printf("查询到的公交卡信息:卡号:%X,余额:%.2f\n", result.card_id, result.balance);
       } else {
          //printf("未找到卡号为%d的公交卡记录\n", card_id);
          printf("未找到卡号为%X的公交卡记录\n", card_id);
       }

       // 清理准备好的语句资源
       sqlite3_finalize(stmt);
    }

    // 返回查询结果
    return result;
}

// 定义一个函数,用于更新公交卡在数据库中的余额
void update_card_balance(sqlite3 *db, const BusCard *card) {
    // 准备更新数据的SQL语句,使用问号作为占位符
    const char *sql_update = "UPDATE BusCards SET Balance = ? WHERE CardID = ?;";

    sqlite3_stmt *stmt;
    // 准备SQL语句并绑定公交卡ID和新的余额
    if (sqlite3_prepare_v2(db, sql_update, -1, &stmt, NULL) == SQLITE_OK) {
       sqlite3_bind_double(stmt, 1, card->balance);
       sqlite3_bind_int(stmt, 2, card->card_id);

       // 执行更新操作
       if (sqlite3_step(stmt) != SQLITE_DONE) {
          fprintf(stderr, "更新数据时出错: %s\n", sqlite3_errmsg(db));
       } else {
          printf("成功更新卡号为%X的公交卡余额为%.2f\n", card->card_id, card->balance);
       }

       // 清理准备好的语句资源
       sqlite3_finalize(stmt);
    }
}

// 示例主函数,演示如何使用上述功能进行数据库操作
int demo_2(int a) {
    sqlite3 *db;
    // 打开数据库连接
    if (open_database(&db, "buscard.db") == 0) {
       // 创建公交卡表
       create_table(db);

       // 创建并插入一个新的公交卡记录
       BusCard new_card = {ID, 50.0};
       insert_card(db, &new_card);

       // 查询并显示刚才插入的公交卡信息
       BusCard queried_card = query_card(db, ID);

       // 更新公交卡的余额
       if(fufei_bz==1)
       {
          if(queried_card.balance<-a)
          {
             show_bmp("./car21.bmp");
             printf("余额不足\n");
             return 0;
          }
       }
       queried_card.balance += a;

       beep_start(0);

       update_card_balance(db, &queried_card);

       // 关闭数据库连接
       sqlite3_close(db);
    }

    // 程序正常结束,返回0
    return 0;
}

demo2.h

#ifndef _DEMO2_H_
#define _DEMO2_H_

#include <stdio.h>
#include "sqlite3.h"
#include "rfid_write_read.h"
#include "beep.h"
#include "show.h"

// 定义公交卡结构体,包含卡ID和余额两个字段
typedef struct {
    int card_id;          // 公交卡ID
    double balance;       // 公交卡余额
} BusCard;


int open_database(sqlite3 **db, const char *db_name);
void create_table(sqlite3 *db);
void insert_card(sqlite3 *db, const BusCard *card);
BusCard query_card(sqlite3 *db, int card_id);
void update_card_balance(sqlite3 *db, const BusCard *card);
int demo_2(int a);

extern char *c[100];
extern char *k[100];
extern char *id_i[100];
extern char *id_k[100];
extern int ck;
extern int ck_1;
extern int ck_id;


#endif

main.c

//显示第一个界面(首界面),登录界面的键盘设置,登录密码设置
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <linux/input.h>
#include "font.h"
#include "show.h"
#include "beep.h"
#include "Swiping_card.h"
#include "Development_board.h"
#include "manager.h"
#include "rfid_write_read.h"
#include "pthread.h"
#include "record.h"


int Login(void);
int get_xy(int *x,int *y);
int Display_font(int x0,int y0,int len,char *buf,int size,unsigned int color);
int main()
{   


    //线程
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    // 以分离属性启动线程
    pthread_t tid;
    pthread_create(&tid, &attr, (void *)shuaka, NULL);

    for(int i=0;i<100;i++)
    {
       c[i]=malloc(12);
       k[i]=malloc(12);
       id_i[i]=malloc(12);
       id_k[i]=malloc(12);
    }
    char s[]= "1           ";
    strcpy(k[0],s);


    //beep_start(0);
    // led_off();//led全部关闭
    char loginflag=0;
    int x=0;
    int y=0;
    //先加载文件里面的账号和密码
    
    do
    {
       
       
       show_bmp("./car1.bmp");    //显示第一个界面
       
       get_xy(&x,&y);
       if(x>283&&y>120&&x<555&&y<168) //直接进入刷卡付费界面----左
       {  
          
          loginflag=1;
       }
       if(x>313&&y>205&&x<545&&y<256) //唤出键盘输入密码并且比对----右
       {
          Login();
          loginflag=2;
       }

       if(x>0&&x<165&&y>372&&y<478) //535 310  625 365
       {
          loginflag=3;
       }
       
       
       switch  (loginflag)
       {
          case 1:
                printf("请刷卡付款\n");
                slod();    
                loginflag=0;
                break;
          case 2:
                //登录
                printf("请输入密码\n");
                loginflag=0;
                break;
          case 3:
                record();
                loginflag=0;
                break;
                
       }

    }while(1);
    
    
    
    
}

int Login(void)//登录
{   
    printf("请输入密码");
    show_bmp("./car31.bmp");
    show(250,0,"./jianpan.bmp");//键盘图片
    
    //char passwd[12]={'6','6','6','6','6','6'};//设置的密码
    //char passwd[12]={'1','2','3'};//设置的密码
    char passwd[12]={'6','6','6'};//设置的密码
    
    char spasswd[12]={0};//存输入的密码
    

    int bz3=0; //输入账号的标志位
    int sr_bz3=1;//输入账号的标志位
    int bz4=0; //输入密码的标志位
    int sr_bz4=1;
    int bz5 = 0;

    int x=0;
    int y=0;

    while (1)
    {
       printf("请输入登录密码");
       get_xy(&x,&y);
       if(x>210&&x<587&&y>188&&y<242) 
       {
          bz4=1;
       }
       if(x>250&&x<350&&y>270&&y<320) { bz4=2;}
       else if(x>350&&x<450&&y>270&&y<320) { bz4=3;}
       else if(x>450&&x<550&&y>270&&y<320) { bz4=4;}
       else if(x>250&&x<350&&y>320&&y<370) { bz4=5;}
       else if(x>350&&x<450&&y>320&&y<370) { bz4=6;}
       else if(x>450&&x<550&&y>320&&y<370) { bz4=7;}
       else if(x>250&&x<350&&y>370&&y<420) { bz4=8;}
       else if(x>350&&x<450&&y>370&&y<420) { bz4=9;}
       else if(x>450&&x<550&&y>370&&y<420) { bz4=10;}
       else if(x>250&&x<350&&y>430&&y<480) { bz4=11;break;} //退出按键
       
       else if(x>450&&x<550&&y>430&&y<480) { bz4=12;} //删除

       switch(bz4)
       {

          case 2:
             printf("%s\n",spasswd);strcat(spasswd,"1");bz4=0;sr_bz4=1;break;
          case 3:
             printf("%s\n",spasswd);strcat(spasswd,"2");bz4=0;sr_bz4=1;break;
          case 4:
             printf("%s\n",spasswd);strcat(spasswd,"3");bz4=0;sr_bz4=1;break;
          case 5:
             printf("%s\n",spasswd);strcat(spasswd,"4");bz4=0;sr_bz4=1;break;
          case 6:
             printf("%s\n",spasswd);strcat(spasswd,"5");bz4=0;sr_bz4=1;break;
          case 7:
             printf("%s\n",spasswd);strcat(spasswd,"6");bz4=0;sr_bz4=1;break;
          case 8:
             printf("%s\n",spasswd);strcat(spasswd,"7");bz4=0;sr_bz4=1;break;
          case 9:
             printf("%s\n",spasswd);strcat(spasswd,"8");bz4=0;sr_bz4=1;break;
          case 10:
             printf("%s\n",spasswd);strcat(spasswd,"9");bz4=0;sr_bz4=1;break;
          case 11:
             printf("%s\n",spasswd);;bz4=0;sr_bz4=0;bz5=1;break;
          case 12:
             printf("%s\n",spasswd);
             spasswd[strlen(spasswd) - 1] = '\0';  // 删除最后一个字符
             Display_font(50,165, strlen(spasswd) + 1, spasswd, 2, 0x000000);  // 更新显示
             break;
                
             
       }
       if(sr_bz4)
       {
          show_bmp("./car31.bmp");
          show(250,0,"./jianpan.bmp");//键盘图片
          //Display_font(211,200,strlen(spasswd)+1,spasswd,2,0x000000);
          Display_font(60,168,strlen(spasswd)+1,spasswd,2,0x000000);
       }


    } 

    //对比
    printf("开始对比\n");

    if(strcmp(passwd,spasswd) == 0)
    {
       printf("登录成功\n");
       manager();
    }
    else
    {
       printf("密码错误\n");
       show_bmp("./car311.bmp");
       sleep(5);
    }

    
}

六、编译命令

在Ubuntu软件下编译

arm-linux-gcc main.c show.c font.c Swiping_card.c Development_board.c manager.c rfid_write_read.c demo2.c record.c beep.c -o main -lpthread -L ./ -lsqlite3

七、下载到开发板

把编译生成的main文件拖到._cache_MobaXterm_Personal_21.3软件的文件夹里,所涉及的图片.bmp也要拖进去才能实现效果。

执行编译命令:

(1)    chmod 777 main

(2)    ./main

八、项目工程图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值