单片机
返回首页

基于STM32+JAVA宠物管理系统的设计与实现

2024-03-22 来源:elecfans

【摘要】 本系统主要是由RFID自动识别技术,通过无线射频方式对宠物的电子标签进行读取,获取宠物的基本信息和在店内的所有消费,然后将数据通过网络传输至服务器。在应用层开发一个管理系统,对宠物信息、店内消费等各种行为进行管理。同时系统需有登录注册功能,宠物信息管理,店内消费管理等功能。

一、设计需求

本系统主要是由RFID自动识别技术,通过无线射频方式对宠物的电子标签进行读取,获取宠物的基本信息和在店内的所有消费,然后将数据通过网络传输至服务器。在应用层开发一个管理系统,对宠物信息、店内消费等各种行为进行管理。同时系统需有登录注册功能,宠物信息管理,店内消费管理等功能。


宠物店管理系统主要分为以下模块:

1.RFID模块:由天线和射频电路组成,通过自动识别电子标签,采集数据,采用RFID封装技术将其封装,并传输给服务器。

2.电子标签模块:接收外部信号和发送信号

3.店铺管理模块:管理员可以对店铺商品进行增删改操作,修改、删除顾客宠物信息以及店内消费行为。

4.登录注册模块:新用户可以进行注册和登录5.用户管理模块:对注册用户进行管理

二、设计需求总结

整个系统的设计:

(1). 宠物店每来一个新的宠物,就在软件端进行注册、注册时填入宠物的名称,宠物的类型,主人的电话号码、选择一张宠物的图片方便后面展示(图片可以预存几张猫、狗即可)、如果宠物后面在店里有消费也会记录包含时间,这些数据都保存在软件端的数据库里。

(2). 开卡: 新宠物注册之后,需要为这个宠物办理一张电子标签卡,这个卡里存放着这个宠物主人的电话号码,后面要查询这个宠物的信息,就读取整个电子标签里的电话号码,到数据库里查询。

(3). 开卡和查询的数据传输: 设备端与软件端采用 TCP网络方式进行通信;设备端当做TCP客户端,软件端当做TCP服务器;当设备端查询宠物的电子标签时,设备端读取电话号码之后,会通过约定的数据格式通过网络传递给软件端。 当软件端开卡注册时,也会用约定好的数据格式传递给设备端,如果设备端收到数据,开发板上的LED会点亮;这时把IC拿到RC522射频模块上刷一下即可;如果成功写入LED灯就会关闭。

(4). 软件端的设计(这个软件是给店家用的,功能都是针对店家这边方向开发):

有注册界面、登录界面;

主界面上显示店内有所有注册过的宠物信息,每个宠物有图片进行显示、宠物图片下面就显示宠物的名称;

商品界面: 展示一些狗粮、猫粮、药剂、一些宠物周边物品。 用于演示消费功能。 可以预定几个商品即可。 用户可以自己动态添加修改。

管理员界面: 可以对店内的商品进行添加、设计价格、修改宠物的信息等。

查询页面: 输入宠物信息可以查询这个宠物在店里的所有详细信息。

设备硬件部分:

这里的硬件刷卡部分采用的使用STM32开发的,更加灵活方便,完成对IC卡读写通过网络与JAVA服务器通信,也可以换成扫码枪之类的其他设备。

1. RC522刷卡模块负责对卡进行读写。

2. ESP8266WIFI初始化工作在STA模式,连接到指定WIFI,与软件所在的电脑处于同一个局域网,方便连接软件端的服务器进行数据通信,每次设备开机将会自动连接到程序里设置好WIFI热点和服务器。

3. 设备端上有一个LED灯,用来显示刷卡的状态—成功与否。

三、硬件设备效果图与部分核心代码

imgimgimg

#include 'esp8266.h'

u8 ESP8266_IP_ADDR[16]; //255.255.255.255

u8 ESP8266_MAC_ADDR[18]; //硬件地址

