应变片信号采集--串口程序
- 解决方案
利用python中的serial串口通信工具包实现与下位机通信,利用tkinter工具包编写GUI界面用于实时显示采集到的信号和传输指令。
界面设计:
最终效果:
参考代码:
#应变信号采集(为保证测量精确度,可将砝码及物体的质量扩大100000倍,代入计算)
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import threading
import tkinter as tk
import serial.tools.list_ports
from tkinter import ttk
from tkinter import scrolledtext
#创建存档文件
file=open('data.csv', 'w+')
#定义父容器
SerialPort = serial.Serial()
GUI = tk.Tk() # 父容器
GUI.title("Serial Tool") # 父容器标题
GUI.geometry("440x600") # 父容器大小
#显示操作信息的框图
Information = tk.LabelFrame(GUI, text="操作信息", padx=10, pady=10) # 创建一个框架
Information.place(x=20, y=20) #将该框架放在x=20,y=20的地方
Information_Window = scrolledtext.ScrolledText(Information, width=20, height=5, padx=10, pady=10, wrap=tk.WORD) #创建一个有滚动条的文本框
Information_Window.grid()
#创建发送指令框架
Send = tk.LabelFrame(GUI, text="发送指令", padx=10, pady=5) # 水平,垂直方向上的边距均为 10
Send.place(x=240, y=20)
# 定义保存文本框内容的字符串
DataSend = tk.StringVar() #输出窗的内容
EntrySend = tk.StringVar() #输入窗的内容
#创建输入窗口
Send_Window = ttk.Entry(Send, textvariable=EntrySend, width=23) #窗口的指令为 textvariable,
Send_Window.grid()
#将输入的指令输出到输出窗口,并执行指令
def WriteData():
global DataSend
DataSend = EntrySend.get()
Information_Window.insert("end", '发送指令为:' + str(DataSend) + '\n') # 在操作信息窗口显示发送的指令并换行,end为在窗口末尾处显示
Information_Window.see("end") # 此处为显示操作信息窗口进度条末尾内容,以上两行可实现窗口内容满时,进度条自动下滚并在最下方显示新的内容
SerialPort.write(bytes(DataSend, encoding='utf8'))#将指定的字符串写入串行端口。发送命令,编码成utf8格式
#设置一个激活以上操作的按钮
tk.Button(Send, text="发送", command=WriteData).grid(pady=5, sticky=tk.E) #放在最东面
#接收文本框(带滚动条)
Receive = tk.LabelFrame(GUI, text="接收区", padx=10, pady=10) # 水平,垂直方向上的边距均为 10
Receive.place(x=240, y=124)
Receive_Window = scrolledtext.ScrolledText(Receive, width=18, height=9, padx=8, pady=10, wrap=tk.WORD)
Receive_Window.grid()
#建立系数
#设定初始值
k=1.0
b=0.0
text1=tk.Label(GUI, text="k:",padx=10, pady=10) #Label组件用于显示文本和图像
text1.place(x=220, y=350)
text2=tk.Label(GUI, text="b:",padx=10, pady=10)
text2.place(x=220, y=380)
v1 = tk.StringVar()
v2 = tk.StringVar()
e1 = tk.Entry(GUI,textvariable=v1)
e2 = tk.Entry(GUI,textvariable=v2)
e1.place(x=290, y=360)
e2.place(x=290, y=390)
def insert_1():
global k,b
k = v1.get()
k=float(k)
b = v2.get()
b = float(b)
b2=tk.Button(GUI,text='输入参数',width=8,height=1,command=insert_1)
b2.place(x=290, y=420)
#建立物品质量框图
result = tk.LabelFrame(GUI, text='物品质量 /g', padx=10, pady=10) # 水平,垂直方向上的边距均为 10
result.place(x=20, y=350)
result_Window = scrolledtext.ScrolledText(result, width=18, height=9, padx=8, pady=10, wrap=tk.WORD)
result_Window.grid()
#传输数据选项框图
option = tk.LabelFrame(GUI, text="选项", padx=10, pady=10) # 水平,垂直方向上的边距均为10
option.place(x=20, y=150, width=203) # 坐标位置
# 创建下拉列表
ttk.Label(option, text="串口号:").grid(column=0, row=0) # 添加串口号标签,第0行第0列
ttk.Label(option, text="波特率:").grid(column=0, row=1) # 添加波特率标签
#建立端口号列表
Port = tk.StringVar() # 端口号字符串
Port_list = ttk.Combobox(option, width=12, textvariable=Port, state='readonly')#创建下拉菜单栏
ListPorts = list(serial.tools.list_ports.comports())#扫描当前可用串口保存到表ListPorts
Port_list['values'] = [i[0] for i in ListPorts]## 下拉列表的值为ListPorts的所有值
Port_list.current()# 初始显示表中第一个值
Port_list.grid(column=1, row=0) # 设置其在界面中出现的位置
#建立波特率列表
BaudRate = tk.StringVar() # 波特率字符串
BaudRate_list = ttk.Combobox(option, width=12, textvariable=BaudRate, state='readonly')
BaudRate_list['values'] = (1200, 2400, 4800, 9600, 14400, 19200, 38400, 43000, 57600, 76800, 115200)
BaudRate_list.current(5)# 初始显示19200
BaudRate_list.grid(column=1, row=1) # 设置其在界面中出现的位置 column代表列 row 代表行
#开关框图
switch = tk.LabelFrame(GUI, text="开关", padx=10, pady=10) # 水平,垂直方向上的边距均为 10
switch.place(x=20, y=250, width=203) # 定位坐标
#不断读取串口数据,并计算
def ReceiveData():
while SerialPort.isOpen():
Receive_Window.insert("end", str(SerialPort.readline()) + '\n') #在接收窗口不断显示接受的数据,一行一行地读数据
Receive_Window.see("end")
#number = int.from_bytes(str(SerialPort.readline()), byteorder='big') #全部读取的方式,一般不用
# 转换字符串为16进制,再转换为10进制。
data = SerialPort.readline()#读取的数据类型为字节类型
str1 = data.hex() # 转换为16进制,解码
num0 = str1[6:] # 截取需要的数据部分
num1 = int(num0, 16) # 转换为10进制
print(num1)
file = open('data.csv', 'a')
file.write(str(num1) + '\n')
file.close()
num1=float(num1)
result_Window.insert("end", str(b+k*num1) + '\n')#将字节串转换为数字并求出方程
result_Window.see("end")
#关闭数据的读取
def Close_Serial():
SerialPort.close()
#打开数据读取
def Open_Serial():
if not SerialPort.isOpen():
SerialPort.port = Port_list.get()# 读取端口下拉菜单栏的选择,将其设为串口的端口
SerialPort.baudrate = BaudRate_list.get()# 读取波特率下拉菜单栏的选择,将其设为串口的波特率
SerialPort.timeout = 0.1
SerialPort.open() # 打开串口
if SerialPort.isOpen():
t = threading.Thread(target=ReceiveData) # 新建线程用来不断接收数据并显示,与主线程并行
t.setDaemon(True)# 守护线程
t.start()# 开始线程
else:
SerialPort.close()
#设置开始和结束按钮,并执行指令
tk.Button(switch, text="开始采集", command=Open_Serial).pack(side="left", padx=13)
tk.Button(switch, text="停止采集", command=Close_Serial).pack(side="right", padx=13)
GUI.mainloop()
#程序还是有点小问题,敬请改正#