Informe 4 - Analizador Lógico y de Protocolo

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 20

Universidad Tecnológica Nacional

Facultad Regional Paraná

Especialidad:
Ingeniería Electrónica

Cátedra:
Medidas Electrónicas II

Informe N°4

Titular: Ing. Cappelletti, Carlos Alberto


Adjunto: Ing. Krenz, Mónica

Alumnos:
Genzelis, Ivan
Götte, Agustín Esteban
Hacen, Karim Isaac
José, Agustín Gabriel
Informe N°4 – Medidas Electrónicas II
Contenido
Introducción ........................................................................................................... 2
Hardware ............................................................................................................... 2
Circuito de entrada.................................................................................................. 2
Software RP2040 ................................................................................................... 5
Software (PC) ........................................................................................................ 6
Interfaz PC-Pico ..................................................................................................... 6
Análisis de Protocolos ............................................................................................ 8
Referencias .......................................................................................................... 10
Anexo ................................................................................................................... 11
untriggered-input.c ................................................................................................ 11
untriggered-input.pio ............................................................................................. 13
CMakeLists.txt ...................................................................................................... 14
ALyP_mainwindow.py ........................................................................................... 14

1
Informe N°4 – Medidas Electrónicas II
Introducción
En esta cuarta entrega se presentan los avances sobre el diseño, desarrollo e
implementación del analizador lógico y de protocolos.
Hardware
Circuito de entrada
En el capítulo anterior se propusieron algunos circuitos de protección contra
sobrevoltaje para las entradas de la Raspberry Pi Pico, donde se requería que la
tensión no sobrepase los 3,6[V] para proteger al microcontrolador. El circuito
propuesto más adecuado a nuestros requerimientos es el siguiente:

Figura 1
El transistor BJT PNP conduce cuando su juntura base emisor se polariza en
inversa, es decir, cuando la tensión en el emisor es mayor a la tensión en la base. Es
poca la corriente que se fuga por la base hacia la línea de 3,3[V], ya que la mayoría
circula por el colector hacia masa. La razón entre las corrientes de base y colector
está dada por la ganancia del transistor (hfe), que puede tener un valor entre 100 y
400. En la práctica, para mantener una tensión de 3,3[V] en la entrada del
microcontrolador, la tensión en la base tiene que ser menor que 3,3 [V] debido a la
caída de tensión en la juntura base-emisor del transistor. Este valor se encuentra en
la hoja de datos como Vbe(sat).
Se eligió el transistor 2n3906 para el circuito de protección, el cual tiene una V be(sat)
máxima de 0,95[V]. Ajustando la tensión de base con un divisor resistivo obtenemos
el siguiente circuito para la etapa de entrada:

Figura 2

2
Informe N°4 – Medidas Electrónicas II
Se realizaron pruebas utilizando un generador de onda cuadrada unipolar de 5[V]
de amplitud a diferentes frecuencias, midiendo con el osciloscopio la tensión en la
entrada del microcontrolador:

Señal a 500[kHz]:

Figura 3

Señal a 2[MHz]:

Figura 4

3
Informe N°4 – Medidas Electrónicas II
Señal a 5[MHz]

Figura 5
Los resultados de esta prueba indican que el cuello de botella en cuanto a
frecuencia máxima a medir de nuestro diseño de analizador lógico se ubica en la
etapa de entrada. Este valor máximo de operación en este circuito se encuentra entre
los 2 y 5 [MHz]. En consecuencia, siempre que mantengamos la velocidad de
muestreo a aproximadamente 10 veces la frecuencia de la señal de entrada,
podremos obtener una representación fiel de la señal medida para su posterior
procesamiento.
Con este avance de la etapa de entrada podemos trabajar con protocolos que
operen a una velocidad menor a 5 [MHz]. Entre ellos podemos encontrar al USB 1.0,
el cual tiene una velocidad máxima de bits de 1,5 [Mbits/s] y es muy utilizado en
periféricos como teclados, mouse y algunas webcam. Otro protocolo muy utilizado,
sobre todo en la industria es el I2C, que en su versión 2.0 trabaja con una tasa de bits
máxima de 3,4[Mbits/s]. Un estándar ampliamente utilizado en microcontroladores es
el UART, el cual opera a una velocidad máxima de 921,6[kbits/s] por lo que nuestro
instrumento nos permitiría trabajar con este protocolo. Otro caso es el del SPI, cuya
velocidad de clock puede alcanzar los 50[MHz], frecuencia para la cual nuestro
circuito de entrada no está preparado. No obstante, muchas implementaciones de
este protocolo se hacen a frecuencias mucho menores, que entran en el rango de
nuestro instrumento.