/*

函数功能: ESP8266命令发送函数

函数返回值:0表示成功  1表示失败

*/

u8 ESP8266_SendCmd(char *cmd)

{

    u8 i,j;

    for(i=0;i<10;i++) //检测的次数--发送指令的次数

    {

        USARTx_StringSend(USART3,cmd);

        for(j=0;j<100;j++) //等待的时间

        {

            delay_ms(50);

            if(USART3_RX_FLAG)

            {

                USART3_RX_BUFFER[USART3_RX_CNT]='';

                USART3_RX_FLAG=0;

                USART3_RX_CNT=0;

                if(strstr((char*)USART3_RX_BUFFER,'OK'))

                {

                    return 0;

                }

            }

        }

    }

    return 1;

}


/*

函数功能: ESP8266硬件初始化检测函数

函数返回值:0表示成功  1表示失败

*/

u8 ESP8266_Init(void)

{

    //退出透传模式

    USARTx_StringSend(USART3,'+++');

    delay_ms(50);

    return ESP8266_SendCmd('ATrn');

}


/*

函数功能: 一键配置WIFI为AP+TCP服务器模式

函数参数:

char *ssid  创建的热点名称

char *pass  创建的热点密码 (最少8位)

u16 port    创建的服务器端口号

函数返回值: 0表示成功 其他值表示对应错误值

*/

u8 ESP8266_AP_TCP_Server_Mode(char *ssid,char *pass,u16 port)

{

    char *p;

    u8 i;

    char ESP8266_SendCMD[100]; //组合发送过程中的命令

    /*1. 测试硬件*/

    if(ESP8266_SendCmd('ATrn'))return 1;

    /*2. 关闭回显*/

    if(ESP8266_SendCmd('ATE0rn'))return 2;

    /*3. 设置WIFI模式*/

    if(ESP8266_SendCmd('AT+CWMODE=2rn'))return 3;

    /*4. 复位*/

    ESP8266_SendCmd('AT+RSTrn');

    delay_ms(1000);

    delay_ms(1000);

    delay_ms(1000);

    /*5. 关闭回显*/

    if(ESP8266_SendCmd('ATE0rn'))return 5;

    /*6. 设置WIFI的AP模式参数*/

    sprintf(ESP8266_SendCMD,'AT+CWSAP='%s','%s',1,4rn',ssid,pass);

    if(ESP8266_SendCmd(ESP8266_SendCMD))return 6;

    /*7. 开启多连接*/

    if(ESP8266_SendCmd('AT+CIPMUX=1rn'))return 7;

    /*8. 设置服务器端口号*/

    sprintf(ESP8266_SendCMD,'AT+CIPSERVER=1,%drn',port);

    if(ESP8266_SendCmd(ESP8266_SendCMD))return 8;

    /*9. 查询本地IP地址*/

    if(ESP8266_SendCmd('AT+CIFSRrn'))return 9;

    //提取IP地址

    p=strstr((char*)USART3_RX_BUFFER,'APIP');

    if(p)

    {

        p+=6;

        for(i=0;*p!=''';i++)

        {

            ESP8266_IP_ADDR[i]=*p++;

        }

        ESP8266_IP_ADDR[i]='';

    }

    //提取MAC地址

    p=strstr((char*)USART3_RX_BUFFER,'APMAC');

    if(p)

    {

        p+=7;

        for(i=0;*p!=''';i++)

        {

            ESP8266_MAC_ADDR[i]=*p++;

        }

        ESP8266_MAC_ADDR[i]='';

    }

    

    //打印总体信息

    USART1_Printf('当前WIFI模式:AP+TCP服务器n');

    USART1_Printf('当前WIFI热点名称:%sn',ssid);

    USART1_Printf('当前WIFI热点密码:%sn',pass);

    USART1_Printf('当前TCP服务器端口号:%dn',port);

    USART1_Printf('当前TCP服务器IP地址:%sn',ESP8266_IP_ADDR);

    USART1_Printf('当前TCP服务器MAC地址:%sn',ESP8266_MAC_ADDR);

    return 0;

}


