| @ -1,157 +1,168 @@ | |||||
| # -*- coding: utf-8 -*- | |||||
| """ | |||||
| Created on Wed Feb 15 10:44:49 2023 | |||||
| @author: david | |||||
| """ | |||||
| from threading import Thread | |||||
| import collections #Colección de datos para graficarlos | |||||
| import matplotlib.pyplot as plt #Gráficación de datos | |||||
| import matplotlib.animation as animation #Animar la gráfica | |||||
| import time | |||||
| import serial | |||||
| #import numpy as np | |||||
| from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg #Crear una figura para insertar en tkinter | |||||
| import tkinter as tk #Para la interfaz | |||||
| #from matplotlib.lines import Line2D | |||||
| def leer_datos(): | |||||
| time.sleep(1.0) | |||||
| arduino.reset_input_buffer() | |||||
| print("leyendo") | |||||
| while(isRun): | |||||
| global isReceiving | |||||
| global dato1 | |||||
| print("RECIBIENDO...") | |||||
| dato1 = float(arduino.readline().decode("utf-8").strip()) | |||||
| print(dato1) | |||||
| var.set("TEMPERATURA: " + str(dato1) + " °C") | |||||
| isReceiving = True | |||||
| def iniciarGrafica(self, muestras,lines): | |||||
| global dato1 | |||||
| data.append(dato1) | |||||
| lines.set_data(range(muestras), data) | |||||
| global isRun | |||||
| isReceiving = False | |||||
| isRun = True | |||||
| dato1 = 0.0 | |||||
| serialPort = 'COM3' | |||||
| baudRate = 9600 | |||||
| def conectar_serial(): | |||||
| global arduino | |||||
| try: | |||||
| arduino = serial.Serial(serialPort, baudRate) | |||||
| arduino.timeout = 0.5 | |||||
| time.sleep(0.5) | |||||
| print("CONECTADO") | |||||
| btnStart.config(state = "normal") | |||||
| btnConectar.config(state = "disabled") | |||||
| except: | |||||
| print("Error de conexión") | |||||
| def iniciar_hilo(): | |||||
| global thread | |||||
| thread = Thread(target=leer_datos) | |||||
| thread.start() | |||||
| btnStart.config(state = "disabled") | |||||
| btnPause.config(state = "normal") | |||||
| def guardarGrafica(): | |||||
| plt.savefig('miFigura.png') | |||||
| def control1(): | |||||
| window2 = tk.Toplevel() | |||||
| window2.resizable(width = 0, height = 0) | |||||
| window2.title('Control Manual') | |||||
| window2.geometry('500x300') | |||||
| def control2(): | |||||
| window3 = tk.Toplevel() | |||||
| window3.resizable(width = 0, height = 0) | |||||
| window3.title('Control ON/OFF') | |||||
| window3.geometry('500x300') | |||||
| def pausar(): | |||||
| anim.event_source.stop() | |||||
| btnResume.config(state = "normal") | |||||
| btnPause.config(state = "disabled") | |||||
| def reanudar(): | |||||
| anim.event_source.start() | |||||
| btnResume.config(state = "disabled") | |||||
| btnPause.config(state = "normal") | |||||
| def desconectar_serial(): | |||||
| global isRun | |||||
| anim.event_source.stop() | |||||
| isRun = False | |||||
| arduino.close() | |||||
| btnPause.config(state = "disabled") | |||||
| btnResume.config(state = "disabled") | |||||
| muestras = 100 | |||||
| data = collections.deque([0] * muestras, maxlen = muestras) | |||||
| tiempoMuestreo = 100 | |||||
| fig = plt.figure(facecolor = '0.94') | |||||
| ax = plt.axes(xlim=(0,100), ylim=(-40, 150)) | |||||
| plt.title("Sensor 1 - Arduino") | |||||
| ax.set_xlabel("Muestras") | |||||
| ax.set_ylabel("Voltaje") | |||||
| lines = ax.plot([], [])[0] | |||||
| root= tk.Tk() | |||||
| root.title("Sistema de calentamiento") | |||||
| var = tk.StringVar() | |||||
| frame = tk.Frame(root, bd=2) | |||||
| frame.grid(column=0, row=3, columnspan=2, sticky="nsew") | |||||
| frame1 = tk.Frame(root) | |||||
| frame1.grid(column=0, row=1, columnspan=2, sticky="EW") | |||||
| frame2 = tk.Frame(root) | |||||
| frame2.grid(column=0, row=2, columnspan=2, sticky="EW") | |||||
| frame0 = tk.Frame(root) | |||||
| frame0.grid(column=0, row=0, columnspan=2, sticky="EW") | |||||
| root.columnconfigure(0, weight=1) | |||||
| root.columnconfigure(1, weight=1) | |||||
| #self.master.rowconfigure(0, weigh=1) | |||||
| #self.master.rowconfigure(1, weigh=1) | |||||
| #self.master.rowconfigure(2, weigh=1) | |||||
| root.rowconfigure(3, weigh=5) | |||||
| canvas = FigureCanvasTkAgg(fig, master=frame) | |||||
| canvas.get_tk_widget().pack(padx=0, pady=0, expand=True, fill='both') | |||||
| btnManual = tk.Button(frame2, text = "Manual", command = control1) | |||||
| btnManual.grid(row=0, column=0, pady=2, padx=10) | |||||
| btnOnOff = tk.Button(frame2, text = "ON/OFF", command = control2) | |||||
| btnOnOff.grid(row=0, column=1, pady=2, padx=10) | |||||
| btnConectar = tk.Button(frame1, text = "Connect", command = conectar_serial, bg="#00F1FC") | |||||
| btnConectar.grid(row=0, column=0, pady=2, padx=10) | |||||
| btnStart = tk.Button(frame1, text = "Start", command = iniciar_hilo, bg="#008C17", state="disabled") | |||||
| btnStart.grid(row=0, column=1, pady=2, padx=10) | |||||
| btnPause = tk.Button(frame1, text = "Pause", command = pausar, bg="#E2E200", state="disabled") | |||||
| btnPause.grid(row=0, column=2, pady=2, padx=10) | |||||
| btnResume = tk.Button(frame1, text = "Resume", command = reanudar, bg="#00F428", state="disabled") | |||||
| btnResume.grid(row=0, column=3, pady=2, padx=10) | |||||
| btnDesconectar = tk.Button(frame2, text='Disconnect', command = desconectar_serial, bg="#FE5E5E") | |||||
| btnDesconectar.grid(row=0, column=3, pady=2, padx=10) | |||||
| labelData = tk.Label(frame2, textvariable=var) | |||||
| labelData.grid(row=0, column=4, pady=2, padx=500) | |||||
| barraMenu = tk.Menu(frame0) | |||||
| barra1 = tk.Menu(barraMenu) | |||||
| barra1.add_command(label="Guardar gráfica", command=guardarGrafica) | |||||
| barraMenu.add_cascade(label="Archivo", menu=barra1) | |||||
| root.config(menu=barraMenu) | |||||
| anim = animation.FuncAnimation(fig, iniciarGrafica, fargs=(muestras, lines), interval = tiempoMuestreo) | |||||
| root.geometry('1000x600') | |||||
| root.mainloop() | |||||
| # -*- coding: utf-8 -*- | |||||
| """ | |||||
| Created on Wed Feb 15 10:44:49 2023 | |||||
| @author: david | |||||
| """ | |||||
| from threading import Thread #Funciones para hilos | |||||
| import collections #Colección de datos para graficarlos | |||||
| import matplotlib.pyplot as plt #Gráficación de datos | |||||
| import matplotlib.animation as animation #Animar la gráfica | |||||
| import time #Delays | |||||
| import serial #comunicación con el monitor serial de Arduino | |||||
| from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg #Crear una figura para insertar en tkinter | |||||
| import tkinter as tk #Para la interfaz | |||||
| #Variables a utilizar | |||||
| global isRun #Valor booleano de programa corriendo | |||||
| isReceiving = False #Valor booleano de recibiendo datos | |||||
| isRun = True | |||||
| dato1 = 0.0 #Variable del dato a leer desde Arduino | |||||
| serialPort = 'COM3' #Puerto al que está conectado el Arduino | |||||
| baudRate = 9600 #Baudios configurados en Arduino | |||||
| #Función de lectura de datos en Arduino | |||||
| def leer_datos(): | |||||
| time.sleep(1.0) | |||||
| arduino.reset_input_buffer() #limpia el buffer de datos | |||||
| print("leyendo") | |||||
| while(isRun): | |||||
| global isReceiving #valor booleano de recibiendo datos | |||||
| global dato1 #dato a recibir desde Arduino | |||||
| print("RECIBIENDO...") | |||||
| dato1 = float(arduino.readline().decode("utf-8").strip()) #Lectura del dato y conversión a float | |||||
| print(dato1) | |||||
| var.set("TEMPERATURA: " + str(dato1) + " °C") #impresión del dato numérico en la interfaz | |||||
| isReceiving = True #Confirmación de que se ha recibido el dato | |||||
| #Función para iniciar la gráfica | |||||
| def iniciarGrafica(self, muestras,lines): | |||||
| global dato1 | |||||
| data.append(dato1) #Agrega el dato a la colección | |||||
| lines.set_data(range(muestras), data) #Se grafica en la línea la colección de datos | |||||
| #Establecer conexión con Arduino | |||||
| def conectar_serial(): | |||||
| global arduino #Variable que va aguardar la conexión | |||||
| try: | |||||
| arduino = serial.Serial(serialPort, baudRate) #Asignación del objeto a la variable | |||||
| arduino.timeout = 0.5 #Tiempo a esperar para que haya datos disponibles en el puerto serie | |||||
| time.sleep(0.5) #Tiempo muerto para permitir la conexión | |||||
| print("CONECTADO") | |||||
| btnStart.config(state = "normal") | |||||
| btnConectar.config(state = "disabled") | |||||
| except: | |||||
| print("Error de conexión") | |||||
| #Hilo para la lectura de datos constante | |||||
| def iniciar_hilo(): | |||||
| global thread #Variable donde guardar el hilo | |||||
| thread = Thread(target=leer_datos) #Creación del hilo con la función para leer los datos | |||||
| thread.start() #Inicio de la lectura | |||||
| btnStart.config(state = "disabled") | |||||
| btnPause.config(state = "normal") | |||||
| #Pestaña para guardar la gráfica | |||||
| def guardarGrafica(): | |||||
| plt.savefig('miFigura.png') | |||||
| #Ventana de control Manual (ON/OFF controlado por el usuario) | |||||
| def control1(): | |||||
| window2 = tk.Toplevel() | |||||
| window2.resizable(width = 0, height = 0) | |||||
| window2.title('Control Manual') | |||||
| window2.geometry('500x300') | |||||
| #Ventana para control según una temperatura dada (Automático) | |||||
| def control2(): | |||||
| window3 = tk.Toplevel() | |||||
| window3.resizable(width = 0, height = 0) | |||||
| window3.title('Control ON/OFF') | |||||
| window3.geometry('500x300') | |||||
| #Función para pausar la gráfica | |||||
| def pausar(): | |||||
| anim.event_source.stop() | |||||
| btnResume.config(state = "normal") | |||||
| btnPause.config(state = "disabled") | |||||
| #Función para continuar graficando | |||||
| def reanudar(): | |||||
| anim.event_source.start() | |||||
| btnResume.config(state = "disabled") | |||||
| btnPause.config(state = "normal") | |||||
| #Función para finaliar la conexión con Arduino | |||||
| def desconectar_serial(): | |||||
| global isRun | |||||
| anim.event_source.stop() | |||||
| isRun = False | |||||
| arduino.close() | |||||
| btnPause.config(state = "disabled") | |||||
| btnResume.config(state = "disabled") | |||||
| #Variables a graficar | |||||
| muestras = 100 #Número de datos a visualizar | |||||
| data = collections.deque([0] * muestras, maxlen = muestras) #Rango de datos | |||||
| tiempoMuestreo = 100 | |||||
| fig = plt.figure(facecolor = '0.94') #creación de la gráfica (figura) | |||||
| ax = plt.axes(xlim=(0,100), ylim=(-40, 150)) #Rango de ejes | |||||
| plt.title("Sensor 1 - Arduino") | |||||
| ax.set_xlabel("Muestras") | |||||
| ax.set_ylabel("Voltaje") | |||||
| lines = ax.plot([], [])[0] #Creación de la línea a graficar | |||||
| root= tk.Tk() | |||||
| root.title("Sistema de calentamiento") | |||||
| var = tk.StringVar() | |||||
| frame = tk.Frame(root, bd=2) | |||||
| frame.grid(column=0, row=3, columnspan=2, sticky="nsew") | |||||
| frame1 = tk.Frame(root) | |||||
| frame1.grid(column=0, row=1, columnspan=2, sticky="EW") | |||||
| frame2 = tk.Frame(root) | |||||
| frame2.grid(column=0, row=2, columnspan=2, sticky="EW") | |||||
| frame0 = tk.Frame(root) | |||||
| frame0.grid(column=0, row=0, columnspan=2, sticky="EW") | |||||
| root.columnconfigure(0, weight=1) | |||||
| root.columnconfigure(1, weight=1) | |||||
| #self.master.rowconfigure(0, weigh=1) | |||||
| #self.master.rowconfigure(1, weigh=1) | |||||
| #self.master.rowconfigure(2, weigh=1) | |||||
| root.rowconfigure(3, weigh=5) | |||||
| canvas = FigureCanvasTkAgg(fig, master=frame) | |||||
| canvas.get_tk_widget().pack(padx=0, pady=0, expand=True, fill='both') | |||||
| btnManual = tk.Button(frame2, text = "Manual", command = control1) | |||||
| btnManual.grid(row=0, column=0, pady=2, padx=10) | |||||
| btnOnOff = tk.Button(frame2, text = "ON/OFF", command = control2) | |||||
| btnOnOff.grid(row=0, column=1, pady=2, padx=10) | |||||
| btnConectar = tk.Button(frame1, text = "Connect", command = conectar_serial, bg="#00F1FC") | |||||
| btnConectar.grid(row=0, column=0, pady=2, padx=10) | |||||
| btnStart = tk.Button(frame1, text = "Start", command = iniciar_hilo, bg="#008C17", state="disabled") | |||||
| btnStart.grid(row=0, column=1, pady=2, padx=10) | |||||
| btnPause = tk.Button(frame1, text = "Pause", command = pausar, bg="#E2E200", state="disabled") | |||||
| btnPause.grid(row=0, column=2, pady=2, padx=10) | |||||
| btnResume = tk.Button(frame1, text = "Resume", command = reanudar, bg="#00F428", state="disabled") | |||||
| btnResume.grid(row=0, column=3, pady=2, padx=10) | |||||
| btnDesconectar = tk.Button(frame2, text='Disconnect', command = desconectar_serial, bg="#FE5E5E") | |||||
| btnDesconectar.grid(row=0, column=3, pady=2, padx=10) | |||||
| labelData = tk.Label(frame2, textvariable=var) | |||||
| labelData.grid(row=0, column=4, pady=2, padx=500) | |||||
| barraMenu = tk.Menu(frame0) | |||||
| barra1 = tk.Menu(barraMenu) | |||||
| barra1.add_command(label="Guardar gráfica", command=guardarGrafica) | |||||
| barraMenu.add_cascade(label="Archivo", menu=barra1) | |||||
| root.config(menu=barraMenu) | |||||
| #Animación de la gráfica (figura, función que grafica la línea, argumentos para graficar, rango de la figura) | |||||
| anim = animation.FuncAnimation(fig, iniciarGrafica, fargs=(muestras, lines), interval = tiempoMuestreo) | |||||
| root.geometry('1000x600') | |||||
| root.mainloop() | |||||