4
Informe N°4 – Medidas Electrónicas II
Software RP2040
Al igual que la entrega anterior, el programa que corre sobre el microcontrolador
consiste en tres archivos separados, cuyo contenido se puede encontrar en el anexo
al final del documento. El primero, untriggered-input.c contiene el bucle principal del
programa, cuyo diagrama de flujo es más o menos como sigue:

Configura
Inicio Adquiere PIO
Variables

Adquiere y Decodifica Muestrea y


configura DMA Mensaje Serial Transmite

Figura 6

El segundo archivo, untriggered_input.pio es un archivo en lenguaje ensamblador


que corre sobre el periférico Programmable Input Output. Este archivo no ha
cambiado en lo absoluto respecto de la anterior entrega.
Por último, el tercer archivo, CMakeLists.txt es un archivo que contiene directivas
para el asistente de compilación CMake. Como solo se han añadido librerías, no
existen modificaciones sustanciales respecto de la entrega pasada.

5
Informe N°4 – Medidas Electrónicas II
Software (PC)
Un script de Python (disponible en el anexo) con QT se encarga de la transmisión
de datos, cálculo e interfaz gráfica, que es como sigue:

Figura 7

Donde se muestran funcionando los 8 canales, 4 de ellos con una señal de 1 [KHz],
muestreando a 10 [KHz] por 1024 ciclos para obtener 8 [KSa]. La frecuencia de
muestreo es seleccionable en el combo box de la derecha, al igual que la cantidad de
muestras, y se ofrece un indicador del tiempo que toma llenar ese buffer. El botón de
muestrear solicita los datos a la Raspberry Pi Pico.
Debajo del visor gráfico, una barra navegadora asiste al usuario al moverse en la
gráfica. Están disponibles las funcionalidades de desplazamiento, volver al inicio,
zoom, guardar una captura, deshacer, rehacer y un menú completo con todas las
opciones ya mencionadas, entre otras.
El apartado “Puerto Serie” ofrece una simple ventana modal que muestra los
puertos disponibles, y permite elegir uno de ellos para el funcionamiento. Los botones
de configuración y archivo no tienen funcionalidad aún.
Interfaz PC-Pico
La interfaz consiste en una serie de comandos, que indican su comienzo con un
“#” y su fin con un “;”. Aunque son varios, su uso es bastante evidente y basta analizar
un ejemplo para comprender sus roles.
• “#H;” es un mensaje de prueba.
• “#ACK;” y “#NACK;” son acuses de recibo positivo y negativo, respectivamente.
También cumplen el rol de indicar el comienzo de la transmisión de datos, si
corresponde.
• “#EOF;” indica el final de una transmisión de datos.

6
Informe N°4 – Medidas Electrónicas II
• “#USXXXYZZZ;” es el comando para muestrear sin gatillado. “XXX” indica la
frecuencia de muestreo con tres dígitos, “Y” puede ser “M” o “K”, como
multiplicador de los dígitos en “XXX” y “ZZZ” indica el tamaño del buffer en
KiloBytes, con un máximo de 192.
Debajo, un diagrama del funcionamiento de estos comandos.

Figura 8

