Saltar al contenido principal
LibreTexts Español

14.3: Parte Due — Cambio de Forma de Onda

  • Page ID
    83167
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)

    \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)

    \( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)

    ( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)

    \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)

    \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)

    \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)

    \( \newcommand{\Span}{\mathrm{span}}\)

    \( \newcommand{\id}{\mathrm{id}}\)

    \( \newcommand{\Span}{\mathrm{span}}\)

    \( \newcommand{\kernel}{\mathrm{null}\,}\)

    \( \newcommand{\range}{\mathrm{range}\,}\)

    \( \newcommand{\RealPart}{\mathrm{Re}}\)

    \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)

    \( \newcommand{\Argument}{\mathrm{Arg}}\)

    \( \newcommand{\norm}[1]{\| #1 \|}\)

    \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)

    \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    \( \newcommand{\vectorA}[1]{\vec{#1}}      % arrow\)

    \( \newcommand{\vectorAt}[1]{\vec{\text{#1}}}      % arrow\)

    \( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)

    \( \newcommand{\vectorC}[1]{\textbf{#1}} \)

    \( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)

    \( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)

    \( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)

    \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)

    \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)

    \(\newcommand{\avec}{\mathbf a}\) \(\newcommand{\bvec}{\mathbf b}\) \(\newcommand{\cvec}{\mathbf c}\) \(\newcommand{\dvec}{\mathbf d}\) \(\newcommand{\dtil}{\widetilde{\mathbf d}}\) \(\newcommand{\evec}{\mathbf e}\) \(\newcommand{\fvec}{\mathbf f}\) \(\newcommand{\nvec}{\mathbf n}\) \(\newcommand{\pvec}{\mathbf p}\) \(\newcommand{\qvec}{\mathbf q}\) \(\newcommand{\svec}{\mathbf s}\) \(\newcommand{\tvec}{\mathbf t}\) \(\newcommand{\uvec}{\mathbf u}\) \(\newcommand{\vvec}{\mathbf v}\) \(\newcommand{\wvec}{\mathbf w}\) \(\newcommand{\xvec}{\mathbf x}\) \(\newcommand{\yvec}{\mathbf y}\) \(\newcommand{\zvec}{\mathbf z}\) \(\newcommand{\rvec}{\mathbf r}\) \(\newcommand{\mvec}{\mathbf m}\) \(\newcommand{\zerovec}{\mathbf 0}\) \(\newcommand{\onevec}{\mathbf 1}\) \(\newcommand{\real}{\mathbb R}\) \(\newcommand{\twovec}[2]{\left[\begin{array}{r}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\ctwovec}[2]{\left[\begin{array}{c}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\threevec}[3]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\cthreevec}[3]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\fourvec}[4]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\cfourvec}[4]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\fivevec}[5]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\cfivevec}[5]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\mattwo}[4]{\left[\begin{array}{rr}#1 \amp #2 \\ #3 \amp #4 \\ \end{array}\right]}\) \(\newcommand{\laspan}[1]{\text{Span}\{#1\}}\) \(\newcommand{\bcal}{\cal B}\) \(\newcommand{\ccal}{\cal C}\) \(\newcommand{\scal}{\cal S}\) \(\newcommand{\wcal}{\cal W}\) \(\newcommand{\ecal}{\cal E}\) \(\newcommand{\coords}[2]{\left\{#1\right\}_{#2}}\) \(\newcommand{\gray}[1]{\color{gray}{#1}}\) \(\newcommand{\lgray}[1]{\color{lightgray}{#1}}\) \(\newcommand{\rank}{\operatorname{rank}}\) \(\newcommand{\row}{\text{Row}}\) \(\newcommand{\col}{\text{Col}}\) \(\renewcommand{\row}{\text{Row}}\) \(\newcommand{\nul}{\text{Nul}}\) \(\newcommand{\var}{\text{Var}}\) \(\newcommand{\corr}{\text{corr}}\) \(\newcommand{\len}[1]{\left|#1\right|}\) \(\newcommand{\bbar}{\overline{\bvec}}\) \(\newcommand{\bhat}{\widehat{\bvec}}\) \(\newcommand{\bperp}{\bvec^\perp}\) \(\newcommand{\xhat}{\widehat{\xvec}}\) \(\newcommand{\vhat}{\widehat{\vvec}}\) \(\newcommand{\uhat}{\widehat{\uvec}}\) \(\newcommand{\what}{\widehat{\wvec}}\) \(\newcommand{\Sighat}{\widehat{\Sigma}}\) \(\newcommand{\lt}{<}\) \(\newcommand{\gt}{>}\) \(\newcommand{\amp}{&}\) \(\definecolor{fillinmathshade}{gray}{0.9}\)

    Si bien puede ser divertido cambiar el delay, editar las tablas de ondas a mano y luego escuchar los resultados, lo que sería más útil sería controlar tanto la frecuencia como la forma de onda con algunos controles externos. Esto es más acorde con un generador de funciones de laboratorio estándar.

    ¿Cómo podemos ofrecer al usuario el control sobre la forma de onda? Muchos generadores de funciones de laboratorio utilizan un conjunto de pulsadores interdependientes donde solo se puede presionar un botón a la vez. Esto ofrece una agradable retroalimentación visual y táctil. Una técnica más simple y menos costosa utiliza un solo botón que recorre las opciones, volviendo a la primera opción una vez que se alcanza la última. Esto es particularmente efectivo si el número de opciones es bastante pequeño. Podríamos acoplar esto a una serie de LEDs para indicar el ítem seleccionado. Detrás de escena una sola variable mantendrá el “estado” de la selección y se actualizará como el interruptor como activado. Este switch debe ser debounced en hardware ya que un debounce de software requerirá demasiado tiempo. Podemos verificar el estado de este switch al inicio de cada ciclo. Esto tiene dos ventajas potenciales sobre verificarlo después de escribir cada valor en el puerto de salida. La primera ventaja es menos procesamiento. La segunda ventaja es que si configuramos las mesas correctamente, podemos garantizar que los interruptores de forma de onda siempre ocurrirán en una pendiente positiva cruce de cero voltios evitando así transitorios potencialmente peligrosos.

    Usemos tres formas de onda: sinusoidal, cuadrada y rampa. Vamos a necesitar tres LEDs para indicar la forma así que son tres pines de salida. También necesitaremos un pin de entrada para el interruptor de forma. Aunque nuestra variable de forma de onda solo podría usar los números 1, 2 y 3 para representar estas tres formas de onda, con un poco de previsión podemos ahorrarnos algo de trabajo. ¿Por qué no usar el valor de bit del puerto LED correspondiente para representar la elección de onda? Hacerlo significa que no habrá ninguna traducción necesaria entre la elección de la forma de onda y qué LED se iluminará. Usemos el puerto B.1 (puerto B bit 1) para el interruptor de entrada y B. 2:4 para los LEDs sinusoidales, cuadrados y de rampa, respectivamente. Podríamos usar lo siguiente:

    // all port B
    #define WAVEBIT         0x02
    #define SINEWAVE        0x04
    #define SQUAREWAVE      0x08
    #define RAMPWAVE        0x10
    

    Luego necesitamos modificar la función setup () con lo siguiente:

    // set B.2:4 for output
    DDRB |= (SINEWAVE | SQUAREWAVE | RAMPWAVE);
    
    // set B.1 for input, enable pull-up
    DDRB &= (~WAVEBIT);
    PORTB |= WAVEBIT;
    

    En la función loop () necesitaremos varias variables nuevas:

    unsigned char wavechoice=SINEWAVE;
    unsigned char waveswitch=WAVEBIT, currentwaveswitch=WAVEBIT;
    

    wavechoice es la variable que mantiene la elección actual de la forma de onda del usuario. Se inicializa a seno. Es importante recordar que solo cambiaremos la forma de onda en una transición de pulsador, no en que sea alta o baja per se. Por lo tanto, necesitamos conocer el estado previo del conmutador así como su estado actual. Las dos variables de interruptor de onda se utilizan para mantener estos dos estados, presionados o liberados. En lugar de establecer estos en 1/0 (verdadero/falso), usamos el valor de bit real para representar verdadero. Esto hará que la codificación sea un poco más transparente. Entonces, antes de ingresar al bucle while () necesitamos establecer el puntero de tabla de ondas al valor predeterminado actual:

    // select default sine and light corresponding waveshape LED
    PORTB |= wavechoice;
    p = sinetable;
    

    Debido a que la variable wavechoice usa los valores de bit de puerto para los LEDs, podemos simplemente copiar el valor al puerto de salida para encenderlo (recuerde, por defecto al reiniciar todos los demás bits son cero); agradable y simple.

    Ahora echemos un vistazo al procesamiento del switch. Primero tenemos que determinar el estado actual:

    currentwaveswitch = PINB & WAVEBIT;
    

    Solo procesaremos el interruptor en un estado deprimido (es decir, una transición de alto a bajo). Tenga en cuenta que si está utilizando un circuito de desrebote de hardware que invierte, esta lógica también se invertirá (elimine el “no”).

    if( !currentwaveswitch ) // selected (down)
    {
          if( currentwaveswitch != waveswitch ) // transition
          {
    

    Luego verificamos el estado actual de la variable wavechoice y recorremos los valores disponibles, actualizando también el puntero genérico de tabla de ondas:

                if( wavechoice == SINEWAVE )
                {
                      wavechoice = SQUAREWAVE;
                      p = squaretable;
                }
                else
                {
                      if( wavechoice == SQUAREWAVE )
                      {
                            wavechoice = RAMPWAVE;
                            p = ramptable;
                      }
                      else
                      {
                            wavechoice = SINEWAVE;
                            p = sinetable;
                      }
                }
    

    Desactivamos todos los LEDs y activamos el elemento recién elegido:

                //turn off all LEDs
                PORTB &= (~(SINEWAVE| SQUAREWAVE| RAMPWAVE));
    
                // turn on newly selected LED
                PORTB |= wavechoice;
          }
    }
    

    Por último, actualizamos la variable waveswitch para que nuestra lógica de detección de transición funcione correctamente:

    waveswitch = currentwaveswitch;
    

    Lo único que queda es simplemente colocar una cláusula if () alrededor de este trozo de código para que solo verifiquemos el interruptor al inicio de la tabla de ondas. Esto ocurre cuando la variable de índice u es cero:

    if( !u )
    {
          // wave shape switch code goes here
    }
    

    Crea dos tablas de nueva ola para el cuadrado y la rampa, y agrega el código anterior. También cable en los tres LED y el interruptor de forma de onda. Compilar, transferir y probar la operación usando un osciloscopio. El programa Python presentado anteriormente se puede utilizar para crear las nuevas matrices. La onda cuadrada consta de 128 entradas de 255 seguidas de 128 entradas de 0. La onda de rampa consta de 256 entradas comenzando en 0 e incrementando en 1 cada vez para terminar en el valor 255.


    This page titled 14.3: Parte Due — Cambio de Forma de Onda is shared under a CC BY-NC-SA 4.0 license and was authored, remixed, and/or curated by James M. Fiore via source content that was edited to the style and standards of the LibreTexts platform.