¿Cómo funcionan las comunicaciones en serie en el Arduino?


16

Con referencia a Arduino Uno, Mega2560, Leonardo y tableros similares:

  • ¿Cómo funcionan las comunicaciones en serie?
  • ¿Qué tan rápido es serial?
  • ¿Cómo me conecto entre un remitente y un receptor?

Tenga en cuenta: esto pretende ser una pregunta de referencia.


Puede que le resulte interesante acerca de los buffers a ambos lados de un Nano conectado a un sistema Raspian que ejecuta un registrador de datos Python, utilizando solo un cable de programación USB normal entre los dos: arduino.stackexchange.com/questions/11710/…
SDsolar

Respuestas:


16

Las comunicaciones en serie asíncronas (generalmente denominadas en serie) se utilizan para enviar bytes de un dispositivo a otro. Un dispositivo podría ser uno o más de los siguientes:

  • Arduino
  • ordenador personal
  • GPS
  • Lector de tarjetas RFID
  • pantalla LCD
  • Módem
  • Otro

Frecuencia de reloj y muestreo de datos.

A diferencia de las comunicaciones serie SPI / USB / I2C no tiene señal de reloj. El reloj de muestreo es una frecuencia de muestreo acordada (conocida como velocidad de transmisión). Tanto el emisor como el receptor deben configurarse para usar la misma velocidad o el receptor recibirá datos sin sentido (debido a que los bits no se muestrean a la misma velocidad que se enviaron).

La transmisión es asíncrona, lo que básicamente significa que los bytes se pueden enviar en cualquier momento, con diferencias entre ellos. Este gráfico ilustra un solo byte que se envía:

Comunicaciones en serie: envío de un byte

El gráfico anterior muestra la letra 'F' que se transmite. En ASCII esto es 0x46 (en hexadecimal) o 0b01000110 (en binario). El mínimo (bajo pedido) bit más significativo se transmite primero, por tanto, en el gráfico anterior, puede ver los bits que llegan en el orden: 01100010.

El tiempo "inactivo" entre bytes se transmite como bits continuos "1" (efectivamente, la línea de transmisión se mantiene alta continuamente).

Para indicar el inicio de un byte, el bit de inicio siempre se indica tirando la línea hacia abajo como se muestra en el gráfico. Una vez que el receptor ve el bit de inicio, espera 1,5 veces el tiempo de muestreo y luego muestrea los bits de datos. Espera 1,5 veces para que:

  • Omite el bit de inicio
  • Muestras a mitad del siguiente bit

Si la velocidad de transmisión es de 9600 baudios, por ejemplo, entonces la velocidad de muestreo será de 1/9600 = 0.00010416segundos (104.16 µs).

Por lo tanto, a 9600 baudios, después de recibir un bit de inicio, el receptor espera 156.25 µs, y luego toma muestras cada 104.16 µs.

Inicio de sincronización de bits

El propósito del Stop Bit es asegurar que definitivamente haya un bit entre cada byte. Sin el bit de parada, si un byte terminara en cero, sería imposible que el hardware dijera la diferencia entre eso y el bit de inicio del siguiente byte.

Para producir el resultado anterior en un Uno, puede escribir este código:

void setup()
  {
      Serial.begin(9600);
      Serial.print("F");
  }

void loop ()
  {
  }

Numero de bits de datos

Para ahorrar tiempo de transmisión (en los viejos tiempos, heh) se le permitió especificar diferentes números de bits de datos. El hardware de AtMega admite numeración de bits de datos de 5 a 9. Claramente, cuantos menos bits de datos, menos información puede enviar, pero más rápido será.


Bits de paridad

Opcionalmente, puede tener un bit de paridad. Esto se calcula, si es necesario, contando el número de 1 en el carácter y luego asegurándose de que este número sea impar o incluso estableciendo el bit de paridad en 0 o 1 según sea necesario.

Por ejemplo, para la letra "F" (o 0x46 o 0b01000110) puede ver que hay 3 unos (en 01000110). Por lo tanto, ya tenemos una paridad impar. Entonces, el bit de paridad sería el siguiente:

  • Sin paridad: omitido
  • Paridad par: un 1 (3 + 1 es par)
  • Paridad impar: a 0 (3 + 0 es impar)

El bit de paridad, si está presente, aparece después del último bit de datos pero antes del bit de detención.

Si el receptor no obtiene el bit de paridad correcto, eso se denomina "error de paridad". Indica que hay algún problema. Posiblemente, el emisor y el receptor están configurados para usar diferentes velocidades en baudios (bit), o hubo ruido en la línea que convirtió un cero en uno o viceversa.

Algunos sistemas anteriores también usaban paridad de "marca" (donde el bit de paridad siempre era 1 independientemente de los datos) o paridad de "espacio" (donde el bit de paridad siempre era 0 independientemente de los datos).


Transmisión de 9 bits