7
Informe N°4 – Medidas Electrónicas II
Análisis de Protocolos
En la entrega anterior se realizó una breve descripción de los protocolos más
utilizados por microcontroladores y se propusieron ideas sobre cómo procesar los
datos obtenidos por el hardware. En esta ocasión se pretende explorar más en detalle
estos protocolos y establecer algún algoritmo que permita de forma sencilla
decodificar el mismo, una vez que los datos ya se encuentran alojados en el software
de escritorio.
SPI
Como se mostró anteriormente, el protocolo SPI permite la comunicación serie de
manera síncrona entre un maestro y uno o más esclavos. Una de las principales
características de este es que emplea cuatro líneas para realizar la comunicación,
entre las que encontramos las llamadas MOSI y MISO, que envían datos al esclavo y
al maestro respectivamente, la SCLK que es la señal de clock que define el maestro
y finalmente el CS que indica el chip select del esclavo.
En este protocolo, la comunicación ocurre de forma bidireccional en cada ciclo de
reloj, lo que se conoce como full dúplex. En cada ciclo de clock el maestro enviara un
bit de la palabra a transmitir, una vez que el mensaje es recibido por el esclavo, se
completa un registro de desplazamiento del tamaño de palabra recibida. Luego, el
esclavo comenzara a transmitir en simultaneo con el maestro, los datos en su buffer.
Aquí podemos encontrar distintos modos de funcionamiento, dependiendo de cómo
se configura la comunicación se comenzará transmitiendo el bit más significativo
(MVB) o el menos significativo (LVB), variantes a tener en cuenta al momento de
decodificar el mismo.

Figura 9
Para el protocolo SPI la comunicación se establece de forma sencilla, el maestro
establece una señal de clock apta para el esclavo, cambia la señal CS a bajo y
comienza a transmitir. No existen bits de inicio o final, cuando se quiere finalizar la
comunicación el maestro detiene la señal de reloj y pone en alto el chip select.
Entendiendo el proceso de cómo se da la comunicación podemos realizar distintos
análisis de como decodificar el protocolo según los datos adquiridos. Si es está
empleando el modo sincrónico del analizador lógico, podemos simplemente tomar las
distintas señales según las interpretan los dispositivos. Distinto es el caso donde un
protocolo SPI fue muestreado con el modo asíncrono, con una frecuencia mayor a la
que se da la comunicación, aquí se dará el caso de que los datos se encuentran sobre
muestreados. Para solucionar este problema se deberán diezmar valores hasta que
solo quede uno por ciclo de reloj del sistema, generando así variantes en el algoritmo
para decodificar el protocolo.

8
Informe N°4 – Medidas Electrónicas II
Como bien vimos, dado que el protocolo emplea cuatro líneas para realzar la
comunicación deberemos tomar estas señales para poder decodificarlo. Existen
casos donde solo podríamos decodificar el mismo con la señal de reloj, MOSI y MISO,
esto funcionaria en sistemas sencillos, pero en casos donde existe más de un esclavo
puede que se desfasen las señales respecto del clock, generando lecturas erróneas.

Figura 10
I2C
A diferencia del SPI, este protocolo permite la comunicación entre múltiples
maestros y múltiples esclavos. A pesar de soportar menos velocidad que el SPI, este
reduce las líneas necesarias a dos, una señal de datos serie SDA y otra en la que
transmite la señal de reloj SCL. Al transmitirse todos los datos en una misma línea se
deben establecer reglas concretas para que la comunicación entre distintos
dispositivos funciones de manera apropiada. De esta forma, las tramas de I2C estarán
formadas por una señal de inicio, una dirección a donde están destinados los datos,
un bit para indicar si es una solicitud de lectura o escritura, los datos de ocho bits y
una señal de fin. Entre las distintas partes que conforman esta comunicación se
añaden los acknowledge (ACK), indicando que la comunicación se da de forma
correcta.

