¿Cómo puede un Arduino generar una frecuencia portadora específica (es decir, 56 kHz)?


9

Estoy trabajando en un proyecto de óptica de espacio libre para enviar datos de forma inalámbrica entre dos puntos. Para lograr esto, estoy usando un LED IR conectado a un Arduino Uno que pulsa con una frecuencia portadora de 56 kHz para el transmisor y un segundo Arduino con un módulo detector de IR de 56 kHz para el receptor.

Intenté usar delayMicroseconds () entre los comandos pin high y pin low para crear la frecuencia de la portadora. Este tipo de trabajo funciona, pero la frecuencia no siempre es la misma y cualquier retraso adicional para pulsar la señal (es decir, el tiempo requerido para llamar a la función y disminuirla) puede cambiarla.

Al leer la hoja de datos del ATmega328, parece que hay una manera de establecer un pulso más preciso utilizando los temporizadores del chip. ¿Es eso posible y, de ser así, cómo se crea un pulso de 56 kHz con los temporizadores?


¿Cuál es la precisión que necesita para su frecuencia de 56KHz? ¿Qué rango de frecuencia es aceptable en su proyecto? Pregunto porque usando solo temporizadores Arduino, la precisión tiene limitaciones.
jfpoilpret

55.5khz a 56.5khz sería ideal para mantener un alto nivel de respuesta en el detector.
jlbnjmn

Respuestas:


10

De hecho, es posible generar una señal de 56 kHz con un Arduino temporizador .

Un temporizador en realidad se puede ver como un registro especial, en la MCU, que contiene un valor (comenzando en 0) que se incrementa a una frecuencia que es la frecuencia de reloj de la MCU (16 MHz en Arduino Uno), posibilidad dividida por un factor llamado prescaler . Cuando ese valor alcanza un límite, llamado Comparar coincidencia , que usted especifica, entonces suceden dos cosas:

  • El valor del registro del temporizador se restablece a 0.
  • Se llama a una función de devolución de llamada ISR (rutina de servicio de interrupción) (puede definirla para que apunte a su propio código).

La idea es usar ese ISR para cambiar la salida de un pin lógico cada vez que se llama ( HIGH, luego LOW, entonces HIGH...).

Ahora, para generar una onda cuadrada de 56 kHz, necesitará que su ISR se llame 56000 * 2veces por segundo ( * 2porque necesita cambiar el valor de salida dos veces por período).

Puede elegir el valor de preescalador que desea para un temporizador de la siguiente lista:

  • 1 (la frecuencia del reloj no está dividida, por lo tanto, 16 MHz)
  • 8 (la frecuencia del reloj se divide por 8, por lo tanto, 2 MHz)
  • 64
  • 256
  • 1024

Hay dos tamaños de temporizadores / contadores en Arduino Uno (en realidad se denominan temporizadores / contadores ): 8 bits y 16 bits.

En Arduino Uno (ATmega328P), tiene tres temporizadores en general, pero algunos pueden ser utilizados por la biblioteca principal de Arduino u otras bibliotecas utilizadas en sus bocetos (tendrá que verificarlo usted mismo):

  • timer0 (8 bits)
  • temporizador1 (16 bits)
  • timer2 (8 bits): este tiene más opciones de preescalado (1, 8, 32, 64, 128, 256 y 1024)

Ahora necesita generar una onda de 56 kHz a partir de 16 MHz, por lo tanto, sin preescalar, necesitaría contar para:

16000000 / (56000 * 2) - 1 = 141.857( - 1porque un temporizador cuenta de 0 a este valor y se restablece solo después de alcanzarlo)

De este cálculo, podemos sacar dos observaciones:

  1. 141.857 no es un entero y, por lo tanto, no podrá generar una onda de exactamente 56 kHz.
  2. Sin preescalado, necesita un temporizador de 16 bits ya que 285 no es representable como un entero sin signo de 8 bits.