Algunos equipos de comunicación utilizan datos de 9 bits, por lo que en estos casos el bit de paridad se convierte en el noveno bit. Existen técnicas especiales para enviar este noveno bit (los registros son registros de 8 bits, por lo que el noveno bit debe colocarse en otro lugar).


Número de bits de parada

Los primeros equipos tendían a ser algo más lentos electrónicamente, por lo que para darle tiempo al receptor para procesar el byte entrante, a veces se especificaba que el emisor enviaría dos bits de parada. Básicamente, esto agrega más tiempo donde la línea de datos se mantiene alta (un bit más) antes de que pueda aparecer el siguiente bit de inicio. Este tiempo de bit adicional le da al receptor tiempo para procesar el último byte entrante.

Si el receptor no obtiene un 1 lógico cuando se supone que es el bit de parada, eso se denomina "error de trama". Indica que hay algún problema. Es muy probable que el emisor y el receptor estén configurados para usar diferentes velocidades de transmisión (bit).


Notación

Comúnmente, la comunicación en serie se indica diciéndole la velocidad, el número de bits de datos, el tipo de paridad y el número de bits de parada, como este:

9600/8-N-1

Esto nos está diciendo:

  • 9600 bits por segundo
  • 8 bits de datos
  • Sin paridad (puede ver en su lugar: E = par, O = impar)
  • 1 bit de parada

Es importante que el remitente y el receptor estén de acuerdo con lo anterior, de lo contrario es poco probable que la comunicación sea exitosa.


Pin-outs

El Arduino Uno tiene pines digitales 0 y 1 disponibles para hardware en serie:

Pines serie Arduino Uno

Para conectar dos Arduinos, intercambia Tx y Rx de esta manera:

Conectando dos Arduinos juntos


Velocidad

Se admite una amplia gama de velocidades (ver gráfico a continuación). Las velocidades "estándar" suelen ser un múltiplo de 300 baudios (p. Ej. 300/600/1200/2400, etc.).

Se pueden manejar otras velocidades "no estándar" configurando los registros apropiados. La clase HardwareSerial hace esto por usted. p.ej.

Serial.begin (115200);  // set speed to 115200 baud

Como regla general, suponiendo que está utilizando datos de 8 bits, puede estimar el número de bytes que puede transmitir por segundo dividiendo la velocidad en baudios por 10 (debido al bit de inicio y el bit de parada).

Por lo tanto, a 9600 baudios puede transmitir 960 bytes ( 9600 / 10 = 960) por segundo.


Errores de velocidad de transmisión

La velocidad de transmisión en el Atmega se genera dividiendo el reloj del sistema y luego contando hasta un número preestablecido. Esta tabla de la hoja de datos muestra los valores de registro y los porcentajes de error para un reloj de 16 MHz (como el del Arduino Uno).

Errores de velocidad de transmisión

El bit U2Xn afecta al divisor de velocidad de reloj (0 = dividir por 16, 1 = dividir por 8). El registro UBRRn contiene el número que el procesador cuenta.

Entonces, de la tabla anterior, vemos que obtenemos 9600 baudios de un reloj de 16 MHz de la siguiente manera:

16000000 / 16 / 104 = 9615

Dividimos por 104 y no 103 porque el contador es relativo a cero. Por lo tanto, el error aquí es el 15 / 9600 = 0.0016que está cerca de lo que dice la tabla anterior (0.02%).

Notará que algunas tasas de baudios tienen una cantidad de error más alta que otras.

De acuerdo con la hoja de datos, el porcentaje de error máximo para 8 bits de datos está en el rango de 1.5% a 2.0% (consulte la hoja de datos para obtener más detalles).


Arduino Leonardo

El Arduino Leonardo y Micro tienen un enfoque diferente para las comunicaciones en serie, ya que se conectan directamente a través de USB a la computadora host, no a través del puerto en serie.

Debido a esto, debe esperar a que Serial esté "listo" (ya que el software establece una conexión USB), con un par adicional de líneas, como esta:

void setup()
  {
      Serial.begin(115200);
      while (!Serial)
      {}  // wait for Serial comms to become ready
      Serial.print("Fab");
  }

void loop ()
  {
  }

Sin embargo, si realmente desea comunicarse a través de los pines D0 y D1 (en lugar de hacerlo mediante el cable USB), debe usar Serial1 en lugar de Serial. Lo haces así:

void setup()
  {
      Serial1.begin(115200);
      Serial1.print("Fab");
  }

void loop ()
  {
  }

Niveles de voltaje

Tenga en cuenta que Arduino utiliza niveles TTL para las comunicaciones en serie. Esto significa que espera:

  • Un bit "cero" es 0V
  • Un bit "uno" es + 5V

Los equipos en serie más antiguos diseñados para conectarse al puerto en serie de una PC probablemente usen niveles de voltaje RS232, a saber:

  • Un bit "cero" es de +3 a +15 voltios
  • Un bit "uno" es −3 a −15 voltios

