目录
一、环境与说明
1.1、环境
操作系统:win10 家庭版
编辑器:pycahrm edu
版本: python 3.10
数据库:mysql
1.2、说明
使用说明:
关于程序:
本次内容是门禁卡系统的软件部分,有图形界面显示、录入卡号、刷卡进门、数据库保存数据-->掉电存储的功能;
关于串口:
使用python的串口库,连接单片机,需要使用串口模块接入电脑的端口;
关于数据库:
使用python的数据库连接库,连接到数据库,需要下载好数据库并建相应的表与字段;
关于串口接收数据:
串口接收到字符串数组类型的'12'(这个是关键,因为这个类型发过来的数据(发过来的数据是字节流的16进制数据)可以直接进行编码为十进制数,更好处理),进入保存状态,把接下来的发送的数据包内容保存到数据库中;
关于界面:
界面是tk写的,把接收到的数据显示在行,并3秒刷新一次界面更新数据;
使用的库:
import serial # 串口库
import timeimport pymysql # 连接数据库的库
# 图形界面库
import tkinter
from tkinter import *
import tkinter as tk
二、完整源代码
2.1、源代码如下
注意:下面的连接数据库,我把x换成了passwd,移植测试时,注意识别并更改。
import serial # 串口库
import time
import pymysql # 连接数据库的库
import threading # 多线程库
# 图形界面库
import tkinter
from tkinter import *
import tkinter as tk
# 数据库部分
class OperationMysql:
def __init__(self):
# 创建一个连接数据库的对象
self.conn = pymysql.connect(
host='127.0.0.1', # 连接的数据库服务器主机名
port=3306, # 数据库端口号
user='数据库用户', # 数据库登录用户名
x='登录', # passwd
db='ittest', # 数据库名称
# charset='gbk', # 连接编码
cursorclass=pymysql.cursors.DictCursor
)
# 使用cursor()方法创建一个游标对象,用于操作数据库
# self.conn.ping(reconnect=True) # 超时重新连接,这个很重要
self.cur = self.conn.cursor()
# 查询一条数据
def search_one(self, sql):
self.conn.ping(reconnect=True)
self.cur.execute(sql)
# result = self.cur.fetchone() # 使用 fetchone()方法获取单条数据.只显示一行结果
result = self.cur.fetchall() # 显示所有结果
self.conn.commit() # 增删改操作完数据库后,需要执行提交操作
# self.cur.close()
return result
# 更新SQL
def updata_one(self, sql):
try:
self.conn.ping(reconnect=True)
self.cur.execute(sql) # 执行sql
self.conn.commit() # 增删改操作完数据库后,需要执行提交操作
# self.cur.close()
except:
# 发生错误时回滚
self.conn.rollback()
self.conn.close() # 记得关闭数据库连接
# 插入SQL
def insert_one(self, sql):
try:
self.conn.ping(reconnect=True)
self.cur.execute(sql) # 执行sql
self.conn.commit() # 增删改操作完数据库后,需要执行提交操作
# self.cur.close()
except:
# 发生错误时回滚
self.conn.rollback()
self.conn.close()
# 删除sql
def delete_one(self, sql):
try:
self.conn.ping(reconnect=True)
self.cur.execute(sql) # 执行sql
self.conn.commit() # 增删改操作完数据库后,需要执行提交操作
# self.cur.close()
except:
# 发生错误时回滚
self.conn.rollback()
self.conn.close()
# 串口部分
ser = serial.Serial()
def open_port():
ser.port = 'COM3' # 端口
ser.baudrate = 115200 # 波特率
ser.bytesize = 8 # 数据位
ser.stopbits = 1 # 停止位
# ser.parity = "N" # 奇偶经验位
ser.open()
if ser.isOpen():
print("串口打开成功")
else:
print("串口打开失败")
def close_port():
ser.close()
if ser.isOpen():
print("串口关闭失败!")
else:
print("串口关闭成功!")
# 发数据
def send_data(data):
# date = data
if ser.isOpen():
ser.write(data.encode('utf-8'))
print("发送成功", data)
else:
print("发送失败!")
# 卡号符合返回k
def ok_ack():
global one_flag
global two_flag
one_flag = 1
two_flag = 1
send_data('k')
def no_ok_ack():
send_data('m')
# 接收发送的数据
# 12录入信息 其它开门
def reciver_data():
global all_data
all_data = '0'
global pid_t
global flag
# one_ser = OperationMysql()
# 定义全局变量列表,给全部需要使用数据的地方使用
global one_data
global two_data
two_data = '0'
global ones_data
ones_data = '0'
global id_flag
global one_flag
global two_flag
if ser.in_waiting:
t_data = ser.read(2).decode('ascii')
time.sleep(3)
all_data = ser.read_all().decode('ascii') # 接收全部
one_data = all_data
print("接收成功", all_data)
print(type(two_data))
print(type('11'))
print(t_data)
if (all_data[1] >= 'A') and (all_data[1] <= 'Z'):
ones_data = all_data
# print("卡号", one_data)
# eilf
if (all_data[1] >= '0') and (all_data[1] <= '9'):
two_data = all_data
# print("温湿度", two_data)
# 录卡信息
if t_data == '11':
print('录卡部分进入成功')
s = [0,0,0,0,0,0,0,0]
s = one_data[0:8]
print(s)
pid_t = one_data + "s"
one_sql = "insert into f_test(id,pid) values('%s','%s')" % (s, pid_t) # pid_t应该是有序递增的
print(one_data)
op_mysql.insert_one(one_sql)
print("插入完成")
flag = 1
# 进门
else:
dic = {}
all_da = [0, 0, 0,0,0,0,0,0,0,0,0,0]
dit = {}
two_dit = {}
# 构造查找语句取出数据库的值,给字典
two_sql = "select id from f_test;"
dic = op_mysql.search_one(two_sql)
print(len(dic))
lengh=len(dic)
for x in range(lengh):
all_da[x] = dic[x].get('id')
print(all_da)
#all_da[i] = dic[0]
print(dic)
# 取出字典的键:值数据进行与串口接收到的数据all_data比较 用循环应该比较好
for o in all_da:
# print(o)
if o == all_data:
# print(i)
print("卡号符合")
ok_ack()
two_flag = 1
id_flag = 1
one_flag = 1
if id_flag == 0:
print("卡号不符合")
# no_ok_ack()
# 界面内容显示部分
def show_id():
if id_flag == 1:
dic_one = ones_data
return dic_one
else:
return '数据暂无'
def show_pid():
if id_flag == 1:
dic_two = ones_data + 's'
return dic_two
else:
return '数据暂无'
# 温度返回
def show_dht11_t():
if two_flag == 1:
three_data = two_data
data1 = three_data[0:2]
data2 = three_data[2:4]
temp = min(data1, data2)
return temp
else:
return 0
# 湿度返回
def show_dht11_s():
if two_flag == 1:
four_data = two_data
data1 = four_data[0:2]
data2 = four_data[2:4]
shidu = max(data1, data2)
return shidu
else:
return 0
def set_values():
c_id.set(show_id())
p_id.set(show_pid())
# door_s.set(show_door())
dht11_s.set(show_dht11_s())
dht11_t.set(show_dht11_t())
def open_door():
ok_ack()
def off_door():
no_ok_ack()
def show_tk():
ser1 = tkinter.Tk()
# 标题
ser1.title("门禁界面")
# 窗口大小与出现位置
ser1.geometry("300x300+500+200")
one_l = Label(ser1, text="卡号")
global c_id
c_id = tk.StringVar()
one_e = Entry(ser1, width=45, textvariable=c_id)
# c_id.set(show_id())
two_l = Label(ser1, text="卡序号")
global p_id
p_id = tk.IntVar()
two_e = Entry(ser1, width=45, textvariable=p_id)
# p_id.set(show_pid())
'''
three_l = Label(ser1, text="门状态")
global door_s
door_s = tk.StringVar()
three_e = Entry(ser1, width=45, textvariable=door_s)
# door_s.set(show_door())
'''
four_l = Label(ser1, text="湿度")
global dht11_s
dht11_s = tk.IntVar()
four_e = Entry(ser1, width=45, textvariable=dht11_s)
# dht11_s.set(show_dht11())
five_l = Label(ser1, text="温度")
global dht11_t
dht11_t = tk.IntVar()
five_e = Entry(ser1, width=45, textvariable=dht11_t)
bt1 = Button(ser1, text="开门", command=open_door)
bt2 = Button(ser1, text="关门", command=off_door)
one_l.pack(anchor="nw")
one_e.pack(anchor="nw")
two_l.pack(anchor="nw")
two_e.pack(anchor="nw")
'''
three_l.pack(anchor="nw")
three_e.pack(anchor="nw")
'''
four_l.pack(anchor="nw")
four_e.pack(anchor="nw")
five_l.pack(anchor="nw")
five_e.pack(anchor="nw")
bt1.pack(anchor="center")
bt2.pack(anchor="center")
set_values()
# 创建显示
ser1.after(3000, ser1.destroy)
ser1.mainloop()
if __name__ == '__main__':
global id_flag
global one_flag
global ones_data
global one_data
global two_data
global all_data
id_flag = 0
one_flag = 0
two_flag = 0
op_mysql = OperationMysql()
open_port()
while True:
reciver_data()
time.sleep(3)
show_tk()
三、运行过程
3.1、总体过程描述
首先,python串口等待接收数据,若没有数据,则图形界面开始显示(因为没有数据,此时图形界面也是没有数据显示的),3秒过后图形界面消失;
之后,串口继续等待接收数据(这个数据大约为1.5秒),若有数据发送,则判断发送的数据是否是12(这个数字是编码后的),若是,则把接下来的发送数据前8个字节进行保存到数据库中,若不是数字12(这个数字是编码后的),则进行数据库的比对,数据库存在该数据则向单片机回传信号,单片机进行开门的处理。若数据库比对未发现该内容,则返回不符合,并向单片机发送回传信号。