基于STM32+RFID设计的宿舍检修管理系统

1. 需求

需求: 一个寝室一个标签,设备端扫描标签,通过显示屏键入维修成功与否之类的的信息提交到平台

系统构架: 一个设备端 + 一个上位机

硬件选型:
(1)STM32F103RCT6作为设备端的主控MCU
(2)RC522作为设备端的射频刷卡设备,读写IC卡
(3)多张IC卡,模拟代表每个宿舍

实现思路:
设计一个上位机,用来管理查看维修检修信息,当维修寝室的设备或者检修完成时,通过STM32上的RC522刷一下这个寝室的IC卡,识别这是哪个寝室,识别成功后在软件上弹出一个对话框,填写本次维修或者检修的事件,填写完毕点击提交即可。

软件分为两个功能:
(1)注册功能:每个寝室都有一张IC卡,这张卡第一次使用需要在维检系统里进行注册,填写这个IC卡对应的这个寝室的信息。
(2)维修、检修报告提交:当完成检修、检修之后,填写报告。
(3)查看历史记录,可以查看维修,检修的所有详细报告信息,可以导出execl表格,方便公布出去公众查看。
(4)注册、维修、检修记录都存放在数据库里,方便管理。

硬件的具体功能:
STM32上有两个按键,一个LCD屏,一个RC522模块,当终端刷卡后,LCD显示屏会弹出一个询问提示? “当前是维修还是检修”,按下按键1或者按键2之后,就会将卡号上传到上位机。 上位机与下位机通过串口进行通信。

2. 演示效果

image-20220501230852154

image-20220501230839452

3. 上位机软件设计

3.1 通信说明

上位机与设备之间通过串口进行通信,上位机里使用SQLITE数据库存放所有关键信息,数据库里创建了3张表,一张表存放维检信息,一张表是账号信息,一张表是意见反馈记录。

A,F39A471B,  注册
B,F39A471B,  检修
C,F39A471B,  维修

3.2 搭建开发环境

上位机软件采用Qt框架设计,Qt是一个跨平台的C++图形用户界面应用程序框架。Qt是一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。简单来说,QT可以很轻松的帮你做带界面的软件,甚至不需要你投入很大精力。

QT官网: https://www.qt.io/

image-20220314143105032

QT学习入门实战专栏文章: https://blog.csdn.net/xiaolong1126626497/category_11400392.html

QT5.12.6的下载地址:
https://download.qt.io/archive/qt/5.12/5.12.6/

打开下载链接后选择下面的版本进行下载:

qt-opensource-windows-x86-5.12.6.exe 13-Nov-2019 07:28 3.7G Details

软件安装时断网安装,否则会提示输入账户。

安装的时候,第一个复选框里勾选一个mingw 32编译器即可,其他的不管默认就行,直接点击下一步继续安装。

image-20220417145923643

选择MinGW 32-bit 编译器:

image-20220417150002770

选择MinGW 32-bit 编译器:

image-20220417150031913

安装好之后,将源码工程复制到英文路径下,双击工程文件打开。

image-20220503002536986

工程打开之后,点击左下角的绿色三角形按钮即可编译运行。

image-20220503002719440

运行效果如下:

image-20220503002923034

3.3 效果

image-20220502084605933

image-20220502084630720

image-20220502085054445

image-20220502085111189

image-20220503002304800

image-20220503002321178

image-20220503002338426

3.4 数据库的插入代码示例

//在数据库创建维检信息表
void Widget::CreateStudentSurface()
{
    
    
    //数据库:建表,如果存在就不创建,不存在就创建
    QSqlQuery sql_query(database);

    //下面语句查询指定的表是否存在.
    sql_query.exec(QString("select count(*) from sqlite_master where type='table' and name='%1'").arg("student"));
    if(sql_query.next())
    {
    
    
        if(sql_query.value(0).toInt()==0)
        {
    
    
            qDebug("维检记录数据库表是不存在的.准备创建.\n");
            //创建表格 创建表格语句:create table <table_name> (f1 type1, f2 type2,…);
            /* CREATE TABLE 是告诉数据库系统创建一个新表的关键字。
                * CREATE TABLE 语句后跟着表的唯一的名称
                * 或标识*/
            /*下面的语句: 创建一个名称为student的表,字段分别是ID、编号、地点名称、类型、事件*/
            QString create_sql = "create table student(id int primary key, number varchar(100),name varchar(100),type varchar(100),enevt varchar(1024))";

            sql_query.prepare(create_sql);
            if(!sql_query.exec())
            {
    
    
                Log_Text_Display("维检记录数据库表创建失败.\n");
            }
            else
            {
    
    
                Log_Text_Display("维检记录数据库表创建成功.\n");
            }
        }
        else
        {
    
    
            Log_Text_Display("维检记录数据库表是存在的.不需要创建.\n");
        }
    }
}