A partir de ahora tienes dos opciones:

  1. Use un temporizador de 16 bits ( timer1 ), use prescaler = 1 y seleccione 142como Comparar coincidencia; eso te dará la siguiente frecuencia:16000000 / (2 * (142 + 1)) = 55944 Hz
  2. Use un temporizador de 8 bits ( timer0 ), use preescaler = 8 y seleccione 17como Comparar coincidencia; eso dará menos precisión con la siguiente frecuencia: 16000000 / (8 * 2 * (17 + 1)) = 55555 Hzque todavía está dentro del rango requerido.

Ahora, con respecto a cómo escribir su boceto para eso, le aconsejo que consulte este instructable que es muy completo y muy interesante de leer.

Por supuesto, la hoja de datos completa ATmega328P también es importante si desea comprender, en el más mínimo detalle, lo que está haciendo.

Algunas notas importantes:

  • Un ISR se ejecuta con interrupciones deshabilitadas y, por lo tanto, debe ser lo más corto posible. En particular, hay varias funciones de la biblioteca Arduino que no se invocarán desde un ISR.
  • El reloj Arduino Uno no es muy preciso (utiliza un resonador de cerámica en lugar de un cuarzo, que habría sido mucho más preciso), por lo que esto significa que la frecuencia de salida se desplazará aún más.

2
Además, cuando se alcanza el límite especificado, el hardware puede alternar un pin. Por lo tanto, no hay necesidad de usar ISR en absoluto. Siempre habrá jitter con un ISR porque una instrucción no se puede interrumpir una vez que comienza. Sin embargo, el hardware siempre alternará el pin a la velocidad deseada.
Nick Gammon

Es algo sorprendente que el Arduino Uno use un resonador de cerámica, pero una de sus fuentes son las preguntas frecuentes de Arduino UNO (cerca de "¿El Uno usa un resonador o un cristal para el reloj del procesador?" ).
Peter Mortensen

3

He encontrado tone()útil para generar pulsos de alta frecuencia en cualquier pin. Debería ser capaz de manejar 56 KHz. (Editar: como lo señaló jfpoilpret, lo más cercano que podría estar realmente en un Arduino de 16 MHz es aproximadamente 55.944 KHz)

La dificultad obviamente será combinarlo con su señal de datos. No creo que se pueda hacer eso en software sin recurrir a un código de bajo nivel. Sin embargo, debería ser bastante fácil en hardware, ya que es digital.

Todo lo que necesita hacer es emitir su señal de datos en un pin diferente y luego combinarlo con el operador utilizando una puerta AND. La señal combinada puede ir directamente a su transmisor IR.

Si no tiene una compuerta AND a mano, entonces es bastante simple hacerla con un par de transistores. Simplemente busque en línea "transistor y puerta".


Los receptores a menudo tienen salidas bajas activas en general. Si conecta la parte superior del LED a los 56khz, y la parte inferior a su pin de datos, cuando el pin de datos baja, obtiene una salida IR, lo que debería hacer que el receptor baje. No y puerta necesaria, solo un led y resistencia. El único problema es que se limita a cualquier pin io actual que pueda manejar.
EternityForest

2

La respuesta aceptada de jfpoilpret está muy bien escrita, perfectamente válida y en el 99% de los casos haré exactamente lo que él explica. Sus soluciones están bien dentro de sus parámetros definidos, por lo que deberían funcionar muy bien. Pero, ¿qué es mejor que " muy bien "? ¡Perfección! Después de todo, la pregunta es sobre generar un valor exacto. Como se dijo lo suficientemente cerca, es bueno en la mayoría de los casos (posiblemente todos), e incluso cuando se trata de algo como un reloj cuando 1 segundo necesita ser 1 segundo, aún tiene que sufrir imperfecciones de las partes heredadas.

Lo que sugeriré no siempre es posible. En algunos casos, es posible, pero con mucha más molestia y esfuerzo que este caso. ¿Vale la pena depender de cada caso? Mi objetivo es principalmente mostrar una alternativa para futuras referencias que sea mejor en casos algo marginales. Esto está escrito teniendo en cuenta a los usuarios novatos de Arduino que no tienen una amplia experiencia en electrónica.

Para las personas más avanzadas, esto probablemente se verá demasiado detallado y tonto. Pero creo que, esas mismas personas probablemente ya lo saben y no necesitan esta respuesta. Esto también es aplicable a cada microcontrolador y a cada fabricante y arquitectura. Pero para otros microcontroladores, deberá consultar la hoja de datos correcta para encontrar los registros adecuados y los nombres y valores de preescala.

