python串口通信连接STM-F103单片机+Mysql数据库+Gui图形界面

目录

一、环境与说明

1.1、环境

1.2、说明

二、完整源代码

三、运行过程

3.1、总体过程描述


一、环境与说明

1.1、环境

操作系统:win10 家庭版

编辑器:pycahrm edu

版本: python 3.10

数据库:mysql

1.2、说明

使用说明:

关于程序:
    本次内容是门禁卡系统的软件部分,有图形界面显示、录入卡号、刷卡进门、数据库保存数据-->掉电存储的功能;


关于串口:
    使用python的串口库,连接单片机,需要使用串口模块接入电脑的端口;


关于数据库:
    使用python的数据库连接库,连接到数据库,需要下载好数据库并建相应的表与字段;


关于串口接收数据:
    串口接收到字符串数组类型的'12'(这个是关键,因为这个类型发过来的数据(发过来的数据是字节流的16进制数据)可以直接进行编码为十进制数,更好处理),进入保存状态,把接下来的发送的数据包内容保存到数据库中;


关于界面:
    界面是tk写的,把接收到的数据显示在行,并3秒刷新一次界面更新数据;

使用的库:

import serial  # 串口库
import time

import 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(这个数字是编码后的),则进行数据库的比对,数据库存在该数据则向单片机回传信号,单片机进行开门的处理。若数据库比对未发现该内容,则返回不符合,并向单片机发送回传信号。        

猜你喜欢

转载自blog.csdn.net/qq_57663276/article/details/127936995