用Visual Basic或者C#, LabVIEW等软件开发的上位机界面,和文本式交互界面比较而言,就是可以用图形方式来显示数据。那么python可不可以用图形来显示数据呢?Of course! 和串口通讯,保存文件一样,绘制曲线对于python而言也是易如反掌。接下来,就让大伙儿看看我的神操作。
绘制曲线,我们可以使用python自带的Turtle(海龟画图)模块。绘图的基本步骤如下:
- 导入Turtle模块
- 设定画笔的宽度,速度,颜色等
- 抬起画笔,移动画笔到起点,放下画笔,移动画笔到终点。
- 重复2、3步骤,直到图形画完。
Turtle的常用的绘图函数有:
turtle.home() - 将位置和方向恢复到初始状态,位置初始坐标为(0,0),方向初始为("standard"模式为right向右即东,"logo"模式是up向上即北)
turtle.dot(size, *color) - 按给定直径size画圆点, color圆点颜色
turtle.speed(speed) – 设置画笔的速度,speed为0-10的整数(1-10越来越快,但是0表示最快)
turtle.pencolor(*args) - 设置或返回画笔颜色(设置后海龟箭头的外轮廓也是这个颜色)
turtle.pensize(width) – 设置画笔宽度
turtle.pendown() - 画笔落下,海龟移动时将画线
turtle.penup() - 画笔抬起,海龟移动时不画线
turtle.goto(x,y) - 前往一个绝对坐标
turtle.left(angle) - 画笔方向向左转,angle为左转的角度
turtle.right(angle) - 画笔方向向右转,angle为右转的角度
turtle.write(arg, move=False, align=“left”, font=(“Arial”, 8, “normal”)) - 绘制文字,arg为要绘制的纹波,align为对齐方式,font为字体
turtle.showturtle() - 显示画笔(即海龟箭头)
turtle.hideturtle() - 隐藏画笔(即海龟箭头)
turtle.clear() - 清屏并且画笔形状也恢复默认,保持画笔位置和方向不变
这些函数的命名真是简单直观而易懂。和我们用笔画图的动作也非常相似。相信大家几分钟之内就能掌握,并且画出自己的第一个图形。
当python从串口中读取到数据存储到列表data中以后,我们就可以把data中的数据按照时间顺序,把这些数据用图形显示出来:
- 先绘制x轴和y轴,x轴表示的是时间,y轴表示收到的数据的值的大小。
turtle.speed(0) #画笔速度,10为最慢
turtle.goto(200,0) #画时间轴
turtle.write("时间") #标注为时间轴
turtle.penup() #抬起画笔
turtle.goto(0,200) #到y轴的终点
turtle.write("数据") #标注为数据轴
turtle.pendown() #画笔落下
turtle.home() #绘制y轴,同时画笔回到原点,
- 选择画笔颜色
turtle.pencolor("blue") #重新选择画笔颜色为蓝色
- 计算每个数据点的x坐标和y坐标
for i in range(len(data)): #把所有的数据循环一遍
x = i*20 #设置时间值,比如20ms一个点
y = int(data[i]) #获取y的值
- 绘制每一个点
turtle.goto(x,y) #画笔移动到x,y坐标
turtle.dot(5,"red")#在该点绘制一个红色圆点
- 抬起画笔,回到原点,绘图结束
turtle.penup() #画笔抬起
turtle.home() #画笔回到原点,画线结束
下图是整个程序的源代码:
import serial #导入串口模块
import time #导入时间模块,时间模块是Python自带模块,无需安装
import csv #导入csv模块,csv模块是Python自带模块,无需安装
import turtle #导入Turtle画图模块,此模块为Python自带,无需安装
try:
SCI1 = serial.Serial("com15",9600,timeout=50) #打开串口,并且获得串口对象
#判断是否打开成功
if (SCI1.isOpen()==True):
print("串口已经打开!")
except Exception as exc:
print("串口打开异常:",exc)
while True:
commandFromECU = input("请输入控制命令,c-向ECU发送命令;r-从ECU中读取数据。") #从键盘上输入一个命令
SCI1.write(str(commandFromECU).encode("utf-8")) #将键盘输入的控制命令发送给ECU上的单片机
if commandFromECU == 'r': #如果是读取数据,则从串口中接收数据。
data = [] #将data列表清空,准备存放新的数据
time.sleep(1) #等待1秒,等待接收ECU上单片机返回的数据. ECU会依次发送0x30-0x39等10个数据
bufferSize = SCI1.in_waiting #接收ECU上单片机发过来的数据,并且返回数据的大小
print("接收到",str(bufferSize),'个数据') #打印缓冲区中接收到数据的个数
for i in range(bufferSize):
data.append(SCI1.read(1).hex()) #将接收缓冲区中数据读取到data中
print(data)
#将数据保存到csv文件中
with open ('C:\\Users\\tti\\Desktop\\python\\test.csv', 'a+',newline='') as file1: #打开文件,在文件末尾,追加数据
writer = csv.writer(file1) #创建一个实例
writer.writerow(data) #给csv文件写入一行数据
#把接收到的数据打印成曲线输出
turtle.speed(0) #画笔速度,10为最慢
turtle.goto(200,0) #画时间轴
turtle.write("时间") #标注为时间轴
turtle.penup() #抬起画笔
turtle.goto(0,200) #到y轴的终点
turtle.write("数据") #标注为数据轴
turtle.pendown() #画笔落下
turtle.home() #绘制y轴,同时画笔回到原点,
turtle.pencolor("blue") #重新选择画笔颜色为蓝色
for i in range(len(data)): #把所有的数据循环一遍
x = i*20 #设置时间值,比如20ms一个点
y = int(data[i]) #获取y的值
turtle.goto(x,y) #画笔移动到x,y坐标
turtle.dot(5,"red")#在该点绘制一个红色圆点
turtle.penup() #画笔抬起
turtle.home() #画笔回到原点,画线结束
time.sleep(1) #等待1秒
if(input("如果退出,请输入n,如果继续发送命令,请按其他键 ") == 'n'):
break
SCI1.close() #关闭端口