//添加信息
void Widget::on_pushButton_add_student_clicked()
{
    
    
    QString number=ui->lineEdit_student_number->text();
    QString name=ui->lineEdit_student_name->text();
    if(number.isEmpty()||name.isEmpty())
    {
    
    
        QMessageBox::information(this,"提示","请认真填写数据后再添加.",
        QMessageBox::Ok,QMessageBox::Ok);
        return;
    }

    //添加维检地点信息
    LuRu_data(number,name);
}


//录入数据 传入设备编号和地点名称
void Widget::LuRu_data(QString number,QString name)
{
    
    
    //没有表就先创建
    CreateStudentSurface();

    //添加数据到表
    //保存数据到数据库
    QSqlQuery sql_query(database);

    //查询原数据库表里有没有重复数据
    //查询全部数据
    sql_query.prepare("select * from student");
    if(!sql_query.exec())
    {
    
    
        Log_Text_Display("维检记录数据库查询错误.\n");
    }
    else
    {
    
    
        while(sql_query.next())
        {
    
    
            //ID、编号、地点名称、类型、事件
            // int id = sql_query.value(0).toInt(); //ID
            QString find_number = sql_query.value(1).toString(); //编号
            QString find_name = sql_query.value(2).toString(); //地点名称
            QString find_type = sql_query.value(3).toString(); //类型
            QString find_event = sql_query.value(4).toString(); //事件
            //判断编号有没有冲突的
            if(number==find_number)
            {
    
    
                QMessageBox::information(this,"提示","你输入的编号在数据库已经存在!\n请认真填写.",
                QMessageBox::Ok,QMessageBox::Ok);
                return;
            }
        }
    }

    //准备插入数据
    //查询最大ID
    QString select_max_sql = "select max(id) from student";
    int max_id = 0;
    sql_query.prepare(select_max_sql);
    if(!sql_query.exec())
    {
    
    
        Log_Text_Display("维检信息表最大ID查找失败.\n");
    }
    else
    {
    
    
        while(sql_query.next())
        {
    
    
            max_id = sql_query.value(0).toInt();
        }
        Log_Text_Display(QString("data base max id:%1\n").arg(max_id));

        //添加数据
        //插入数据 插入语句:insert into <table_name> values (value1, value2,…);
        QString insert_sql = tr("insert into student values(?,?,?,?,?)");
        sql_query.prepare(insert_sql);
        //ID、编号、地点名称、类型、事件
        sql_query.addBindValue(max_id+1); //id
        sql_query.addBindValue(number);
        sql_query.addBindValue(name);
        sql_query.addBindValue("----");
        sql_query.addBindValue("----");
        if(!sql_query.exec())
        {
    
    
            Log_Text_Display("维检信息表数据插入失败.\n");
            return;
        }
        else //插入成功
        {
    
    
            //插入成功就清除页面
            ui->lineEdit_student_name->clear();
         //   ui->lineEdit_student_type->clear();
            ui->lineEdit_student_number->clear();
        }
    }

    //更新维检信息表格数据显示
    on_pushButton_update_student_clicked();
}

4. STM32设备端设计

如果需要全部工程源码、上位机的源码可以在这里下载即可:
https://download.csdn.net/download/xiaolong1126626497/85682742

如果需要看项目视频演示,可以看这里:

基于STM32+RFID设计的宿舍维检管理系统

4.1 汉字取模

image-20220501230518200

4.2 keil工程

image-20220501230544234

4.3 硬件连线

RC522射频模块外部的接口:    
*1--SDA <----->PB5--片选脚
*2--SCK <----->PB4--时钟线
*3--MOSI<----->PA12--输出
*4--MISO<----->PA11--输入
*5--悬空
*6--GND <----->GND
*7--RST <----->PA8--复位脚
*8--VCC <----->VCC

4.4 main.c代码

#include "sys.h"
#include "delay.h"
#include "usart.h" 
#include "led.h" 		 	 
#include "lcd.h"
#include "RFID_RC522.h"
#include "key.h"
#include "beep.h"

unsigned char SN[4]={
    
    88,88,88,88}; //默认卡号

u8 SendBuff[50];

/*
函数功能: 打印卡号
*/
void print_info(unsigned char *p,int cnt)
{
    
    
  int i;
	for(i=0;i<cnt;i++)
	{
    
    
		printf("0x%X ",p[i]);
	}
	printf("\r\n");
}


/*
函数功能: 读卡号--电子标签的卡号
返回值: 1成功 0失败
*/
int ReadCardNumber(void)
{
    
    
    unsigned char CT[2];//卡类型
	u8 status=1;
	status=RC522_PcdRequest(PICC_REQIDL ,CT);//(寻卡模式,卡类型),成功返回0
	if(status==MI_OK)//寻卡成功
	{
    
    
	    status=MI_ERR;
	    status=RC522_PcdAnticoll(SN);  //防冲撞,成功返回0,SN是读到卡号的地址
		printf("卡类型:");
		print_info(CT,2);//打印类型
		printf("卡号:");
	    print_info(SN,4);//打印卡号	
        return 1;
	}
    return 0;
}