Figura 11
Cuando un maestro quiera iniciar una comunicación, lo primero que hace es
corroborar que el bus esté disponible, lo que corresponde a las señales SDA y SCL
en alto. Luego, dará la señal de que iniciará la comunicación haciendo que la señal
de SDA cambie de alto a bajo mientras SCL este en alto. Luego se enviará la dirección
de destino para la comunicación seguido del bit de lectura o escritura. Luego de
transmitir todos estos datos se deberá recibir el bit de ACK, el cual indica con un nivel
bajo de que la transmisión o comunicación fue exitosa. Dependiendo si se trabaja en
escritura o lectura el master enviará o recibirá datos de un byte seguidos de un bit de

9
Informe N°4 – Medidas Electrónicas II
ACK. Cuando se quiera finalizar la comunicación se dará la señal de stop, la cual
consiste en cambiar la señal SDA de un nivel bajo a uno alto cuando SCL pasa
también a un nivel alto.

Figura 12
Analizando cómo se da esta comunicación, podemos observar que debemos tomar
muestras de las señales al menos al doble de la frecuencia de SCL para poder
detectar el fin de datos. Siguiendo el modelo de las tramas y buscando los bits de
ACK podemos decodificar fácilmente este protocolo.

Referencias
1. C. F. Coombs, Electronic Instrument Handbook, McGraw-Hill.
2. Raspberry Pi, «RP2040 Datasheet,» 2020. [En línea]. Available:
https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf. [Último
acceso: 07 Agosto 2022].
3. Raspberry Pi, «C/C++ SDK,» 2020. [En línea]. Available:
https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-c-sdk.pdf. [Último
acceso: 07 Agosto 2022].
4. Codemy.com, “PyQt5 GUI Thursdays”(serie de videos). Youtube.
Disponible:https://www.youtube.com/watch?v=rZcdhles6vQ&list=PLCC34OH
NcOtpmCA8s_dpPMvQLyHbvxocY.[Último acceso: 07 Agosto 2022].
5. Microchip Technology Inc., «newark.com,» 2006. [En línea]. Available:
https://www.newark.com/pdfs/techarticles/microchip/3_3vto5vAnalogTipsnTric
ksBrchr.pdf. [Último acceso: Julio 2022].

10
Informe N°4 – Medidas Electrónicas II
Anexo
untriggered-input.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pico/stdlib.h"

#include "hardware/clocks.h"
#include "hardware/pio.h"
#include "untriggered_input.pio.h"
#include "hardware/dma.h"
#include "hardware/structs/bus_ctrl.h"

#define MASTER_BUFFER_SIZE (1024*192) // array size, equivalent to 3


internal SRAM banks
#define CMD_STRING_SIZE 25
#define ANSWER_HELLO "#H\n"
#define ACKNOWLEDGE "#ACK\n"
#define NEGATIVE_ACKNOWLEDGE "#NACK\n"
#define END_OF_FILE "#EOF\n"

int main (void)