En su caso, necesita una frecuencia específica y lo bueno de esto es que exactamente 56 kHz en realidad se puede lograr muy fácilmente (sin contar las imperfecciones prácticas de las partes). Así que este también es un ejemplo perfecto.

La generación de una señal depende de los temporizadores y la fuente de reloj del microcontrolador, como explica bien jfpoilpret. Su respuesta aborda el problema de un solo punto de vista y eso es jugar con temporizadores. Pero también puede jugar con la fuente del reloj, o incluso mejor con ambas para obtener sinergia y resultados increíbles. Al cambiar los parámetros del entorno, en este caso pirateando el sistema y reemplazando la fuente del reloj, podemos tratar un problema específico con mucha, mucha más facilidad y simplicidad.

Primero para recordar, debido a la alternancia del estado del pin, debe ejecutar el ISR dos veces más que la frecuencia de la señal. Esto es 112,000 veces por segundo. 56,000 y 16,000,000 no suman muy bien como ya se señaló. Necesitamos cambiar la frecuencia de la señal o la frecuencia del tacto. Tratemos por ahora con una frecuencia de señal inmutable y encontremos una mejor velocidad de reloj.

Sería más sencillo elegir un reloj con un orden de magnitud mayor que 56 kHz (o 112 kHz, pero es prácticamente lo mismo), ya que solo agrega ceros y este tipo de matemática es más simple para la mayoría de las personas. Desafortunadamente, todo en este mundo es algún tipo de compromiso con algo. No todos los valores funcionarán.

El primer ejemplo es con una velocidad de generador de tacto demasiado baja.

Si elige un reloj de 56,000 Hz, no podrá hacer nada, ya que deberá llamar al ISR en cada ciclo y no podrá hacer nada más. Es completamente inútil. Si elige una velocidad 10 veces más rápida (560 kHz), tendrá 9 (10 ciclos para que el temporizador alcance su valor máximo - un ciclo para llamar a la función ISR) ciclos de microcontrolador para hacer su trabajo y esto es muy posible que no sea suficiente. Simplemente a menudo necesita más potencia de cálculo.

Si elige un valor demasiado grande por otro lado, como 56 MHz, el microcontrolador simplemente no puede funcionar con él. Es demasiado rápido Por lo tanto, simplemente elegir el mayor valor en la tienda tampoco será suficiente.

El Arduino Uno R3 original tiene un reloj de stock a 16 MHz, por lo que cualquier cosa más lenta garantiza que funcione. El siguiente valor que es un orden de magnitud mayor que 56 y menor que 16 MHz es 5.6 MHz. Esto permitirá llamar al ISR cada 50 ciclos y creará la frecuencia de temporizador perfecta de 112,000 Hz. Y su señal será exactamente 56 kHz. Tendrá 49 ciclos de MCU para ejecutar su programa entre llamadas ISR, pero todavía es aproximadamente 1/3 de la velocidad del reloj original. Se puede usar 112 como base y usar un reloj de 11.2 MHz y esto dará aproximadamente 2/3 del resonador de 16 MHz. La función ISR se llamará cada 100 ciclos y seguirá generando una señal perfecta de 56 kHz.

Sin embargo, existen dos problemas principales con estos valores.

  • El primer problema depende en gran medida de sus necesidades: sacrifica aproximadamente 1/3 (con 11.2 MHz) de su potencia computacional máxima para obtener la frecuencia de señal exacta que utiliza un valor de registro fácil de encontrar (OCR iirc ). Puede estar bien con eso o no.

  • El segundo problema es un duro showtopper : es muy fácil encontrar valores, pero a menudo simplemente no existen como una fuente de reloj fabricado. Esta es la página web de resonadores de Farnell que simplemente carece de 5.6 MHz y 11.2 MHz.

