Protocolo de transmisión de paquetes para microcontroladores PSP1N

Declaración del problema.


Al desarrollar otro dispositivo en un microcontrolador, me encontré con una situación en la que se requería el registro continuo de una gran cantidad de datos. El dispositivo tuvo que guardar un conjunto de datos que consta de una marca de tiempo y seis mediciones de ADC de 100 veces por segundo en una tarjeta SD (llamemos a este conjunto de datos un paquete), y luego analizar estos datos en una computadora en forma de gráficos. También era necesario en paralelo con la escritura de datos en una tarjeta SD, transfiriéndolos a través de UART. Estos datos deberían haber ocupado el menor espacio posible, ya que hay muchos datos. Al mismo tiempo, era necesario separar de alguna manera estos paquetes, ya que los datos se transmitían de forma continua. No busqué nada bueno en Internet, no lo encontré, así que decidí crear mi propio protocolo y bibliotecas para él.


Y luego apareció: protocolo de transmisión de paquetes (PSP1N)


Como resultado de algunas consideraciones, se decidió lo siguiente: en el protocolo, los datos se transmitirán en paquetes que consisten en N bytes, donde el primer bit de cada byte se asigna al signo de bit de inicio para la sincronización del paquete (de ahí el nombre del protocolo), los siete bits restantes se asignan a los datos. La secuencia y el tamaño de los datos se conocen de antemano.


Un ejemplo:


Asignamos 32 bits para la marca de tiempo, 60 bits para las mediciones ADC (6 canales de 10 bits), con un total de 92 bits. Como puede transferir 7 bits de datos útiles en un byte, el paquete constará de 14 bytes (92 bits / 7 bits = 13.14 ... redondeado a 14). Hay 112 bits de información en 14 bytes, de los cuales 14 bits están ocupados por el atributo de bit de inicio de 92 bits de datos útiles, hay 6 bits no utilizados (en los que podemos escribir más información, pero por simplicidad no los usaremos).



Donde el séptimo bit es un signo del bit de inicio (indica el comienzo del paquete), 6,5,4,3,2,1,0 son bits de datos.


El lado receptor también sabe que recibe un paquete de 14 bytes en el que el primer bit del primer byte es el bit de inicio (1) (en los bytes restantes, los bits de inicio son 0), luego en los bits de datos en orden hay 32 bits de la marca de tiempo, luego 10 bits de la medición de ADC No. 1, luego 10 bits de ADC # 2 y así sucesivamente ...


Del mismo modo, tiene lugar la escritura en la tarjeta SD y la lectura de acuerdo con el protocolo. En total, para un día de grabación en una tarjeta SD, obtenemos 115.4 MB de información (14 bytes x 100 mediciones por segundo x 3600 segundos x 24 horas).


Tal estructura de datos sigue siendo conveniente porque en el futuro podemos seleccionar bloques de datos desde cualquier parte del archivo y mostrarlos en forma de gráficos, sin cargar el archivo completo en la RAM (que puede alcanzar varias decenas de gigabytes). Y también podemos implementar un desplazamiento conveniente de estos gráficos cargando los paquetes necesarios.



Es hora de comenzar la implementación de software para el microcontrolador


Escribimos la biblioteca para el microcontrolador en C ++.


Por conveniencia, cree una clase:


class PSP { public: /*   init: startBit -   0  1 *arrayByte -      sizeArrayByte -     */ void init(byte startBit, byte* arrayByte, byte sizeArrayByte); /*      pushData: sizeBit -     value -   (       ) */ void pushData(byte sizeBit, uint32_t value); /*       popData: return     . */ byte* popData(); protected: byte startBit; //  byte* arrayByte; //   byte sizeArrayByte; //   byte position = 0; //    bool clearFlag = false; //   void setStartBit(byte &value); //     void clearStartBit(byte &value); //     }; 

Con el método de inicialización, creo que todo está claro:


 void PSP::init(byte startBit, byte* arrayByte, byte sizeArrayByte) { this->startBit = startBit; this->arrayByte = arrayByte; this->sizeArrayByte = sizeArrayByte; } 

El método de agregar datos es más complicado, aquí, mediante astutas manipulaciones bit a bit, colocamos los datos en nuestra matriz de bytes.


 void PSP::pushData(byte sizeBit, uint32_t value) { byte free; byte y; int remBit = 0; //      //   ,     if (!clearFlag) { for (byte i = 0; i < sizeArrayByte; i++) { arrayByte[i] = 0; } clearFlag = true; } //        7      while (remBit > -1) { free = 7 - (position) % 7; //        y = (position) / 7; //     //       remBit = sizeBit - free; //      if (remBit < 0) { arrayByte[y] |= value << ~remBit + 1; //   ,    position += sizeBit; //        remBit = -1; //      } //      else if (remBit > 0) { arrayByte[y] |= value >> remBit; //     ,    position += sizeBit - remBit; sizeBit = remBit; //        } //         else if (remBit == 0) { arrayByte[y] |= value; //    position += sizeBit; remBit = -1; //      } clearStartBit(arrayByte[y]); //   } setStartBit(arrayByte[0]); //   } 

Método para obtener una matriz de bytes de un paquete:


 byte* PSP::popData() { position = 0; //   clearFlag = false; //    return arrayByte; //   } 

Y finalmente, un par de funciones auxiliares:


 //      void PSP::setStartBit(byte &value) { if (startBit == 0) value &= ~(1 << 7); else value |= 1 << 7; } //      void PSP::clearStartBit(byte &value) { if (startBit == 1) value &= ~(1 << 7); else value |= 1 << 7; } 

Para resumir


Como resultado del trabajo realizado, el protocolo compacto para la transmisión de datos PSP1N y las bibliotecas listas para usar que se pueden descargar desde GitHub aquí "nacieron". En este repositorio encontrará:


  1. Ejemplo de uso de la biblioteca ColsolePSP1N / C #
  2. PSP1N_CPP / contiene la biblioteca PSP para trabajar con el protocolo y un ejemplo de su uso en Arduino
  3. PSP1N_CSHARP / biblioteca de protocolos para .NET

Para demostrar el funcionamiento del protocolo, puede actualizar el boceto en Arduino y, en el ejemplo ExampleSerialPortRead de la computadora, recibir datos del microcontrolador a través del puerto COM. Allí, estos datos se descifran y se muestran en una aplicación de consola. Hablaré sobre la biblioteca escrita en C # para el lado receptor en otra ocasión.


TestingConsole:



ACTUALIZACIÓN (31/03/19): Se modificó el algoritmo de codificación y decodificación.

Source: https://habr.com/ru/post/441506/


All Articles