{
sleep_ms(5000);
stdio_init_all();
const uint pinSwitch = 25;
gpio_init(pinSwitch);
gpio_set_dir(pinSwitch, GPIO_OUT);
PIO pio = pio0; // define PIO structure, buffer, and aux variables
uint8_t master_buffer[MASTER_BUFFER_SIZE] = {'$'};
uint32_t i = 0;
uint32_t sampling_freq = 1;
uint32_t sampling_count = 1;
float clock_divider = 1;
char serial_input;
char cmdString[CMD_STRING_SIZE];
bool cmdRxFinished = true;
uint8_t cmdStringIndex = 0;

// claim an unused pio, set the sampling program


uint sm = pio_claim_unused_sm(pio, true);
uint offset = pio_add_program(pio, &untriggered_input_program);

// set the priority from the bus to DMA, claim a channel and its
default config
// set also, data size, no read increment, yes write increment, and
DREQ.
// set origin and data destinations, but no starting yet
bus_ctrl_hw->priority = BUSCTRL_BUS_PRIORITY_DMA_W_BITS |
BUSCTRL_BUS_PRIORITY_DMA_R_BITS;
int transfer_dma_channel = dma_claim_unused_channel(true);
dma_channel_config transfer_dma_channel_config =
dma_channel_get_default_config(transfer_dma_channel);

11
Informe N°4 – Medidas Electrónicas II
channel_config_set_transfer_data_size(&transfer_dma_channel_config,
DMA_SIZE_8);
channel_config_set_read_increment(&transfer_dma_channel_config,
false);
channel_config_set_write_increment(&transfer_dma_channel_config,
true);
channel_config_set_dreq(&transfer_dma_channel_config,
pio_get_dreq(pio, sm, false));

// main loop, expect and decode messages


while (true)
{
serial_input = getchar_timeout_us(100);
// if we recieved a hashtag
if(serial_input == '#')
{ // store it and begin looping, expecting more chars as a
command
cmdString[0] = '#';
cmdRxFinished = false;
while(!cmdRxFinished)
{
serial_input = getchar_timeout_us(100);
if(serial_input != 255){} // if it is a char, store an
continue looping
{
cmdStringIndex++;
if(cmdStringIndex > (CMD_STRING_SIZE-1)){cmdRxFinished
= true; cmdStringIndex = 0;} // if the message is bigger than the buffer,
exit
else
{
cmdString[cmdStringIndex] = serial_input; //
unless its a semicolon, then stop looping and start decoding
if(serial_input == ';'){cmdRxFinished = true;
cmdStringIndex = 0;}
}
}
}
// decode strings and act accordingly
if (cmdString[1] == 'H')
{
printf(ANSWER_HELLO);
gpio_put(pinSwitch, 1);
sleep_ms(500);
gpio_put(pinSwitch, 0);
}
if (cmdString[1] == 'U' && cmdString[2] == 'S') //
{
sampling_freq = (atoi(&cmdString[3]));
if(cmdString[6] == 'M'){sampling_freq = sampling_freq *
1000000;}
else if(cmdString[6] == 'K'){sampling_freq = sampling_freq
* 1000;}
sampling_count = (atoi(&cmdString[7]));

12
Informe N°4 – Medidas Electrónicas II
if(sampling_count > 192){printf(NEGATIVE_ACKNOWLEDGE);}
else if(sampling_freq >
100000000){printf(NEGATIVE_ACKNOWLEDGE);}
else
{
gpio_put(pinSwitch, 1);
sampling_count = sampling_count * 1024;
clock_divider = (float)clock_get_hz(clk_sys) /
sampling_freq;
untriggered_input_program_init(pio, sm, offset, 0,
clock_divider);
pio_sm_set_enabled(pio, sm, true);
dma_channel_configure(transfer_dma_channel,
&transfer_dma_channel_config, master_buffer, &pio->rxf[sm],
sampling_count, true);
dma_channel_wait_for_finish_blocking(transfer_dma_chan
nel);
printf(ACKNOWLEDGE);
for(i=0;i<sampling_count;i++){printf("%d\n",master_buf
fer[i]);}
printf(END_OF_FILE);
gpio_put(pinSwitch, 0);
}
}
}
if(serial_input == 255){} // PICO_ERROR_TIMEOUT, VALOR QUE
DEVUELVE LA FUNCION SI HAY TIMEOUT ES -1, QUE PARA UN CHAR SE REPRESENTA
EN 255
}
}
untriggered-input.pio
.program untriggered_input

.wrap_target
in pins, 8
.wrap

