Clases de C ++ para la abstracción del pin de E / S

13

Estoy buscando abstracciones de C ++ para puntos de E / S de hardware o pines. Cosas como in_pin, out_pin, inout_pin, tal vez open_collector_pin, etc.

Seguramente puedo crear un conjunto de abstracciones de este tipo, así que no estoy buscando el tipo de respuestas 'hey, podrías hacerlo de esta manera', sino el 'vistazo a esta biblioteca que se ha utilizado en este y este y este proyecto '.

Google no encontró nada, tal vez porque no sé cómo dirían los demás a esto.

Mi objetivo es crear bibliotecas de E / S basadas en dichos puntos, pero que también proporcionen dichos puntos, por lo que sería fácil, por ejemplo, conectar un HD44780 LCd a cualquiera de los pines IO del chip o un I2C ( o SPI) Extensor de E / S, o cualquier otro punto que pueda controlarse de alguna manera, sin ningún cambio en la clase de LCD.

Sé que esto está en el borde de la electrónica / software, lo siento si no pertenece aquí.

@leon: cableado Esa es una gran bolsa de software, tendré que mirar más de cerca. Pero parece que no usan un pin abstracción como yo quiero. Por ejemplo, en la implementación del teclado que veo

digitalWrite(columnPins[c], LOW);   // Activate the current column.

Esto implica que hay una función (digitalWrite) que sabe cómo escribir en un pin de E / S. Esto hace que sea imposible agregar un nuevo tipo de pin de E / S (por ejemplo, uno que está en un MCP23017, por lo que tiene que escribirse a través de I2C) sin volver a escribir la función digitalWrite.

@Oli: Busqué en Google un ejemplo de Arduino IO, pero parece que se utiliza casi el mismo enfoque que la biblioteca Wiring:

int ledPin = 13;                 // LED connected to digital pin 13
void setup(){
    pinMode(ledPin, OUTPUT);      // sets the digital pin as output
}
    

5 respuestas

3

Respuesta corta: lamentablemente, no hay biblioteca para hacer lo que quieres. Lo he hecho muchas veces, pero siempre en proyectos que no son de código abierto. Estoy considerando poner algo en github pero no estoy seguro de cuándo puedo hacerlo.

¿Por qué C ++?

  1. El compilador es libre de usar la evaluación dinámica de expresiones de tamaño de palabra. C se propaga a int. Su máscara / cambio de bytes se puede hacer más rápido / más pequeño.
  2. en línea.
  3. Las operaciones de templado le permiten variar el tamaño de las palabras y otras propiedades, con seguridad de tipos.
respondido por el Jim Frimmel
5

Permítame enchufar descaradamente mi proyecto de código abierto enlace . La parte Kvasir :: Io proporciona funciones de manipulación de pines. Primero debe definir su pin utilizando una ubicación de Kvasir :: Io :: Pin así:

constexpr PinLocation<0,4> led1;    //port 0 pin 4
constexpr PinLOcation<0,8> led2;

Tenga en cuenta que esto no utiliza realmente RAM porque son variables constexpr.

A lo largo de su código, puede usar estas ubicaciones de pines en funciones de 'fábrica de acciones' como makeOpenDrain, set, clear, makeOutput y así sucesivamente. Una 'fábrica de acciones' no ejecuta realmente la acción, sino que devuelve un Kvasir :: Register :: Action que puede ejecutarse utilizando Kvasir :: Register :: apply (). La razón de esto es que apply () fusiona las acciones que se le pasan cuando actúan en el mismo registro, por lo que hay una ganancia de eficiencia.

apply(makeOutput(led1),
    makeOutput(led2),
    makeOpenDrain(led1),
    makeOpenDrain(led2));

Dado que la creación y fusión de acciones se realiza en tiempo de compilación, esto debería producir el mismo código de ensamblador que el equivalente típico codificado a mano:

PORT0DIR |= (1<<4) | (1<<8);
PORT0OD |= (1<<4) | (1<<8);
    
respondido por el odinthenerd
3

El proyecto Wiring usa una abstracción como esa:

enlace

y el compilador está escrito en C ++. Debes encontrar muchos ejemplos en el código fuente. El software Arduino está basado en cableado.

    
respondido por el Leon Heller
2

En C ++, es posible escribir una clase para que puedas usar los puertos de E / S como si fueran variables, por ejemplo,

  PORTB = 0x12;  /* Write to an 8-bit port */
  if (RB3) LATB4 = 1;  /* Read one I/O bit and conditionally write another */

sin tener en cuenta la implementación subyacente. Por ejemplo, si uno utiliza una plataforma de hardware que no admite operaciones de nivel de bits pero sí admite operaciones de registro de bytes, se podría (probablemente con la ayuda de algunas macros) definir una clase estática IO_PORTS con una lectura y escritura en línea propiedades llamadas bbRB3 y bbLATB4, de manera que la última declaración anterior se convertiría en

  if (IO_PORTS.bbRB3) IO_PORTS.bbLATB4 = 1;

que a su vez se procesaría en algo como:

  if (!!(PORTB & 8)) (1 ? (PORTB |= 16) : (PORTB &= ~16));

Un compilador debería poder notar la expresión constante en el operador?: y simplemente incluir la parte "verdadera". Podría ser posible reducir el número de propiedades creadas al expandir las macros a algo como:

  if (IO_PORTS.ppPORTB[3]) IO_PORTS.ppPORTB[4] = 1;

o

  if (IO_PORTS.bb(addrPORTB,3)) IO_PORTS.bbPORTB(addrPORTB,4) = 1;

pero no estoy seguro de que un compilador pueda alinear el código tan bien.

No quiero implicar de ninguna manera que el uso de puertos de E / S como si fueran variables es necesariamente una buena idea, pero como mencionas C ++ es un truco útil para saber. Mi propia preferencia en C o C ++, si no fuera necesaria la compatibilidad con el código que usa el estilo mencionado anteriormente, sería definir algún tipo de macro para cada bit de E / S y luego definir macros para "readBit", "writeBit", "setBit" y "clearBit" con la condición de que el argumento de identificación de bits pasado a esas macros debe ser el nombre de un puerto de E / S destinado a ser utilizado con dichas macros. El ejemplo anterior, por ejemplo, se escribiría como

  if (readBit(RB3)) setBit(LATB4);

y traducido como

  if (!!(_PORT_RB3 & _BITMASK_RB3)) _PORT_LATB4 |= _BITMASK_LATB4;

Eso sería un poco más de trabajo para el preprocesador que el estilo C ++, pero sería menos trabajo para el compilador. También permitiría la generación óptima de código para muchas implementaciones de E / S y una implementación de código decente para casi todas.

    
respondido por el supercat
1

Si está buscando algo realmente impresionante para abstraer el hardware y confía en sus habilidades de C ++, debe probar este patrón:

enlace

Lo he usado en un intento de extraer hardware para un chip Cortex-M0. Aún no he escrito nada sobre esta experiencia (lo haré algún día), pero créeme que ha sido muy útil debido a su naturaleza polimórfica estática: el mismo método para diferentes chips, sin costo (en comparación con el polimorfismo dinámico).

    
respondido por el Francisco Rodríguez

Lea otras preguntas en las etiquetas