int main(void)
{
    
    		
    u32 cnt=0;
 	u8 key=0;
  	Stm32_Clock_Init(9);	//系统时钟设置
	uart_init(72,115200);	//串口初始化为115200
	LED_Init();		  		//初始化与LED连接的硬件接口
 	LCD_Init();
    KEY_Init();
    BEEP_Init();
	POINT_COLOR=RED;
    RC522_Init();		 //RC522
    
    //LCD_DisplayData(24*1,0,24,24,font_data[0]);
    //LCD_DisplayData(24*2,0,24,24,1);
    //LCD_DisplayData(24*3,0,24,24,2);
    
    DisplayData(24*0,0,24,24,(u8*)font_data[0],WHITE,BLACK);
    DisplayData(24*1,0,24,24,(u8*)font_data[1],WHITE,BLACK);
    DisplayData(24*2,0,24,24,(u8*)font_data[2],WHITE,BLACK);
    DisplayData(24*3,0,24,24,(u8*)font_data[3],WHITE,BLACK);
    DisplayData(24*4,0,24,24,(u8*)font_data[4],WHITE,BLACK);
    DisplayData(24*5,0,24,24,(u8*)font_data[5],WHITE,BLACK);
    DisplayData(24*6,0,24,24,(u8*)font_data[6],WHITE,BLACK);
    DisplayData(24*7,0,24,24,(u8*)font_data[7],WHITE,BLACK);
    DisplayData(24*8,0,24,24,(u8*)font_data[8],WHITE,BLACK);
    DisplayData(24*9,0,24,24,(u8*)font_data[9],WHITE,BLACK);
    
    delay_ms(100);
  	while(1) 
	{
    
    	
        //读取卡号
        if(ReadCardNumber())
        {
    
    
            DisplayData(0,100,24,24,(u8*)font_data[16],WHITE,BLACK);
            DisplayData(24,100,24,24,(u8*)font_data[17],WHITE,BLACK);

            sprintf((char*)SendBuff,"%X%X%X%X",SN[0],SN[1],SN[2],SN[3]);
            
            LCD_ShowString(24*3,105,300,300,16,"               ");
            LCD_ShowString(24*3,105,300,300,16,SendBuff);
             
            BEEP=1;
            delay_ms(100);
            BEEP=0;
            
            
            //注册
            DisplayData(0,200,24,24,(u8*)font_data[10],WHITE,BLACK);
            DisplayData(24*1,200,24,24,(u8*)font_data[11],WHITE,BLACK);
            
            
            //检修
            DisplayData(24*2+24*3,200,24,24,(u8*)font_data[12],WHITE,BLACK);
            DisplayData(24*3+24*3,200,24,24,(u8*)font_data[13],WHITE,BLACK);
            
            //维修
            DisplayData(24*4+24*6,200,24,24,(u8*)font_data[14],WHITE,BLACK);
            DisplayData(24*5+24*6,200,24,24,(u8*)font_data[15],WHITE,BLACK);
            
            while(1)
            {
    
    
                key=KEY_Scan(0);
                if(key)
                {
    
    
                   printf("key=%d\r\n",key); 
                    
                    //注册
                   if(key==3)
                   {
    
    
                       sprintf((char*)SendBuff,"A,%X%X%X%X,",SN[0],SN[1],SN[2],SN[3]);
                      printf("%s\r\n",SendBuff);
                   }
                   //检修
                   else if(key==2)
                   {
    
    
                       sprintf((char*)SendBuff,"B,%X%X%X%X,",SN[0],SN[1],SN[2],SN[3]);
                      printf("%s\r\n",SendBuff);
                   }
                   //维修
                   else if(key==1)
                   {
    
    
                      sprintf((char*)SendBuff,"C,%X%X%X%X,",SN[0],SN[1],SN[2],SN[3]);
                      printf("%s\r\n",SendBuff);
                   }
                   break;
                }
                delay_ms(50);
                LED0=!LED0;
             }
            
            LCD_Clear(WHITE);
            DisplayData(24*0,0,24,24,(u8*)font_data[0],WHITE,BLACK);
            DisplayData(24*1,0,24,24,(u8*)font_data[1],WHITE,BLACK);
            DisplayData(24*2,0,24,24,(u8*)font_data[2],WHITE,BLACK);
            DisplayData(24*3,0,24,24,(u8*)font_data[3],WHITE,BLACK);
            DisplayData(24*4,0,24,24,(u8*)font_data[4],WHITE,BLACK);
            DisplayData(24*5,0,24,24,(u8*)font_data[5],WHITE,BLACK);
            DisplayData(24*6,0,24,24,(u8*)font_data[6],WHITE,BLACK);
            DisplayData(24*7,0,24,24,(u8*)font_data[7],WHITE,BLACK);
            DisplayData(24*8,0,24,24,(u8*)font_data[8],WHITE,BLACK);
            DisplayData(24*9,0,24,24,(u8*)font_data[9],WHITE,BLACK);
            
             
        }
        
		cnt++;
        delay_ms(10);
        if(cnt>=20)
        {
    
    
            cnt=0;
            LED1=!LED1;
            LED0=!LED0;		
        }
	} 
}

猜你喜欢

转载自blog.csdn.net/xiaolong1126626497/article/details/125510106
今日推荐