/*

函数功能: TCP服务器模式下的发送函数

发送指令: 

*/

u8 ESP8266_ServerSendData(u8 id,u8 *data,u16 len)

{

    u8 i,j,n;

    char ESP8266_SendCMD[100]; //组合发送过程中的命令

    for(i=0;i<10;i++)

    {

        sprintf(ESP8266_SendCMD,'AT+CIPSEND=%d,%drn',id,len);

        USARTx_StringSend(USART3,ESP8266_SendCMD);

        for(j=0;j<10;j++)

        {

            delay_ms(50);

            if(USART3_RX_FLAG)

            {

                USART3_RX_BUFFER[USART3_RX_CNT]='';

                USART3_RX_FLAG=0;

                USART3_RX_CNT=0;

                if(strstr((char*)USART3_RX_BUFFER,'>'))

                {

                    //继续发送数据

                    USARTx_DataSend(USART3,data,len);

                    //等待数据发送成功

                    for(n=0;n<200;n++)

                    {

                        delay_ms(50);

                        if(USART3_RX_FLAG)

                        {

                            USART3_RX_BUFFER[USART3_RX_CNT]='';

                            USART3_RX_FLAG=0;

                            USART3_RX_CNT=0;

                            if(strstr((char*)USART3_RX_BUFFER,'SEND OK'))

                            {

                                return 0;

                            }

                         }            

                    }   

                }

            }

        }

    }

    return 1;

}


/*

函数功能: 配置WIFI为STA模式+TCP客户端模式

函数参数:

char *ssid  创建的热点名称

char *pass  创建的热点密码 (最少8位)

char *p     将要连接的服务器IP地址

u16 port    将要连接的服务器端口号

u8 flag     1表示开启透传模式 0表示关闭透传模式

函数返回值:0表示成功  其他值表示对应的错误

*/

u8 ESP8266_STA_TCP_Client_Mode(char *ssid,char *pass,char *ip,u16 port,u8 flag)

{

    char ESP8266_SendCMD[100]; //组合发送过程中的命令

    //退出透传模式

    //USARTx_StringSend(USART3,'+++');

    //delay_ms(50);

    /*1. 测试硬件*/

    if(ESP8266_SendCmd('ATrn'))return 1;

    /*2. 关闭回显*/

    if(ESP8266_SendCmd('ATE0rn'))return 2;

    /*3. 设置WIFI模式*/

    if(ESP8266_SendCmd('AT+CWMODE=1rn'))return 3;

    /*4. 复位*/

    ESP8266_SendCmd('AT+RSTrn');

    delay_ms(1000);

    delay_ms(1000);

    delay_ms(1000);

    /*5. 关闭回显*/

    if(ESP8266_SendCmd('ATE0rn'))return 5;

    /*6. 配置将要连接的WIFI热点信息*/

    sprintf(ESP8266_SendCMD,'AT+CWJAP='%s','%s'rn',ssid,pass);

    if(ESP8266_SendCmd(ESP8266_SendCMD))return 6;

    /*7. 设置单连接*/

    if(ESP8266_SendCmd('AT+CIPMUX=0rn'))return 7;

    /*8. 配置要连接的TCP服务器信息*/

    sprintf(ESP8266_SendCMD,'AT+CIPSTART='TCP','%s',%drn',ip,port);

    if(ESP8266_SendCmd(ESP8266_SendCMD))return 8;

    /*9. 开启透传模式*/

    if(flag)

    {

       if(ESP8266_SendCmd('AT+CIPMODE=1rn'))return 9; //开启

       if(ESP8266_SendCmd('AT+CIPSENDrn'))return 10;  //开始透传

       if(!(strstr((char*)USART3_RX_BUFFER,'>')))

       {

            return 11;

       }

        //如果想要退出发送:  '+++'

    }

    

     //打印总体信息

    USART1_Printf('当前WIFI模式:STA+TCP客户端n');

    USART1_Printf('当前连接的WIFI热点名称:%sn',ssid);

    USART1_Printf('当前连接的WIFI热点密码:%sn',pass);

    USART1_Printf('当前连接的TCP服务器端口号:%dn',port);

    USART1_Printf('当前连接的TCP服务器IP地址:%sn',ip);

    return 0;

}