Esto no solo está "invertido" con respecto a los niveles de TTL (un "uno" es más negativo que un "cero"), sino que el Arduino no puede manejar voltajes negativos en sus pines de entrada (ni positivos de más de 5V).

Por lo tanto, necesita un circuito de interfaz para comunicarse con dichos dispositivos. Solo para la entrada (al Arduino), un simple transistor, diodo y un par de resistencias lo harán:

Invertir buffer

Para la comunicación bidireccional, debe poder generar voltajes negativos, por lo que se requiere un circuito más complejo. Por ejemplo, el chip MAX232 hará eso, junto con cuatro condensadores de 1 µF para actuar como circuitos de bomba de carga.


Serie de software

Hay una biblioteca llamada SoftwareSerial que le permite hacer comunicaciones en serie (hasta cierto punto) en software en lugar de hardware. Esto tiene la ventaja de que puede usar diferentes configuraciones de pin para las comunicaciones en serie. La desventaja es que hacer software en serie es más intensivo en el procesador y más propenso a errores. Ver Serie de software para más detalles.


Mega2560

El Arduino "Mega" tiene 3 puertos seriales de hardware adicionales. Están marcados en el tablero como Tx1 / Rx1, Tx2 / Rx2, Tx3 / Rx3. Deben usarse con preferencia a SoftwareSerial si es posible. Para abrir esos otros puertos, use los nombres Serial1, Serial2, Serial3, de esta manera:

Serial1.begin (115200);  // start hardware serial port Tx1/Rx1
Serial2.begin (115200);  // start hardware serial port Tx2/Rx2
Serial3.begin (115200);  // start hardware serial port Tx3/Rx3

Interrupciones

Tanto el envío como la recepción, usando la biblioteca HardwareSerial, usan interrupciones.

Enviando

Cuando hace una Serial.print, los datos que está intentando imprimir se colocan en un búfer interno de "transmisión". Si tiene 1024 bytes o más de RAM (como en el Uno) obtendrá un búfer de 64 bytes, de lo contrario obtendrá un búfer de 16 bytes. Si el búfer tiene espacio, el Serial.printretorno vuelve de inmediato, sin demorar su código. Si no hay espacio, entonces "bloquea" esperando que el búfer se vacíe lo suficiente como para que haya espacio.

Luego, a medida que el hardware transmite cada byte, se llama una interrupción (la interrupción "USART, registro de datos vacío") y la rutina de interrupción envía el siguiente byte desde el búfer fuera del puerto serie.

Recepción

A medida que se reciben los datos entrantes, se llama una rutina de interrupción (la interrupción "USART Rx Complete") y el byte entrante se coloca en un búfer de "recepción" (el mismo tamaño que el búfer de transmisión mencionado anteriormente).

Cuando llame Serial.available, descubra cuántos bytes están disponibles en ese búfer de "recepción". Cuando llama, Serial.readun byte se elimina del búfer de recepción y se devuelve a su código.

En Arduinos con 1000 bytes o más de RAM, no hay prisa por eliminar datos del búfer de recepción, siempre que no permita que se llene. Si se llena, se descartan los datos entrantes adicionales.

Tenga en cuenta que, debido al tamaño de este búfer, no tiene sentido esperar a que llegue una gran cantidad de bytes, por ejemplo:

while (Serial.available () < 200)
  { }  // wait for 200 bytes to arrive

Esto nunca funcionará porque el búfer no puede contener tanto.


Consejos

  • Antes de leer, asegúrese siempre de que haya datos disponibles. Por ejemplo, esto está mal:

    if (Serial.available ())
      {
          char a = Serial.read ();
          char b = Serial.read ();  // may not be available
      }

    La Serial.availableprueba solo garantiza que tenga un byte disponible, sin embargo, el código intenta leer dos. Puede funcionar, si hay dos bytes en el búfer, si no, obtendrá -1, que se verá como 'ÿ' si se imprime.

  • Tenga en cuenta cuánto tiempo lleva enviar datos. Como se mencionó anteriormente, a 9600 baudios, solo puede transmitir 960 bytes por segundo, por lo que tratar de enviar 1000 lecturas desde un puerto analógico, a 9600 baudios, no tendrá mucho éxito.


Referencias


En el primer gráfico: con las flechas parece que el bit de detención se transmite primero. Si intercambiasen Rx / Tx y la dirección de las flechas, creo que es menos confuso.
ott--

Estaba destinado a leerse de izquierda a derecha (como es esta oración) y, por lo tanto, las cosas de la izquierda suceden primero. Póngalo así: en un osciloscopio, así es como vería el rastro.
Nick Gammon

De acuerdo con la explicación del osciloscopio, compro eso. :-)
ott--

Sin embargo, he estado pensando que su punto tiene mucho sentido. ¿Qué piensan los demás? ¿Sería más claro si las flechas se invirtieran e intercambiara Rx / Tx?
Nick Gammon

1
@ linhartr22 Lo modifiqué para leer "datos sin sentido", que probablemente esté más cerca.
Nick Gammon
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.