Serie de software Arduino - dúplex completo

Necesito dos puertos seriales para este proyecto Arduino Atmega328, pero este procesador tiene solo un UART de hardware. El procesador, el diseño del hardware y el entorno de programación ya están configurados y no puedo cambiar el hardware o el procesador en absoluto, por lo que se requiere una solución de software.

Las bibliotecas Arduino incluidas proporcionan una biblioteca SoftwareSerial que he descubierto que es solo semidúplex: durante la rutina de envío, las interrupciones están deshabilitadas, lo que por supuesto significa que la rutina de recepción impulsada por interrupciones está cerrada.

Antes de implementar mi propia biblioteca de dúplex completo, quería saber si otros han encontrado una solución simple para esto, o si hay bibliotecas que la implementen correctamente.

Respuestas (5)

No he usado Arduino, pero he escrito UART suaves y eficientes en varias plataformas. El mejor enfoque en una plataforma determinada dependerá de los tipos de operaciones de manipulación de bits que pueda realizar de manera más eficiente. Sin embargo, ofrecería algunas sugerencias:

  1. Asigne la máxima prioridad al ISR de sondeo en serie y ejecútelo preferentemente a 3 veces la velocidad de datos deseada. Pruebe todas sus entradas y escriba todas sus salidas al comienzo de esta rutina de interrupción, y luego descubra cuáles deberían ser las salidas para el próximo paso. Esto ayudará a minimizar cualquier sesgo de tiempo que podría ser causado por el tiempo de procesamiento de interrupción variable.
  2. Para el receptor, en lugar de usar una máquina de estado como tal, puede ser útil cambiar efectivamente los datos entrantes a un gran registro de desplazamiento. Si el patrón de bits indica que se recibió un byte, tome los datos y borre los bytes apropiados.
      ... cerca del comienzo de la interrupción (para una sincronización constante)
      shiftreg >>= 1;
      si (EN_PORT)
        shiftreg |= 0x20000000;
      ... otra lógica de interrupción, entonces...
      si ((shiftreg & 0x20000007) == 0x20000001)
      {
        resultado int = 0;
        si (shiftreg & 0000000040) resultado |= 1; // Nota: ¡las constantes son OCTAL!
        si (shiftreg & 0000000400) resultado |= 2;
        si (shiftreg & 0000004000) resultado |= 4;
        si (shiftreg & 0000040000) resultado |= 8;
        si (shiftreg & 0000400000) resultado |= 16;
        si (shiftreg & 0004000000) resultado |= 32;
        si (shiftreg & 0040000000) resultado |= 64;
        si (shiftreg & 0400000000) resultado |= 128;
        // Haz algo apropiado con el resultado, luego...
        shiftreg |= 0x3FFFFFFFF;
      }
      si no (shiftreg = 1)
      {
        ... Haz algo con pausa larga (se detectará exactamente una vez)
      }
    

Tenga en cuenta que, si bien el tiempo en el peor de los casos puede ser significativo, el tiempo en el caso normal será bastante rápido. Además, cuando se detecta un byte entrante, uno podría copiarlo en otra palabra de la memoria y hacer el cambio de bits en una interrupción posterior. Dado que la transmisión en serie solo necesitará hacer algo cada tercera interrupción, la manipulación de bits podría realizarse en las interrupciones donde la rutina de transmisión en serie no se ejecuta.

Dices que no puedes cambiar el hardware existente, ¿puedes agregarlo? Si no es necesario que ambas líneas seriales estén activas al mismo tiempo, puede usar un multiplexor o un interruptor analógico en las líneas UART y alternar entre los dos dispositivos que necesitan servicio. Solo tendrá que asegurarse de que cuando cambie el nivel en su pin TX permanezca alto cuando se aleje del UART (para evitar una condición de INICIO falso).

Ambas líneas seriales deben estar activas simultáneamente. No puedo agregar hardware en este diseño.

Cuando necesité un segundo UART de hardware en un AVR, usé un dispositivo MAX3100. Tiene una interfaz SPI y es muy fácil de usar. Son bastante caros, pero ahorran mucho trabajo.

creo que está en un riachuelo si no puede agregar o cambiar el hardware ... también ese precio también podría arrojar un ATMega644 que tiene 2 UART de hardware (y escribir su propia interfaz SPI para él) ... pero Supongo que eso derrota la parte de "ahorra mucho trabajo" :)
En ese momento, sería mejor que metieran un atmega1280 allí con 4 UART de hardware. Lamentablemente, una solución de hardware no cumplirá con sus requisitos.
@AdamDavis jajaja me superaste con un AVR más capaz :)
@AdamDavis Obviamente, no sé todos los detalles de lo que está tratando, pero en general, incluso si un cliente dice que necesita quedarse con un chip específico, si puede darles una buena razón para cambiar, lo harán.
Está usando un Arduino y no puede cambiar el procesador. Es bastante fácil interconectar un chip como ese usando un escudo de prototipos adecuado.
@Kellenjb A los efectos de esta pregunta, supongamos que no pueden cambiar. También estamos buscando otras opciones, por supuesto, pero esta pregunta se limita deliberadamente a opciones que no incluyen cambiar el hardware.
@Adam, es posible que desee cambiar su pregunta para indicar que no está dispuesto a modificar o agregar hardware en absoluto.

¿El cliente le permitirá usar un Arduino Mega que tiene 4 puertos seriales de hardware?

http://www.arduino.cc/en/Main/ArduinoBoardMega

¿Por qué el voto negativo?
Porque no puede cambiar el procesador, presumiblemente.
No te voté en contra, pero la primera parte de la pregunta indica que cambiar el procesador no es una opción. Sugerir algo que el OP ya descartó puede resultar en votos negativos...
Esto probablemente hubiera sido mejor como comentario que como respuesta, pero sondear el límite del requisito de "arduino" parece una idea que vale la pena, ya que arduino es técnicamente una marca que abarca una variedad de tableros, a pesar de que a menudo es una abreviatura para el actualmente Ensamblaje popular mega328p y mega8u.

No use SoftSerial, al menos use NewSoftSerial... Creo que es una hazaña realmente desafiante (quizás incluso imposible) lograr una comunicación UART full-duplex multicanal sin dos UART de hardware... con NewSoftSerial, creo que el sacrificio lo que haces es que solo puedes "usar" un canal a la vez. Creo que si se pudiera hacer con Arduino ya se habría hecho.

Vea la discusión aquí sobre el uso de múltiples instancias de NewSoftSerial.

El SoftwareSerial integrado en el entorno de desarrollo arduino 1.0 es esencialmente NewSoftSerial. Probé NewSoftSerial por si acaso, pero el problema es el mismo: no puede recibir mientras envía.
Puede ver los detalles de la falla aquí: arduino.cc/forum/index.php/topic,81756.0.html Les pedí que actualicen la documentación para que los usuarios posteriores no caigan en esta trampa.
Diría que la viabilidad de la comunicación multicanal realmente depende de la relación entre la velocidad de transmisión y la velocidad del reloj. Lo suficientemente lento y tiene mucho tiempo para manejar múltiples canales de transmisión y recepción.