/*

函数功能: TCP客户端模式下的发送函数

发送指令: 

*/

u8 ESP8266_ClientSendData(u8 *data,u16 len)

{

    u8 i,j,n;

    char ESP8266_SendCMD[100]; //组合发送过程中的命令

    for(i=0;i<10;i++)

    {

        sprintf(ESP8266_SendCMD,'AT+CIPSEND=%drn',len);

        USARTx_StringSend(USART3,ESP8266_SendCMD);

        for(j=0;j<10;j++)

        {

            delay_ms(50);

            if(USART3_RX_FLAG)

            {

                USART3_RX_BUFFER[USART3_RX_CNT]='';

                USART3_RX_FLAG=0;

                USART3_RX_CNT=0;

                if(strstr((char*)USART3_RX_BUFFER,'>'))

                {

                    //继续发送数据

                    USARTx_DataSend(USART3,data,len);

                    //等待数据发送成功

                    for(n=0;n<200;n++)

                    {

                        delay_ms(50);

                        if(USART3_RX_FLAG)

                        {

                            USART3_RX_BUFFER[USART3_RX_CNT]='';

                            USART3_RX_FLAG=0;

                            USART3_RX_CNT=0;

                            if(strstr((char*)USART3_RX_BUFFER,'SEND OK'))

                            {

                                return 0;

                            }

                         }            

                    }   

                }

            }

        }

    }

    return 1;

}


四、JAVA端效果图与部分代码示例

如果需要资料包可以去这里下载: https://download.csdn.net/download/xiaolong1126626497/20687600

imgimgimgimgimgimgimgimgimgimgimgimgimgimgimgimgimg

package com.controller;


import java.util.List;

import java.util.Map;


import javax.servlet.http.HttpSession;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;


import com.common.bean.MySessionContext;

import com.common.bean.ResultData;

import com.entity.User;

import com.mapper.UserMapper;


@RestController()

@RequestMapping('/user')

public class UserController {

@Autowired

private UserMapper um;

@PostMapping('changepswd.action')

ResultData changePswd(String token,@RequestBody Map map) {

HttpSession ss = MySessionContext.getSession(  token );

if( ss == null ) {

return ResultData.fail('请先登录!');

}

User uu = (User) ss.getAttribute('login_user');

if( uu == null )  return ResultData.fail('请先登录!');

String password = map.get('password');

String newpassword = map.get('password2');

int num = um.updatePassword(uu.getId(), password, newpassword);

if( num > 0) return ResultData.success();

  return ResultData.fail('原始密码错误');

}

@PostMapping('adduser.action')

ResultData addUser(String token,@RequestBody User user) {

HttpSession ss = MySessionContext.getSession(  token );

if( ss == null ) {

return ResultData.fail('请先登录!');

}

 

User uu = (User) ss.getAttribute('login_user');

System.out.println( uu );

if( uu == null )  return ResultData.fail('请先登录!');

 

if( !('admin'.equalsIgnoreCase(uu.getRole()) ||

    'root'.equals( uu.getRole() )    )  )   {

return ResultData.fail('请用管理员账号登录再添加');

}

um.addUser(user);

return ResultData.success();

}

@PostMapping('delete.action')

ResultData deleteUser(String token,@RequestBody User user) {

System.out.println( user);

HttpSession ss = MySessionContext.getSession(  token );

if( ss == null ) {

return ResultData.fail('请先登录!');

}

 

User uu = (User) ss.getAttribute('login_user');

if( uu == null )  return ResultData.fail('请先登录!');

if('admin'.equalsIgnoreCase(user.getRole()) || 'root'.equals( user.getRole() ))  return ResultData.fail('无法删除管理员用户!');

 

if( !('admin'.equalsIgnoreCase(uu.getRole()) ||

    'root'.equals( uu.getRole() )    )  )   {

return ResultData.fail('请用管理员账号登录再删除');

}

um.deleteUser(user);

return ResultData.success();

}

@PostMapping('getall.action')

ResultData getAll(String token) {

HttpSession ss = MySessionContext.getSession(  token );

if( ss == null ) {

return ResultData.fail('请先登录!');

}

List list = um.getAll();

for(User u:list) {

u.setPassword(null);

}

return ResultData.success().setData( list );

}

@PostMapping('logout.action')

ResultData getAllUser(String token) {

HttpSession ss = MySessionContext.getSession(  token );

if( ss != null ) {

ss.invalidate();

}

return  ResultData.success();

}

@PostMapping('login.action')

ResultData login(@RequestBody User user,HttpSession ss) {

User rs = um.Login( user );

if(rs != null ) {

rs.setPassword( null );

ss.setAttribute('login_user', rs );

MySessionContext.AddSession( ss );

return  ResultData.success().setData( rs ).setToken(ss.getId() );

}else {

return ResultData.fail('用户名或密码错误!');

}

}

}

