Implementación de un generador de funciones arbitrarias con FPGA

Anuncio
Implementación de un generador de funciones arbitrarias con
FPGA
Matias Risaro y Marcelo Luda
22 de diciembre de 2014
Resumen
En el presente trabajo se detalla la construcción de un generador de funciones arbitrarias
digital de dos canales, utilizando una placa FPGA y electrónica de conversión digital-analógica.
Se desarrolló una interfaz serie para definir la frecuencia de trabajo y cargar los datos de las
funciones arbitrarias. Además el dispositivo construido puede sincronizarse a una función TTL
de referencia a través de un PLL digital diseñado. Se incluye el diseño de la electrónica de
conversión, la descripción en bloques del diseño FPGA y los ASM de los algoritmos principales
implementados.
1.
Introducción
Un generador de funciones es un dispositivo que permite generar señales de tensión que varı́an
de forma periódica en función del tiempo. Es un elemento básico de laboratorios de fı́sica y de
varias ingenierı́as en general. En particular, la generación de funciones arbitrarias permite extender
sus aplicaciones. Además, poder sincronzar una señal generada a una señal de referencia permite
implementar técnicas de medición de alta precisión, como el lock-in, o hacer análisis espectrales de
otras señales.
En el siguiente informe se detalla el desarrollo de un generador de funciones arbitrarias con
resolución en tensión de 8 bits y en tiempo de 6 bits, con una frecuencia máxima de f = 156kHz.
Este dispositivo se implementa utilizando una placa de desarrollo Nexys-3 y un DAC AD7545 de 12
bits. El diseño permite controlar el generador desde un ordenador a través de una interfaz UART,
pudiendo establecer la forma de la función de onda para dos canales diferentes y la frecuencia de
operación. Dicha frecuencia también puede ser definida con una señal externa de referencia de tipo
TTL. Para ello se implementó un módulo Phase Locked Loop (PLL) de detección de frecuencia y
fase.
1.1.
Generador de Funciones
Un generador de funciones es un dispositivo capaz generar señales eléctricas periódicas en
el tiempo. Son utilizados generalmente para probar otros dispositivos electrónicos y para realizar análisis espectrales. Las funciones de onda más utilizadas son las ondas senoidales, las ondas
cuadradas y las triangulares. Estas funciones se pueden construir utilizando elementos totalmente
analógicos a partir de un oscilador electrónico de referencia, elementos que componen los generadores de funciones más básicos del mercado. Los generadores de funciones más sofisticados sintetizan
la función de onda mediante procesamiento de señales digitales (DSP) y luego utilizan un conversor
digital analógico (DAC) para producir una señal analógica. Esto permite ampliar la variedad de
formas de onda y se los conoce como AWG (Arbitrary Waveform Generator )
Un DAC es un dispositivo electrónico capaz de convertir un dato de señal digital en señales de
tensión analógica. Dichos dispositivos son alimentados con una tensión de referencia, Vcc (tı́picamente 5 V), y generan una tensión continua proporcional al dato que se le ingresa. Un DAC de
7 bits alimentado con 5 V, por ejemplo, discretiza en 128 valores las tensiones entre 0 y 5 Volts.
Si se carga a la entrada el número 0100000, que corresponde al número decimal 64, a la salida se
obtiene una tensión continua de 2,5 V. El DAC que se utiliza en el presente trabajo es el AD7545,
1
que tiene una resolución de 12 bits y un tiempo de respuesta de aproximadamente 100 ns. La carga
de los datos se realiza en forma paralela, a través de las 12 entradas que posee. En la figura 1 se
muestra un esquema de las conexiones del AD7545.
RFB
20
AD7545
VREF 19
R
12-BIT
MULTIPLYING DAC
1
OUT 1
2
AGND
12
WR 17
CS 16
18 VDD
INPUT DATA LATCHES
3
DGND
12
DB11–DB0
(PINS 4–15)
Figura 1: Esquema de E/S del DAC AD7545
La resolución del AD7545 es de 12 bits, pero no se utiliza a su máxima resolución. Se conectan
a tierra los 4 bits menos significativos y se tiene entonces un DAC de 8 bits, que nos permite
una resolución en tensiones de aproximadamente 2 mV. Esto es lo que se conoce como resolución
vertical de un generador de funciones.
Otra de las caracterı́sticas de un generador de funciones es la longitud de la forma de onda,
que es la cantidad de puntos que definen la función a repetir periódicamente. En nuestro caso se
opta por una longitud de 6 bits (64 puntos) para definir la función de onda. Cabe destacar que con
esta elección, y considerando el tiempo de respuesta del DAC, se obtiene el mı́nimo perı́odo que
puede tener la función de onda. Dicho perı́odo es T = 100ns ∗ 64 = 6, 4µs, por lo tanto la máxima
frecuencia a la que puede trabajar el generador de funciones es f = 1/T = 156kHz.
1.2.
PLL
La sigla PLL (Phase-Locked Loop) se refiere a técnica de control que permite sincronizar la
frecuencia y la fase de una señal generada por un oscilador controlable, a la de una señal de referencia. Dicha técnica representa un elemento básico para múltiples aplicaciones en procesamiento
de señales, entre los que se halla la demodulación de una señal de radio FM o la medición de señales
débiles por la técnica de Lock-in.
La técnica Lock-in permite hacer una análisis espectral de la respuesta de un sistema ante
una excitación periódica. Para ello se utiliza una señal de referencia con la misma frecuencia y
fase que la señal excitadora, normalmente generada bajo la norma TTL (onda cuadrada de 0 a
5V). La técnica de lock-in consiste en generar funciones de seno y coseno sincornizadas a la señal
de referencia con un PLL, multiplicarlas por la señal de respuesta del sistema y filtrarlas con un
filtro pasa bajos. Con este procedimiento se obtiene una tensión de salida, correspondiente a los
coeficientes de la serie de Fourier de la señal de respuesta del sistema.
Un PLL analógico consiste en un detector de fase con un filtro pasa bajos y un VCO (Voltage
Controlled Oscillator ) vinculados en forma realimentada como muestra la figura 2. La salida del
filtro es una tensión de error, que da cuenta de la diferencia entre la frecuencia de referencia y
la del VCO. En este trabajo se implementó un PLL digital que puede lockearse a señales TTL
haciendo detección de flancos e induciendo la frecuencia de la señal de referencia.
2
Figura 2: Esquema de un PLL analógico
2.
Implementación en FPGA
El dispositivo fue desarrollado sobre una placa FPGA de desarrollo Nexys-3 programada en
Verilog. A continuación se realiza un análisis de la estructura modular de esta implementación.
En la figura 3 se detallan las entradas y salidas del dispositivo y los periféricos asociados. Se
incluye una interfaz de comunicación con el ordenador (pines tx y rx), la señal de entrada signal
para la referencia, los bus de datos JC y JD para comunicación con los DAC, algunas salidas para
el control del display de siete segmentos (an y seg) y algunas entradas para el control de variables
internas (NTau, PC_o_PLL y sw_mem). Se incluye una salida extra jb para debugging que sirve para
usar de trigger externo en el osciloscopio al visualizar las señales de salida de los DAC.
main
rx
tx
JC[8]
JD[8]
jb
Ntau[2]
PC_o_PLL
sw_mem
signal
an[4]
seg[8]
Figura 3: Módulo principal del proyecto
Las principales partes del diagrama de bloques interno del generador de funciones se muestran
en la figura 4. Cada una de las salidas que controla un DAC está asociada a un módulo de memoria
(memoria A y memoria B). Dichos módulos consisten en un banco de registros con un puntero de
lectura que avanza cı́clicamente y de a un paso, cada vez que llega un 1’b1 al pin change_val.
Además cuenta con una interfaz de escritura compuesta por las entradas mem_reset, mem_wr y
mem_wr_dat. El módulo divisor_tau es un divisor de frecuencia programable, implementado con
un contador de ciclos de reloj (10ns) y se reinicia cada vez que llega al valor freq emitiendo un
tick en la salida. Este módulo alimenta las entradas change_val que hacen avanzar el puntero de
lectura de las memorias.
El valor de freq es seleccionado entre cfreq o dfreq, dependiendo del valor del switch PC_o_PLL.
En el primer estado la frecuencia se define con la interfaz UART, mientras que en el otro se calcula
la frecuencia de la señal de referencia con el módulo PLL. Es un valor de 32bit y los 16 bits más
significativos se muestran en valor hexadecimal utilizando el display de siete segmentos.
3
rx
tx
UART
freq[32]
phase[32]
selector_mem
mem_reset
mem_wr
mem_wr_dat[8]
memoria A
mem_reset
mem_wr
mem_wr_dat[8]
sw_mem
change_val
rd_reset
cfreq[32]
selector
freq[32]
divisor_tau
freq[32]
tick
rd_val[8]
memoria B
mem_reset
mem_wr
mem_wr_dat[8]
dfreq[32]
PC_o_PLL
change_val
rd_reset
[31:28]
[27:24]
[23:20]
[19:16]
rd_val[8]
disp_mux
hex2seg
hex2seg
hex2seg
an[4]
seg[8]
hex2seg
Figura 4: Estructura de módulos del generador de funciones
El módulo UART, además de implementar la comunicación con el ordenador incluye la interfaz
de escritura de las memorias. El switch sw_mem determina qué memoria se esta programando en
un instante dado. También posee dos registros internos de 32 bits para guardar la información de
cfreq y phase que se le envı́a desde el ordenador.
2.1.
Banco de memoria para funciones arbitrarias
El módulo de memoria (figura 5) consiste en un banco de 64 registros de 8 bits. La única salida
es rd_val que muestra el valor apuntado por el puntero rd_ptr en cada momento. En cada flanco
del reloj en que el pin change_val está en 1’b1 el puntero rd_ptr se incrementa en +1 y al llegar
a 64 vuelve a comenzar desde cero. De este modo, cada 64 ticks que llegan a change_val ocurre
un periodo completo de la función de onda guardada en la memoria.
memoria
mem_reset
wr_ptr
mem_wr
mem_wr_dat[8]
change_val
rd_reset
rd_ptr
rd_val[8]
Figura 5: Módulo de memoria
Para llenar el contenido de la memoria se utiliza la interfaz de escritura mencionada en la
sección anterior. Cada vez que llega un tick a mem_wr se escribe el valor de mem_wr_dat en el registro
apuntado por wr_ptr y se incrementa wr_ptr en +1. Cuando wr_ptr llega a 64 se deshabilita la
escritura hasta que este vuelva a ser cero. El pin mem_reset sirve para reiniciar el puntero wr_ptr
a cero y habilitar nuevamente la escritura del banco completo.
4
2.2.
Módulo UART modificado
Sobre la base del módulo UART proporcionado en el curso “Diseño de Sistemas con FPGA”
DC-FCEN-UBA1 se programó un módulo de control que interpreta los caracteres enviados desde
un ordenador usando el protocolo RS-232. En la figura 6 se puede apreciar el diseño interno del
módulo modificado.
UART
rx
stick
baud_rate_gen
uart_rx
uart_cpu
fifo_wr
din
fifo_wr_dat[8]
rx_tick
fifo_reset
dout[8]
rx_done
stick
fifo_empy
fifo_full
din[8]
tx_start
tx_done
r_data[8]
empty
rd
msg_dat[8]
msg_tick
stick
tx
fifo_tx
fifo_rd
fifo_rd_dat[8]
w_data[8]
wr
uart_tx
s_exito
s_fallo
fifo_rx
wr
wr_dat[8]
fifo_reset
empty
full
rd
rd_dat[8]
mem_wr
mem_wr_dat[8]
mem_reset
s_exito
s_fallo
freq[32]
phase[32]
err_msg
Figura 6: Módulo UART modificado para implementar el protocolo de control del dispositivo desde
un ordenador
El módulo uart_cpu es una FSM que procesa los caracteres que van llegando por rx e implementa diferentes algoritmos en función de ello. El principal se inicia con la llegada de un caracter
’m’ cuando el FSM está en estado idle. En ese caso, se reinicia el fifo_rx (con un tick en el
pin fifo_reset) y los siguientes caracteres que lleguen se van a escribir directamente en el el fifo
hasta que esté lleno (se active el pin fifo_full). El fifo tiene el mismo tamaño que los módulos de
memoria, por lo que se está cargando un periodo completo de la función de onda a producir. Una
vez lleno, el uart_cpu reinicia el módulo de memoria (con un tick en el pin mem_reset), lee de a
uno los registros del fifo y los escribe en el módulo de memoria utilizando la interfase de escritura
ya descrita. Terminado el proceso de escritura, si no hubo errores, envı́a un tick por s_exito que
permite enviar un caracter de confirmación a través del tx al ordenador.
En caso de que la FSM en estado idle reciba un caracter ’f’ o ’p’ en el bus din, el módulo
uart_cpu tomará los siguientes 4 bytes que lleguen y los guardará en el registro freq o phase
respectivamente. De este modo quedan cargados dos registros de 32 bits que sirven para fijar la
frecuencia de trabajo del generador de funciones (en el caso que la frecuencia se controla desde el
ordenador) y un valor que sirve para establecer una diferencia de fase entre la señal de referencia
y la generada (en el caso donde se controla la frecuencia y la fase desde el PLL).
En la figura 7 se puede ver el diagrama ASM del FSM implementado por uart_cpu. No se
incluye la rama de la escritura del valor de phase porque es equivalente al de freq.
1 http://www.dc.uba.ar/materias/disfpga/2014/c2/descargas/UART.rar/view
5
~('m'|'p'|'f')
idle
fifo_reset ← 0
fifo_wr ← 0
fif_rd ← 0
mem_reset ← 0
mem_wr ← 0
s_exito ← 0
'p'
'f'
din
...
reset_fifo_m
reset_mem_f
'm'
w_en_freq_next ← 0
fifo_reset ← 1
guardar1_f
carga_fifo_m
w_ptr_freq_next ← 2'b00
fifo_reset ← 0
fifo_wr ← rx_tick
w_en_freq_next ← 0
F
rx_tick == 1
F
T
fifo_full == 1
w_en_freq_next ← 1
T
reset_mem_m
guardar2_f
mem_reset ← 1
w_ptr_freq_next ← 2'b01
carga_mem_m
w_en_freq_next ← 0
fifo_rd ← 1
mem_wr ← ~fifo_empty
mem_reset ← 0
rx_tick == 1
F
T
F
w_en_freq_next ← 1
fifo_empty == 1
exito_m
guardar3_f
w_ptr_freq_next ← 2'b10
T
w_en_freq_next ← 0
s_exito ← 1
fifo_rd ← 0
mem_wr ← 0
rx_tick == 1
F
T
w_en_freq_next ← 1
guardar4_f
w_ptr_freq_next ← 2'b11
w_en_freq_next ← 0
rx_tick == 1
F
T
w_en_freq_next ← 1
exito_f
Figura 7: ASM del módulo
6
2.3.
Sincronización en fase y frecuencia
Cuando el switch PC_o_PLL está en 1’b1 el generador de funciones trabaja en una frecuencia
calculada a partir de la señal de referencia y con su fase lockeada a la esta señal. Para ello se
implementaron los tres módulos que se muestran en la figura 8.
flank_detector
signal
fup_tick
fdw_tick
freq_detector
Ntau[2]
freq[32]
ftick
dfreq[32]
desfasador
ftick
func_reset
PC_o_PLL
func_reset
phase[32]
freq[32]
Figura 8: Módulos que implementan el PLL
El módulo flank_detector es una máquina de estados con un flip-flop que detecta cambios en
el valor de signal y envı́a un tick por fup_tick cada vez que hay un flanco de subida y un tick
por fdw_tick cada vez que hay un flanco de bajada. Con una de estas dos salidas se alimentan los
módulos de freq_detector y desfasador.
El módulo freq_detector es un contador de ciclos de reloj que se reinicia cada vez que llega
un tick a ftick. Antes de reiniciarse guarda el último valor, que representa el número de ticks de
reloj que entran en un perı́odo de la señal. Debido a que este número puede variar levemente entre
medición y medición (por ruidos, jitter en la señal de referencia u otras fuentes de imprecisión) se
utilizó un algoritmo de integración tipo “filtro pasa bajos” para actualizar el valor de freq. En
lugar de guardar directamente el valor q_reg relevado en cada medición de flanco se guarda el
valor resultante de la fórmula (1).
q reg N + freq (256 − N )
(1)
256
Con los switchs NTau se puede elegir que el valor N = 128, 64, 32, 16 según se quiera converger
en pocos pasos a la frecuencia de relevada o en muchos pasos con una estabilidad mayor.
freq next =
2.4.
Electrónica asociada
El dispositivo se completa con el desarrollo de la electrónica de conversión digital-analógica de
la señal de salida. Para ello se utilizó el DAC integrado AD7545, que funciona como una resistencia
programable, y un amplificador operacional (LF357) de salida para la adaptación de impedancias.
La elección del DAC radica en la disponibilidad de control por un bus directo de 12 cables, lo que
evita la implementación de algún protocolo de control como el I2C o el SPI. El LF357 fue elegido
en función de su gran ancho de banda, que permite operar el DAC a la máxima velocidad posible
(100 ns). En la figura 9a se puede ver el esquema del circuito de conversión para un canal. En la
figura 9b se incluyó el diseño del circuito impreso utilizando dos canales de salida.
El circuito fue impreso en una placa PCB y se soldaron todos sus componentes para hacer las
pruebas de generación de funciones. Se utilizó una fuente partida de ±6V implementada a partir
de una fuente de switching simple y un circuito a medida armado en una protoboard. Se armaron
los cables a medida para conectar la FPGA. Se puede ver una foto del dispositivo terminado en la
figura 10.
7
8
7
6
5
V+
OUT
C1
X1
X1-1
X1-2
1
V+
22-23-2031
X3-1
X3-2
X3-3
12 DB11
11 DB10
10 DB9
9 DB8
8 DB7
7 DB6
6 DB5
5 DB4
4 DB3
3 DB2
2 DB1
1 DB0
R2
200
1
AD7545_BIS
P19
C2
A
2k
R3
33p
E
X2LF357_BIS
S
V+
GND
SV1
22-23-2021
GND
3
R3
AD7545
1
2
3
4
1
22-23-2031
33p LF357
OUT1
GND
V-
X3
P19
V+
GND
GND
33p
C1
R1
20
19
18
17
16
15
14
13
12
11
22-23-2021
DB11
DB10
DB9
DB8
DB7
DB6
DB5
AD7545
DB4
DB3
DB2
DB1
DB0
1
2
3
4
5
6
7
8
9
10
OUT1
GND
GND
3
R1
200
LF357
22-23-2021
2k
200
12
2k
3
3
R4
SV1
12
SV2
1
V-
(a) Esquema para un canal
(b) Diseño impreso
Figura 9: Circuito de conversión digital-analógico para dos canales
Figura 10: Foto del circuito terminado que implementa los dos DAC
3.
Caracterización y resultados
Para controlar el dispositivo se desarrolló un script en Python donde se definieron las funciones
matemáticas que el generador de funciones produce y las funciones necesarias para la comunicación.
En el apéndice A se puede ver el código, disponible para ejecutar desde una consola IPhython.
En la figura 11 se pueden ver la función senoidal generada por el dispositivo relevada por
medio de un osciloscopio. Para bajas frecuencias la resolución temporal del osciloscopio permite
ver los pasos de discretización. En la figura 12 se pueden apreciar diferentes funciones arbitrarias
generadas con el dispositivo.
8
Generador de funciones, Senoidal
Generador de funciones, Senoidal
1
0
0
−1
−1
Tensió n (V)
Tensió n (V)
1
−2
−3
−2
−3
−4
−4
−5
−5
−6
−10
−8
−6
−4
−2
0
Tiempo (ms)
2
4
6
8
10
−6
−100
−80
−60
−40
−20
(a) Baja frecuencia
0
Tiempo (us)
20
40
60
80
100
(b) Alta frecuencia
Figura 11: Generación de función senoidal a dos frecuencias diferentes.
Generador de funciones, Gauss
Generador de funciones, Rampa
1
0
0
−1
−1
Tensión (V)
Tensión (V)
−2
−2
−3
−3
−4
−4
−5
−5
−6
−10
−8
−6
−4
−2
0
Tiempo (ms)
2
4
6
8
−6
−25
10
−20
−15
−10
−5
0
Tiempo (ms)
5
10
15
20
25
(b) Rampa
(a) Gaussiana
Generador de funciones, Triangular
1
0
Tensión (V)
−1
−2
−3
−4
−5
−6
−25
−20
−15
−10
−5
0
Tiempo (ms)
5
10
15
20
25
(c) Triangular
Figura 12: Generación de funciones arbitrarias
Para caracterizar la precisión en la generación de la funciones se midió la dispersión en frecuencia
midiendo el jitter en el periodo de las funciones generadas. Para funciones senoidales la dispersión
en diferentes frecuencias se puede ver en la tabla 1. Se incluyen otras funciones arbitrarias generadas
en la tabla. Se puede ver que la dispersión hallada es del orden del ∼ 1/1000.
9
Función
Seno lento
Seno medio
Seno rápido
Gaussiana
Triangular
Rampa
Frecuencia
156.1 Hz
15.4 KHz
141.6 KHz
15.4 KHz
156.3 KHz
156.3 KHz
dispersión
0.2 Hz
0.1 KHz
0.1 KHz
0.1 KHz
0.6 KHz
0.2 KHz
Tabla 1: Dispersiones en frecuencia para diferentes frecuencias y funciones generadas
Se pudo corroborar el funcionamiento del PLL sincronizando cada una de las funciones arbitrarias generadas, a una señal cuadrada de referencia. La inferencia de la frecuencia de trabajo
demostró una velocidad de adaptación muy rápida, con tiempos del orden de 20 ciclos de reloj de
la señal de referencia.
A modo de ejemplo, se probó la capacidad de generar funciones completamente arbitrarias
tratando de reproducir una imagen 2D arbitraria a partir de la generación de las funciones correspondientes a x(t) e y(t) en cada uno de los canales de salida. En la figura 13 se puede ver la
pantalla del osciloscopio en modo xy representando una de las imágenes emuladas.
Figura 13: Ejemplo práctico de la implementación de funciones arbitrarias en dos canales simultáneos
4.
Conclusiones
La tecnologı́a FPGA demostró ser perfectamente adecuada para la implementación de un generador de funciones arbitrarias digital. Las frecuencias logradas en este trabajo son suficientemente
altas para su utilización en diversas aplicaciones de un laboratorio de fı́sica. Los lı́mites pueden
superarse utilizando electrónica de alta velocidad y una placa FPGA de mayores prestaciones.
10
A.
Programa de control en Python
# Control de generador de funciones en ipython
# Triangular
fun = abs ( xx -32.)
fun = fun - fun . min ()
fun = fun / fun . max () *255
ftrian = uint8 ( fun )
from numpy import *
from matplotlib . pyplot import *
import matplotlib . cm as cm
import Image
# Gaussiana
fun = exp ( -(( xx -32.) /8) **2)
fun = fun - fun . min ()
fun = fun / fun . max () *255
fgauss = uint8 ( fun )
# Funcion para convertir un integer en un string de 4 bytes
def tau2str ( tau ) :
t = uint32 ( tau )
cc = ’ ’
for i in range (0 ,4) :
cc = chr ( mod (t ,256) ) + cc
t = t /256
return cc
# Rampa
fun = xx
fun = fun - fun . min ()
fun = fun / float ( fun . max () ) *255
framp = uint8 ( fun )
# Funcion para convertir una tira de numeros uint8 en chars
def array2str ( fun ) :
ll = ’ ’
for i in fun . tolist () :
ll = ll + chr ( i )
return ll
# Batman
bat_x = array ([ 32 , 52 , 77 , 69 , 72 , 88 , 106 , 112 , 114 , 122 ,
131 , 140 , 142 , 146 , 165 , 183 , 180 , 176 , 196 , 214 , 230 , 241 ,
250 , 255 , 251 , 244 , 229 , 218 , 205 , 211 , 206 , 193 , 181 , 173 ,
162 , 152 , 141 , 133 , 127 , 120 , 115 , 105 , 96 , 86 , 81 , 70 ,
57 , 47 , 43 , 46 , 48 , 31 , 20 ,
8,
2,
0,
4 , 10 ,
17 , 22 , 27 , 31 , 31 , 31] , dtype = uint8 )
# Abrimos el puerto Serie - - - - - - - - - - - - - bat_y = array ([ 41 , 24 , 10 , 38 , 71 , 90 , 71 , 32 ,
0 , 26 ,
26 ,
0 , 23 ,
71 , 94 , 65 , 27 ,
9 , 23 , 37 , 53 , 71 ,
98 , 130 , 159 , 186 , 213 , 231 , 240 , 206 , 180 , 180 , 193 , 207 ,
183 , 180 , 202 , 227 , 255 ,227 , 207 , 185 , 177 , 194 , 204 , 190 ,
178 , 178 , 198 , 224 , 237 , 223 , 206 , 182 , 157 , 126 , 95 , 77 ,
65 , 53 , 49 , 44 , 44 , 44] , dtype = uint8 )
import serial
ser = serial . Serial ( port = ’/ dev / ttyUSB2 ’ , baudrate =19200)
# Configuramos frecuencia de operacion
freq =20000 # x10 ns entre punto y punto
cic = int (1/( freq *1 e -8) )
ciclos = tau2str ( cic )
ser . write ( ’ 66 ’. decode ( ’ hex ’) )
ser . write ( ciclos )
# Comandos para comunicacion directa
def set_freq ( ser , freq ) :
ser . write ( ’f ’+ tau2str ( freq ) )
# Generamos las funciones
xx = arange (0 ,64)
def set_phase ( ser , phase ) :
ser . write ( ’p ’+ tau2str ( phase ) )
# Seno
fun = sin ( xx * pi /32)
fun = fun - fun . min ()
fun = fun / fun . max () *255
fsin = uint8 ( fun )
def sext_fun ( ser , fun ) :
ser . write ( ’m ’+ array2str ( fun ) )
control generador funciones.py
11
Descargar