资源描述
沈阳航空航天大学
课 程 设 计 报 告
课程设计名称:物联网综合课程设计
课程设计题目:13.56MHZ门禁考勤软件设计与实现
院(系):计算机学院
专 业:
班 级:
学 号:
姓 名:
指导教师:
完成日期:
沈阳航空航天大学课程设计报告
目 录
第1章 总体设计方案 2
1.1 设计原理 2
1.2 设计思路 3
1.3 设计环境 5
第2章 详细设计方案 7
2.1 顶层方案图的设计与实现 7
2.2 功能模块的设计与实现 7
2.2.1 信息管理的实现 8
2.2.2 刷卡功能的实现 13
第3章 编程下载与硬件测试 17
3.1 编程下载 17
3.2 硬件测试及结果分析 17
附 录(课设程序源代码) 22
-32-
沈阳航空航天大学课程设计报告
第1章 总体设计方案
1.1 设计原理
本课设题目名称为13.56MHZ门禁考勤软件设计与实现,在数字技术网络技术飞速发展的今天门禁技术得到了迅猛的发展。门禁系统早已超越了单纯的门道及钥匙管理,它已经逐渐发展成为一套完整的出入管理系统。它在工作环境安全、人事考勤管理等行政管理工作中发挥着巨大的作用。需要刷卡进行考勤管理的门禁系统,门禁卡在发放最终用户使用前,经由系统管理员设置,确定可使用区域及用户权限,用户使用门禁卡刷卡进入管理区域,无门禁卡或权限未开通用户,不能进入管理区域。正是在这一应用背景下,本课设设计了一套基于13.56MHZ 的RFID 技术的智能门禁考勤管理系统。
RFID 技术是一种非接触的自动识别技术。该技术的原理主要是利用射频信号和空间耦合的传输属性,从而能够对物体进行自动识别。RFID 技术在门禁考勤上发挥了很大的作用。卡读卡器以固定频率向外发出电磁波,在此设计中频率是 13.56MHZ,当感应卡进入读卡器电磁波辐射范围内时,会触发感应卡上的线圈,产生电流并触发感应卡上的天线向读卡器发射一个信号,该信号带有卡片信息,读卡器将电平信号转换成数字序号,以韦根协议传送给就地控制器,就地控制器将信息上传给上层控制器,最终上传给门禁服务器,门禁服务器将卡号与数据库内的信息进行比对,从而得到全部的卡片信息。
RFID 系统主要由电子标签、RFID 读写器和天线三部分构成。每张门禁卡的RFID 标签都是唯一的电子标签,其内部信息需要用EEPROM 进行存储卡的各项信息;而RFID 读写器由RFID 控制器和RFID 天线构成,读写器主要用来读取和写入RFID 标签信息;而天线的作用就是用来传递RFID 读写器和RFID 标签之间的信息信号。
1.2 设计思路
根据13.56MHZ门禁考勤软件的原理,可以将该考勤管理软件分为以下几个部分:刷卡识别、信息管理。
刷卡识别:该功能可以利用13.56MHZ电子标签卡实现考勤识别,该识别功能主要分为两步:接收读卡器串口数据(如图1.1所示)、解析卡的数据(如图1.2所示)。
打开串口start(“COM1”)
检测串口数据
获取串口有效数据包onPortDataReady()
发射接收数据信号recvPackage()
数据包解析onRecvedPackage()
发射对应信号
图1.1 接收读卡器串口数据框图
寻卡process_searchCard()
数据打包IEEE14443Package()
发送sendData()
等待信号
获取卡号成功
onFoundCard()
读卡成功onReadCard()
图1.2 解析卡的数据框图
信息管理:由数据库包含的用户表和考勤日志表功能可以实现添加、删除或修改门禁卡信息。
门禁考勤软件系统功能结构框图如图1.3所示:
门禁考勤软件
刷
卡 识 别
信
息
管
理
入
图1.3 门禁考勤软件系统功能结构框图
1.3 设计环境
1.软件环境
(1)QT是一个多平台的C++图形应用程序应用框架,QT是完全面向对象的,很容易扩展,并且允许真正的组件编程。QT Creator可以实现代码的查看、编辑、界面的查看、以图形化的方式编辑、修改、编译等工作;甚至在PC环境下还可以对应用程序进行调试。调试QT Creator还是一个跨平台的工具,它支持包括Linux、Mac OS X 以及 Windows在内的多种操作系统平台,使得不同的开发工作者可以在不同的开发平台下共享代码或协同工作。
(2) 超级终端:Windows自带的超级终端可以在PC端使用串口通信来对实验箱进行控制,将编译生成的文件下载到实验箱上并运行。
2.硬件环境
物联网多网技术综合教学开发平台B版(以下简称实验箱),重在研究不同网络在物联网中的各种应用,包含RFID技术、Zigbee、BlueTooth、Wifi、GPRS等各种数据通信方式,可应用于物联网专业教学、项目开发等方向。该系统聚集了传感器网络、RFID射频、WIFI无线网、GPRS通讯、蓝牙技术、二维码扫描等物联网相关技术平台,涉及技术比较广泛。实验箱结构如图1.4所示。
功能特点:
实验箱提供了全面的开发工具和配套资料,最大程度的激发学生兴趣,巩固学习效果,方便了学习和应用。该平台的特色是:实验箱将模拟电子、数字电子、电路设计、信号处理、传感器原理与检测、单片机技术、RFID技术、BlueTooth技术、Wifi技术、Zigbee通信、GPRS通信、嵌入式技术等相关知识融会贯通,涵盖了当前物联网行业最热门最尖端的技术,实现了多网融合,让学生可以灵活应用各科知识,发挥创新能力。实验箱为高校老师和学生们提供当前最受欢迎的嵌入式技术。学生通过实践能够熟悉嵌入式开发的流程,掌握相关软件和调试工具的使用方法。采用源码开放的Linux操作系统采用源代码开放的Linux操作系统。
图1.4 实验箱实物图
老师和学生不仅可以阅读Linux系统的源码,而且可以自己配置和修改部分代码,定制个性操作系统。由于Linux相关的网络资料、书本资料很丰富,因此在学习或开发过程中如果遇到问题,就可以在相关论坛得到帮助,缩短技术攻关的时间,提高学习或工作效率。实验箱具有一键还原功能,通过该功能在做完实验后,可将实验箱恢复到初始状态,方便管理节约检查配置时间。
第2章 详细设计方案
2.1 顶层方案图的设计与实现
顶层方案图实现13.56MHZ门禁考勤软件的逻辑功能。在Linux系统下的Qt软件中将该代码编译,再将编译好的文件从Linux中复制到Windows系统下。在Windows系统下需要使用串口通信软件来对实验箱进行控制。通常情况下,使用Windows 系统自带的“超级终端”工具即可。在超级终端中,执行命令“ipconfig eth0 -i 192.168.87.130 -m 255.255.255.0 -g 192.168.87.1”,即可为实验箱手动配置IP 地址,如图 2.1 所示。
图 2.1 手动配置实验箱的IP 地址
其中,-i 后面的参数是实验箱的IP 地址;-m 后面的参数是子网掩码;-g 后面的参数是网关地址。如果不需要网关,可以将 -g 和其后面的参数省略。 设置完成之后,需要执行“service network restart”命令重启网络服务,使设置生效。需要注意的是,实验箱的IP 地址需要设置为与电脑同一个网段,例如,在本例中,电脑的IP 地址为“192.168.87.1/255.255.255.0”,而实验箱的IP 地址为“192.168.87.130/255.255.255.0”。打开“我的电脑”,在地址栏中输入ftp://开发板的IP地址,在超级终端中执行命令“chmod +x ”,为文件增加可执行权限。最后执行“./”命令,即可运行13.56MHZ 门禁考勤软件程序。
2.2 功能模块的设计与实现
该13.56MHZ门禁考勤软件由刷卡识别和信息管理两个部分组成。
信息管理模块将信息录入后才可以进行刷卡识别。信息管理模块还可以进行考勤信息的添加、修改和删除。
刷卡识别模块可以通过13.56MHZ电子标签实现考勤管理,具体通过电子标签的id号进行对门禁卡的识别。
2.2.1 信息管理功能的实现
该门禁考勤管理的实现主要是在Qt中搭建了一个考勤系统管理的界面,再通过ManageWidget这个类来实现具体的信息管理功能
(1) 门禁考勤管理的界面如下图2 .2所示
图2.2 门禁考勤管理的界面
(2)具体的实现过程
在ManageWidget中定义了7个类,分别为:onCardReaded(const QString &cardid)、updateUserTable()、updateLogTable()、on_addBtn_clicked()、on_delBtn_clicked()、on_modifyBtn_clicked()、on_refreshBtn_clicked()。分别实现了信息的添加、修改、删除、更新等功能。具体的实现过程如下所示:
ManageWidget::ManageWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ManageWidget),
usrEditDlg(new UserEditDialog)
{
ui->setupUi(this);
updateUserTable();
}
ManageWidget::~ManageWidget()
{
delete ui;
}
void ManageWidget::onCardReaded(const QString &cardid)
{
usrEditDlg->setCardId(cardid);
}
void ManageWidget::updateUserTable() //用户的更新
{
ui->userTable->clear();
DBCard c;
if(c.first())
{
QTreeWidgetItem *item;
do {
item = new QTreeWidgetItem(ui->userTable);
item->setText(0, QString::number(c.id()));
item->setText(1, c.cardid());
item->setText(2, c.name());
} while(c.next());
}
}
void ManageWidget::updateLogTable()
{
ui->logTable->clear();
DBLog l;
if(l.first())
{
QTreeWidgetItem *item;
do {
item = new QTreeWidgetItem(ui->logTable);
item->setText(0, QString::number(l.id()));
item->setText(1, l.date().toString("yyyy-MM-dd hh:mm:ss"));
item->setText(2, l.cardid());
} while(l.next());
}
}
void ManageWidget::on_addBtn_clicked() //添加信息
{
if(!usrEditDlg->isHidden())
return;
int currentRow = ui->logTable->currentIndex().row();
qDebug()<<"log table selected index:"<<currentRow;
if(currentRow > 0){
QTreeWidgetItem *item = ui->logTable->currentItem();
usrEditDlg->setCardId(item->text(2));
usrEditDlg->setName("");
}
else{
usrEditDlg->setCardId("");
usrEditDlg->setName("");
}
if(usrEditDlg->exec() == QDialog::Rejected)
return;
if(usrEditDlg->cardId().isEmpty())
{
QMessageBox::warning(this, tr("Warning"), tr("Card ID can't be empty!"));
return;
}
if(usrEditDlg->name().isEmpty())
{
QMessageBox::warning(this, tr("Warning"), tr("User Name can't be empty!"));
return;
}
DBCard::addCard(usrEditDlg->cardId(), usrEditDlg->name());
updateUserTable();
}
void ManageWidget::on_delBtn_clicked() //删除信息
{
QList<QTreeWidgetItem *> selItems = ui->userTable->selectedItems();
while(selItems.count())
{
QTreeWidgetItem *item = selItems.first();
DBCard::delCard(item->text(1));
delete item;
selItems.removeFirst();
}
}
void ManageWidget::on_modifyBtn_clicked() //修改信息
{
QList<QTreeWidgetItem *> selItems = ui->userTable->selectedItems();
if(selItems.count())
{
QTreeWidgetItem *item = selItems.first();
if(!usrEditDlg->isHidden())
return;
usrEditDlg->setCardId(item->text(1));
usrEditDlg->setName(item->text(2));
if(usrEditDlg->exec() == QDialog::Rejected)
return;
DBCard::updateName(usrEditDlg->cardId(), usrEditDlg->name());
updateUserTable();
}
}
void ManageWidget::on_refreshBtn_clicked() //刷新
{
updateLogTable();
}
void ManageWidget::on_pushButton_clicked()
{
//删除login卡的记录
QList<QTreeWidgetItem *> logItems = ui->logTable->selectedItems();
while(logItems.count())
{
QTreeWidgetItem *item = logItems.first();
DBCard::delLogCard(item->text(2)); //删除当前cardid
delete item;
logItems.removeFirst();
}
}
2.2.2 刷卡识别功能的实现
刷卡功能的实现主要是在Qt中搭建了一个刷卡显示信息的界面,刷卡时显示卡号和与之关联的姓名,再通过ClockInWidget这个类来实现具体的刷卡识别功能
(1) 刷卡显示界面如下图2.3所示
图2.3 刷卡显示界面图
(2)具体实现过程
在ClockInWidget类中定义了6个函数:ClockInWidget(QWidget *parent)、~ClockInWidget()、updateTime()、updateDateTime()、onCardReaded(const QString &cardid)、on_pushButton_clicked()。分别实现了类的构造、日期的更新、卡的读取、刷卡事件的响应等功能。具体的实现过程如下:
ClockInWidget::ClockInWidget(QWidget *parent) : //ClockInWidget类的构造
QWidget(parent),
ui(new Ui::widget)
{
ui->setupUi(this);
updateDateTime();
timer = new QTimer(this);
timer->setInterval(1000);
timer->setSingleShot(false);
connect(timer, SIGNAL(timeout()), this, SLOT(updateTime()));
timer->start();
}
ClockInWidget::~ClockInWidget()
{
delete timer;
delete ui;
}
void ClockInWidget::updateTime()
{
QDateTime d = QDateTime::currentDateTime();
ui->secondNumber->display(d.time().second());
if(d.time().second() == 0)
{
ui->minuteLabel->motionToNumber(d.time().minute());
if(d.time().minute() == 0)
{
ui->hourLabel->motionToNumber(d.time().hour());
if(d.time().hour() == 0)
{
ui->dayNumber->display(d.date().day());
if(d.date().day() == 1)
{
ui->monthNumber->display(d.date().month());
if(d.date().month() == 1)
{
ui->yearNumber->display(d.date().year());
}
}
}
}
}
}
void ClockInWidget::updateDateTime() //更新日期
{
QDateTime d = QDateTime::currentDateTime();
ui->yearNumber->display(d.date().year());
ui->monthNumber->display(d.date().month());
ui->dayNumber->display(d.date().day());
ui->hourLabel->motionToNumber(d.time().hour());
ui->minuteLabel->motionToNumber(d.time().minute());
ui->secondNumber->display(d.time().second());
}
void ClockInWidget::onCardReaded(const QString &cardid)
{
QString name = DBCard::findName(cardid);
ui->cardIdEdit->setText(cardid);
ui->nameEdit->setText(name.isEmpty() ? tr("No such person!") : name);
//清理读卡状态字符显示
ui->labelScan->setText("Scanning card:"+cardid);
DBLog::addLog(cardid);
}
void ClockInWidget::on_pushButton_clicked()
{
// 启动扫描卡的过程
ui->cardIdEdit->clear();
ui->nameEdit->clear();
ui->labelScan->setText("Scanning card...");
MainWidget::rfidIEEE14443->getCardId();
}
第3章 编程下载与硬件测试
3.1 编程下载
在Linux系统下的Qt软件中将本软件代码编译,再将编译好的文件从Linux中复制到Windows系统下。在Windows系统下需要使用串口通信软件来对实验箱进行控制。通常情况下,使用Windows 系统自带的“超级终端”工具即可。在超级终端中设定好开发板的IP地址,如图3.1所示。将编译好的程序下载到该IP地址对应的文件夹中,即完成了下载过程。
图3.1 手动配置试验箱的IP地址
其中,-i后是试验箱的IP地址,-m后面的参数是子网掩码,-g后面的参数是网关地址。并且,实验箱的IP地址设置要与电脑的在同一网段。设置完成后,执行“service network restart”命令重启网络服务,使设置生效。
3.2 硬件测试及结果分析
1. 利用物联网多网技术综合开发平台实现门禁卡的识别和信息管理功能。在超级终端中为Attendance 文件增加可执行权限,并运行它如图3.2所示:
图3.2 运行Attendance 程序
2. 程序运行之后,可以在LCD 上看到图3.3所示的界面:
图3.3 Attendance主界面
3. “Clock in”界面为刷卡界面,在此界面下,刷卡时会显示卡号和与之关联的姓名,如果该卡没有记录,则Name栏将显示“No shch person”,如图3.4所示:
图3.4 刷卡无效时的界面
4.在“Manage”页面中,可以对用户信息进行管理,并可以查看考勤记录,如图3.5所示:
图3.5 Manage界面
5. 点击“Add”可以打开添加用户界面,如图3.6所示:
图3.6 添加用户界面
6. 添加用户之后,再次回到“Clock in”界面,此时刷卡将会显示用户名,如图 3.7 所示:
图3.7 刷卡有效时的效果
参考文献
[1] 单承赣.射频识别(RFID)原理与应用[M].北京:电子工业出版社,2012
[2] 物联网多网技术综合开发平台实验指导书[M].北京:凌阳科技有限公司,2013
[3] 熊茂华等.嵌入式Linux实时操作系统及应用编程[M].北京:清华大学出版社,2011
[4] 厦华.无线通信模块设计与物联网应用开发[M].北京:电子工业出版社,2011
[5] 多网综合开发平台B版使用说明书[M].北京:凌阳科技有限公司,2013
[6] 周华.射频识别RFID技术原理与应用实例[M].北京:人民邮政出版社,2008(12)
沈阳航空航天大学课程设计报告 附 录
附 录(关键部分程序清单)
#include "UserEditDialog.h"
#include "ui_UserEditDialog.h"
#include "ClockInWidget.h"
#include "ui_ClockInWidget.h"
#include "MainWidget.h"
#include "ui_MainWidget.h"
#include "rotatenumberlabel.h"
#include <QFile>
#include <QDebug>
UserEditDialog::UserEditDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::UserEditDialog)
{
ui->setupUi(this);
ui->sftKeypad->changeRecver(ui->nameEdit);
connect(ui->sftKeypad, SIGNAL(newString(QString)), this, SLOT(onSftKeypadNewString(QString)));
}
UserEditDialog::~UserEditDialog()
{
delete ui;
}
QString UserEditDialog::cardId() const
{
return ui->cardIdEdit->text();
}
QString UserEditDialog::name() const
{
return ui->nameEdit->text();
}
void UserEditDialog::setCardId(const QString &id)
{
ui->cardIdEdit->setText(id);
}
void UserEditDialog::setName(const QString &name)
{
ui->nameEdit->setText(name);
}
void UserEditDialog::onSftKeypadNewString(const QString &str)
{
ui->nameEdit->insert(str);
}
RotateNumberLabel::RotateNumberLabel(QWidget *parent)
: QLabel(parent)
, currentIndex(0)
, currentNumber(0)
, nextNumber(0)
, motion(false)
{
timer = new QTimer(this);
timer->setInterval(50);
connect(timer, SIGNAL(timeout()), this, SLOT(onTimer()));
reloadPicture();
}
RotateNumberLabel::~RotateNumberLabel()
{
delete timer;
}
void RotateNumberLabel::onTimer()
{
this->update();
if(motion)
{
timer->start();
}
}
void RotateNumberLabel::paintEvent(QPaintEvent *ev)
{
// QLabel::paintEvent(ev);
if(this->bgPic.isNull())
return;
int oy = (90 - 87) / 2;
int ox1 = 8;
int ox2 = 0;
QPainter pt(this);
pt.scale(qreal(this->width()) / 96, qreal(this->height()) / 90);
pt.drawImage(0, 0, bgPic);
pt.drawImage(ox1, oy, underPic[0]);
pt.drawImage(ox1 + ox2 + underPic[0].width(), oy, underPic[1]);
pt.drawImage(ox1, oy, upperPic[0]);
pt.drawImage(ox1 + ox2 + upperPic[0].width(), oy, upperPic[1]);
if(motion)
{
if(++currentIndex >= 10)
{
currentIndex = 0;
currentNumber = nextNumber;
motion = false;
}
reloadPicture();
}
}
int RotateNumberLabel::speed() const
{
return 1000 / timer->interval();
}
void RotateNumberLabel::setSpeed(int fps)
{
timer->setInterval(1000 / fps);
}
int RotateNumberLabel::number() const
{
return nextNumber;
}
void RotateNumberLabel::setNumber(int n)
{
n = n % 100;
currentIndex = 0;
currentNumber = n;
nextNumber = n;
reloadPicture();
motion = false;
this->update();
}
void RotateNumberLabel::motionToNumber(int n)
{
n = n % 100;
currentIndex = 0;
nextNumber = n;
motion = true;
reloadPicture();
this->update();
timer->start();
}
ManageWidget::ManageWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ManageWidget),
usrEditDlg(new UserEditDialog)
{
ui->setupUi(this);
updateUserTable();
}
ManageWidget::~ManageWidget()
{
delete ui;
}
void ManageWidget::onCardReaded(const QString &cardid)
{
usrEditDlg->setCardId(cardid);
}
void ManageWidget::updateUserTable()
{
ui->userTable->clear();
DBCard c;
if(c.first())
{
QTreeWidgetItem *item;
do {
item = new QTreeWidgetItem(ui->userTable);
item->setTex
展开阅读全文