,string>

package com.common.wx;


import org.springframework.web.socket.WebSocketSession;

import org.springframework.web.socket.handler.TextWebSocketHandler;


import com.common.bean.WebSocketProductHolder;


public class WebSocketServerService extends TextWebSocketHandler{

 

@Override

public void afterConnectionEstablished(WebSocketSession session) throws Exception {

WebSocketProductHolder.setSession( session );

}


复制

package com.common.bean;

import java.io.IOException;

import java.net.ServerSocket;

import java.net.Socket;


import org.springframework.beans.BeansException;

import org.springframework.context.ApplicationContext;

import org.springframework.context.ApplicationContextAware;

import org.springframework.stereotype.Component;

import org.springframework.web.socket.TextMessage;

import org.springframework.web.socket.WebSocketSession;


import com.alibaba.fastjson.JSONObject;

import com.entity.Product;

import com.mapper.ProductMapper;


@Component

public class WebSocketProductHolder implements ApplicationContextAware{

private volatile static WebSocketSession oneSession;

private volatile static Socket client;

public WebSocketProductHolder() {

initServer();

}

public static void setSession(WebSocketSession ss) {

oneSession = ss;

}

 

private static void initServer()   {

new Thread() {

public void run() {

ServerSocket ss = null;

try {

ss = new ServerSocket(9988);

System.out.println('初始化');

while(true) {

client = ss.accept();

byte [] b = new byte[128];

try {

while(true) {

int num = client.getInputStream().read(b);//数据少,一次读完就阻塞。

if(num != -1 ) {

String cmd = new String(b,0,num);

parseCMD( cmd);

}

}

}catch (Exception e) {

System.out.println('连接断开...');

}

}

}catch (Exception e) {

}

}

}.start();

}

public static void register(String cardid)throws IOException {

if(cardid!=null && cardid.length() >0 && 

client!=null && client.isConnected()) {

client.getOutputStream().write(('register:'+cardid+'rn').getBytes());

}

}

 

private static void parseCMD(String cmd) {

if(cmd.startsWith('query')) {

try {

String cardid = cmd.split(':')[1].trim();

if(  oneSession != null ) {

oneSession.sendMessage( new TextMessage( cardid ) );

}catch (Exception e) {

System.out.println('数据错误:'+cmd);

}

  

}

}

@Override

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

initServer();

}

}

进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 1瓦线性调频增强器

  • 家用电器遥控器

  • 12V 转 28V DC-DC 变换器(基于 LM2585)

  • 红外开关

  • DS1669数字电位器

  • HA1377 桥式放大器 BCL 电容 17W(汽车音频)

    相关电子头条文章