Para evitar esto, podemos ver los valores de resonador disponibles y descubrir algo más que pueda usarse para generar exactamente los valores deseados. Si dividimos 56 por 4 obtenemos 14 y afortunadamente hay un resonador de 14 MHz. Esto nos proporciona una velocidad mucho mayor y más potencia y un valor de registro igualmente fácil de encontrar. Para llamar al ISR 112,000 veces por segundo, necesitamos poner el valor del decimal 124 o hexadecimal 0x7C en el registro OCR, por lo que contando 124 ciclos + 1 para llamar al ISR, obtenemos nuestro valor perfecto deseado.

nótese bien

  1. ISR: rutina de servicio de interrupción (este es el código que se ejecuta solo en las interrupciones generadas)
  2. ¡Cuán grande puede ser su programa depende del tamaño de la memoria! No tiene nada que ver con la velocidad del reloj ni con la frecuencia con la que llamas al ISR.
  3. Cuando el microcontrolador comienza con el comando del programa, se incrementa un contador. Si se genera una interrupción, se llama al ISR y este valor se almacena en un registro especial. Cuando se completa el código ISR, el valor del contador del programa se restaura desde este registro especial y el programa continúa desde donde fue interrumpido como si nunca hubiera sucedido.

    Daré un ejemplo extremadamente tonto. Si eres purista, te advierto: puede producirse sangrado de nariz y ojos.

    Imagina que tienes que caminar de un lugar a otro. Las instrucciones de ruta paso a paso son su programa principal y sus comandos. La rapidez con la que camina o corre depende de su "velocidad de reloj", pero no de las instrucciones de la ruta (30 pasos hacia adelante, 1 vuelta 90 grados hacia la izquierda, 10 pasos hacia adelante, 45 pasos hacia la derecha, etc.) Siempre son los mismos. . Ahora imagine que un niño pequeño o un político local corrupto y codicioso se desata los zapatos de vez en cuando. Este es el evento que genera una interrupción. Luego te detienes después de tu último paso, arrodíllate y átate el zapato nuevamente. Este es tu programa ISR.

    Luego continúas desde el lugar donde te has detenido; No comienzas desde el principio. Cuando caminas sin cuidado en el mundo y con todo el tiempo, no te importa, incluso si tienes que amarrar tu zapato en cada paso. Sin embargo, si lo hace con limitaciones de tiempo, como correr en 100 metros en los Juegos Olímpicos (o huir de un depredador hambriento que come carne), detenerse y amarrarse los zapatos puede tener graves consecuencias. Lo mismo ocurre con los microcontroladores. Incluso si ejecuta solo una línea de código, su programa continuará, aunque sea lento. Si no te importa la velocidad, no será un problema. Si tiene que hacer algún tiempo relacionado, como usar otras acciones dependientes del temporizador, la interferencia puede ser muy no deseada y problemática.

  4. ¡Menos es más! Un reloj más rápido no siempre es mejor. Los dispositivos con reloj más lento usan considerablemente menos energía. Este puede ser un punto crucial en un dispositivo que funciona con baterías.

  5. Los ciclos necesarios se derivan de estas fórmulas:
    (velocidad de reloj / (valor de preescalador * frecuencia de llamada ISR necesaria)) - 1


TLDR: Desoldear el oscilador cerámico de 16 MHz y reemplazarlo por otro que permita exactamente 56 kHz por división entera (por ejemplo, 14 MHz y dividir por 250).
Peter Mortensen

0

Puede encender y apagar el operador simplemente alternando el modo de pin del operador entre la salida y la entrada. He usado esto para controlar una bomba de calor a través del puerto infrarrojo (control remoto) de 37KHz.


0

No es necesario usar un ISR para crear el operador. Simplemente configure un temporizador para producir una salida PWM del 50% a la frecuencia portadora requerida. El ISR se encarga entonces de modular el operador, generalmente a intervalos de 0,5 o 1 ms, una tasa mucho más cómoda. En mi experiencia, la mayoría de los receptores IR toleran un error del 5% en la frecuencia de la portadora. Utilicé un Freetronics EtherMega 2560 (que tiene muchos temporizadores) pero estoy seguro de que otras CPU funcionarán igual de bien.


¿Cómo se implementa exactamente la modulación de la portadora? ¿Cambiar el modo para el pin de captura de salida del temporizador entre la entrada (portadora apagada) y la salida (portadora encendida)?
Peter Mortensen
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.