% c-sdk {
static inline void untriggered_input_program_init(PIO pio, uint sm, uint
offset, uint pin, float clkdiv) {
pio_sm_config c =
untriggered_input_program_get_default_config(offset);

// Set the IN base pin to the provided `pin` parameter


sm_config_set_in_pins(&c, pin);

// Set the pin directions to input at the PIO


pio_sm_set_consecutive_pindirs(pio, sm, pin, 8, false);

// Set clock divider


sm_config_set_clkdiv(&c, clkdiv);

// Shifting to left matches the customary MSB-first ordering of SPI.

13
Informe N°4 – Medidas Electrónicas II
sm_config_set_in_shift(
&c,
false, // Shift-to-right = false (i.e. shift to left)
true, // Autopush enabled
8 // Autopush threshold = 8
);

// We only receive, so disable the TX FIFO to make the RX FIFO deeper.


sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);

// Load our configuration, and start the program from the beginning
pio_sm_init(pio, sm, offset, &c);
pio_sm_set_enabled(pio, sm, true);
}
%}
CMakeLists.txt
cmake_minimum_required(VERSION 3.22)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
include($ENV{PICO_SDK_PATH}/tools/CMakeLists.txt)
# set the project name
project(untriggered-input C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
pico_sdk_init()
add_executable(${PROJECT_NAME}
main.c
)
# Create C header file with the name <pio program>.pio.h
pico_generate_pio_header(${PROJECT_NAME}
${CMAKE_CURRENT_LIST_DIR}/untriggered_input.pio
)
# create map/bin/hex file etc.
pico_add_extra_outputs(${PROJECT_NAME})
# pull in common dependencies
target_link_libraries(${PROJECT_NAME}
pico_stdlib
hardware_pio
hardware_dma
)
# Enable usb output, disable uart output
pico_enable_stdio_usb(${PROJECT_NAME} 1)
pico_enable_stdio_uart(${PROJECT_NAME} 0)
ALyP_mainwindow.py
from PyQt5.QtWidgets import QVBoxLayout,QListWidget, QDialog, QMessageBox,
QMainWindow, QApplication, QComboBox, QAction, QGraphicsScene,
QGraphicsView, QPushButton, QLabel, QMenuBar, QMenu
from PyQt5 import uic, QtCore
from PyQt5.QtSerialPort import QSerialPort, QSerialPortInfo
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as
FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as
NavigationToolbar

14
Informe N°4 – Medidas Electrónicas II
import matplotlib
from matplotlib.figure import Figure
import numpy as np
import sys

matplotlib.use('Qt5Agg')
app = QApplication(sys.argv)
eleccionDePuerto = ''

class portSelectionWindow(QDialog):
def __init__(self, listaDisponibles):
super().__init__()
# Load GUI
uic.loadUi("PortSelectionWindow.ui", self)
self.pushButtonCancelar = self.findChild(QPushButton,
"pushButtonCancelar")
self.pushButtonConfirmar = self.findChild(QPushButton,
"pushButtonConfirmar")
self.labelPuertosDisponibles = self.findChild(QLabel,
"labelPuertosDisponibles")
self.listWidgetPuertos = self.findChild(QListWidget,
"listWidgetPuertos")
# Show ports and Define signals of interest
self.listWidgetPuertos.addItems(listaDisponibles)
self.pushButtonConfirmar.clicked.connect(self.confirmarPSWindow)
self.pushButtonCancelar.clicked.connect(self.salirPSWindow)
self.show()
self.exec_()
def confirmarPSWindow(self):
global eleccionDePuerto
eleccionDePuerto = self.listWidgetPuertos.currentItem().text()
if eleccionDePuerto == None:
msgBox = QMessageBox()
msgBox.setIcon(QMessageBox.Information)
msgBox.setText("Debe elegir una opción...")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()
else:
self.close()
def salirPSWindow(self):
self.close()

class UI(QMainWindow):
# Various attributes
listaOrdenFrecuencias = [100000000, 50000000, 20000000, 10000000,
5000000, 2000000, 1000000, 500000, 200000, 100000, 50000, 20000, 10000,
5000]
listaOrdenCantMuestras = [1572864, 1048576, 524288, 262144, 131072,
65536, 32768, 16384, 8192]
listaCMDFrecuencias =
['100M','050M','020M','010M','005M','002M','001M','500K','200K','100K','05
0K','020K','010K','005K']
listaCMDCantMuestras =
['192','128','064','032','016','008','004','002','001']

15
Informe N°4 – Medidas Electrónicas II
puertoSerie = QSerialPort()
bufferString = ""
bufferList = []
flagConectado = False
escenaGrafico = QGraphicsScene()
figuraGrafico = FigureCanvas(Figure(figsize=(12, 8), dpi=80))

# Constructor, inherits all properties from itself


def __init__(self):
super(UI, self).__init__()
# Load GUI
uic.loadUi("ALyP_mainwindow.ui", self)
# Define parts of the GUI as atributes of the class, skipping
spacers
self.verLayGrafico = self.findChild(QVBoxLayout, "verLayGrafico")
self.graphicsViewALyP = self.findChild(QGraphicsView,
"graphicsViewALyP")
self.botonMuestrear = self.findChild(QPushButton,
"botonMuestrear")
self.comboBoxCantidadMuestras = self.findChild(QComboBox,
"comboBoxCantidadMuestras")
self.comboBoxFrecuenciaMuestreo = self.findChild(QComboBox,
"comboBoxFrecuenciaMuestreo")
self.labelCantidadMuestras = self.findChild(QLabel,
"labelCantidadMuestras")
self.labelETAMuestreo = self.findChild(QLabel, "labelETAMuestreo")
self.labelFrecuenciaMuestreo = self.findChild(QLabel,
"labelFrecuenciaMuestreo")
self.labelTituloETAMuestreo = self.findChild(QLabel,
"labelTituloETAMuestreo")
self.menubarPrincipal = self.findChild(QMenuBar,
"menubarPrincipal")
self.menuArchivo = self.findChild(QMenu, "menuArchivo")
self.actionCargar = self.findChild(QAction, "actionCargar")
self.actionGuardar = self.findChild(QAction, "actionGuardar")
self.menuConfiguracion = self.findChild(QMenu,
"menuConfiguracion")
self.actionGeneral = self.findChild(QAction, "actionGeneral")
self.actionResetDefault = self.findChild(QAction,
"actionResetDefault")
self.menuPuerto = self.findChild(QMenu, "menuPuerto")
self.actionConectar = self.findChild(QAction, "actionConectar")
self.actionDesconectar = self.findChild(QAction,
"actionDesconectar")
# Define signals of interest
self.botonMuestrear.clicked.connect(self.muestrear)
self.actionConectar.triggered.connect(self.conectarPuertoSerie)
self.actionDesconectar.triggered.connect(self.desconectarPuertoSer
ie)
self.actionCargar.triggered.connect(self.cargarDesdeArchivo)
self.actionGuardar.triggered.connect(self.guardarEnArchivo)
self.actionGeneral.triggered.connect(self.configuracionGeneral)
self.actionResetDefault.triggered.connect(self.configuracionResetD
efault)

16
Informe N°4 – Medidas Electrónicas II
self.comboBoxFrecuenciaMuestreo.currentIndexChanged.connect(self.c
alcularETAMuestreo)
self.comboBoxCantidadMuestras.currentIndexChanged.connect(self.cal
cularETAMuestreo)
self.puertoSerie.readyRead.connect(self.readPortHandler)

self.verLayGrafico.addWidget(NavigationToolbar(self.figuraGrafico,
self))
self.graphicsViewALyP.setScene(self.escenaGrafico)
# show the GUI
self.show()
# para mostrar algo en el label
self.calcularETAMuestreo()
# Define functions to handle signals
def muestrear(self):
if not self.flagConectado:
msgBox = QMessageBox()
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText("¡El periférico no está conectado!")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()
return
else:
self.bufferString = ""
stringCMD =
"#US"+self.listaCMDFrecuencias[self.comboBoxFrecuenciaMuestreo.currentInde
x()]+self.listaCMDCantMuestras[self.comboBoxCantidadMuestras.currentIndex(
)]+";"
self.puertoSerie.write(stringCMD.encode("ascii"))
return
def conectarPuertoSerie(self):
puertosDisponibles = [x.portName() for x in
QSerialPortInfo().availablePorts()]
if len(puertosDisponibles) == 0:
msgBox = QMessageBox()
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText("¡No hay puertos disponibles!")
msgBox.setStandardButtons(QMessageBox.Ok)
msgBox.exec()
else:
portSelectionWindow(puertosDisponibles)
self.puertoSerie.setBaudRate(9600)
self.puertoSerie.setPortName(eleccionDePuerto)
self.puertoSerie.setDataBits(8)
self.puertoSerie.setParity(0)
self.puertoSerie.setStopBits(1)
self.puertoSerie.setFlowControl(0)
checkOpen = self.puertoSerie.open(QtCore.QIODevice.ReadWrite)
if checkOpen:
self.flagConectado = True
msgBox = QMessageBox()
msgBox.setIcon(QMessageBox.Information)
msgBox.setText(self.puertoSerie.portName() + "
conectado.")

17
Informe N°4 – Medidas Electrónicas II
msgBox.setStandardButtons(QMessageBox.Ok |
QMessageBox.Cancel)
msgBox.exec()
else:
self.flagConectado = False
msgBox = QMessageBox()
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText(self.puertoSerie.portName() + " no se pudo
conectar.")
msgBox.setStandardButtons(QMessageBox.Ok |
QMessageBox.Cancel)
msgBox.exec()
pass
return
def desconectarPuertoSerie(self):
if self.flagConectado == False:
msgBox = QMessageBox()
msgBox.setIcon(QMessageBox.Information)
msgBox.setText("No hay puerto conectado que desconectar")
msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
msgBox.exec()
else:
self.flagConectado = False
self.puertoSerie.close()
return
def guardarEnArchivo(self):
return
def cargarDesdeArchivo(self):
return
def configuracionGeneral(self):
return
def configuracionResetDefault(self):
self.graficar()
return
def calcularETAMuestreo(self):
ETA =
self.listaOrdenCantMuestras[self.comboBoxCantidadMuestras.currentIndex()]/
self.listaOrdenFrecuencias[self.comboBoxFrecuenciaMuestreo.currentIndex()]
if ETA > 60:
self.labelETAMuestreo.setText(f'{round((ETA/60),2)}'+"[min]")
elif (ETA < 60) and (ETA > 1):
self.labelETAMuestreo.setText(f'{round(ETA,2)}'+"[seg]")
elif (ETA < 1) and (ETA > 0.001):
self.labelETAMuestreo.setText(f'{round((ETA*1000),2)}'+"[mseg]
")
else:
self.labelETAMuestreo.setText("menos de 1 [ms]")
return
def readPortHandler(self):
datos = self.puertoSerie.readAll()
if len(datos) > 0:
self.bufferString += str(datos, 'ascii')
if self.bufferString[-6:] == '#EOF\r\n':
self.bufferList = self.bufferString.split('\r\n')

18
Informe N°4 – Medidas Electrónicas II
for index, item in enumerate(self.bufferList, start=0):
if (not item.isnumeric()):
self.bufferList.pop(index)
else:
self.bufferList[index] = int(item)
self.bufferList[0] = int(self.bufferList[0]) # this is what i
call atar con alambre
self.bufferList.pop(-1) # this is what i call atar con alambre

self.graficar()
return
def graficar(self):
binaryBufferList = [bin(item).replace("0b","") for item in
self.bufferList]
for index, item in enumerate(binaryBufferList):
while len(item) < 8:
item = '0' + item
binaryBufferList[index] = item

axes = self.figuraGrafico.figure.subplots()
x = np.linspace(1,len(self.bufferList),len(self.bufferList))
for pasada in range(8):
listaAuxiliar = [0 for i in binaryBufferList]
for index, item in enumerate(binaryBufferList):
listaAuxiliar[index] = int(item[pasada])
axes.step(x, [j+(2*pasada) for j in listaAuxiliar])

axes.set(xlim = (0,100))

#axes.legend()
axes.grid(True)
self.figuraGrafico.figure.tight_layout()
self.escenaGrafico.addWidget(self.figuraGrafico)

self.graphicsViewALyP.show()
return
UIWindow = UI()
app.exec_()

19

También podría gustarte