¿Se pueden asignar pines individuales de diferentes puertos de un microcontrolador a un registro y cambiar sus valores al cambiar el valor del registro?

12

P: ¿Se pueden asignar pines individuales de diferentes puertos de un microcontrolador a un registro y cambiar sus valores al cambiar el valor del registro?

Escenario: He usado algunos pines de cada puerto (8 bits) del microcontrolador. Ahora quiero conectar un dispositivo que necesita un bus de 8 bits (supongamos D0 a D7 EN SECUENCIA), es decir, necesito 8 pines del controlador para poder conectarlos de manera individual

portx0  -> D0 // x is the name of port followed by bit location on that port
portx1  -> D1
...
portx7  -> D7

pero no tengo un puerto completo de 8 pines que puedo conectar con este dispositivo, más bien tengo algunos pines de portx, algunos de porty y algunos pines de portz. El nuevo escenario de conexión es como (conexión del microcontrolador al dispositivo respectivamente)

portx0  -> D0
portx1  -> D1
portx2  -> D2
porty4  -> D3
porty5  -> D4
porty6  -> D5
porty7  -> D6
portz1  -> D7

En esta condición si quiero enviar un valor decir

unsigned char dataReg = 0xFA;

en mi dispositivo desde el controlador, tengo que realizar operaciones con bits en el valor que se enviará y establecer cada pin de acuerdo con el valor en el registro individualmente. Por ejemplo

portx0 = ((dataReg & 0x01) >> 0 );  // Masking and shifting as bit position
portx1 = ((dataReg & 0x02) >> 1 );
portx2 = ((dataReg & 0x04) >> 2 );
porty4 = ((dataReg & 0x08) >> 3 );
porty5 = ((dataReg & 0x10) >> 4 );
porty6 = ((dataReg & 0x20) >> 5 );
porty7 = ((dataReg & 0x40) >> 6 );
portz1 = ((dataReg & 0x80) >> 7 );

Ahora, volviendo a la pregunta principal, para evitar estos cálculos individuales en cada bit en diferentes puertos, ¿se pueden asignar pines individuales de diferentes puertos de un microcontrolador a un registro y cambiar sus valores al cambiar el valor del registro?

Osaid
fuente
1
Tuve la misma idea hace un tiempo. Con los PIC, esto no es posible: microchip.com/forums/tm.aspx?high=&m=696277 - No creo que sea posible con ningún micro, pero sería útil enumerar su dispositivo.

Respuestas:

6

Parece que su pregunta se reduce a tener un valor de 8 bits en el firmware y querer leerlo y escribirlo desde y hacia una colección arbitraria de pines de puerto.

No hay forma directa de hardware para hacer esto. Debe escribir dos rutinas, una para leer el valor de 8 bits y otra para escribirlo. Otros han mencionado el uso de sindicatos, pero esa es una mala idea. Con las uniones, debe tratar cada bit por separado, y el código se vuelve dependiente del orden de bits del micro. De todos modos, este podría ser el camino a seguir si todos los 8 bits se dispersan de forma completamente independiente. Si es así, es poco lo que puede hacer sino crear un código especial para cada bit.

La mejor manera de hacer esto, especialmente si puede agrupar los bits en algunos fragmentos contiguos en los puertos físicos es usar enmascaramiento, desplazamiento y OR. Por ejemplo, si los tres bits bajos del byte interno están en los bits <6-4> de un puerto, cambie a la derecha ese valor del puerto en 4 y AND con 7 para colocar esos bits en su posición final. Desplazar y enmascarar (o enmascarar y desplazar) bits de otros puertos en su lugar y ensamblar el byte final de 8 bits OR colocando los resultados en él.

Este tipo de twiddling de bits de bajo nivel es más fácil de hacer en ensamblador que C. Probablemente pondría las rutinas de lectura y escritura de bytes en un solo módulo ensamblador y haría que la interfaz se pueda llamar desde C.

Olin Lathrop
fuente
66
Mi respuesta sería casi idéntica a la suya, excepto que no usaría ensamblaje en absoluto; las manipulaciones de bits son triviales en C. Creo que sería más dolor de cabeza (re) aprender la convención de llamada C específica para el compilador y cómo ejecutar el enlazador. Depende realmente del compilador y de lo difícil que haga las cosas. :-)
akohlsmith
@ Andrew: ¿En serio? Las convenciones de llamadas se detallan claramente en cualquier manual del compilador que he visto en el que podría ser necesario interactuar con el código de ensamblaje. La manipulación de bits puede ser "trivial" para escribir en C, pero esta es un área donde los compiladores pueden producir código horrendo. Si la velocidad o el espacio de código no importan, use lo que le resulte más cómodo. Me siento más cómodo con el ensamblador para el giro de bits de bajo nivel, así que lo usaría. Si esta es una rutina crítica de velocidad de bajo nivel, debe hacerlo en ensamblador. Realmente debería ser fácil.
Olin Lathrop
1
Lo que digo es que tener que lidiar con eso por algo tan trivial como la manipulación de bits no es algo que haría a menos que haya una muy buena razón para ello. No conocemos los detalles de su bus paralelo, pero la mayoría de los buses tienen señales estroboscópicas que eliminan la necesidad de actualizaciones "casi atómicas" de todos los pines del bus, por lo que caer al ensamblaje es una optimización innecesaria y una complejidad innecesaria (incluso si es sencillo).
akohlsmith
@Andrew: solo es complejo o complejo si no sabes lo que estás haciendo. Creo que el verdadero problema es que algunas personas temen al ensamblador y no lo conocen bien. Eso es un error Tiene que ser una herramienta lista en su caja de herramientas. Si no lo conoce bien o se siente incómodo, siempre justificará cómo se deben hacer las cosas de otra manera. Algunas cosas son más fáciles en ensamblador si lo conoce y el HLL igualmente bien. La mayoría de las personas no, pero eso es un problema con ellos, no con el uso del ensamblador.
Olin Lathrop
2
Estoy bien versado en lenguaje ensamblador en varios microcontroladores / microprocesadores. No estoy de acuerdo con que sea una herramienta lista; debe usarse con moderación y solo cuando sea necesario, generalmente para una inicialización de muy bajo nivel, código crítico de tiempo o tamaño o, en el caso más común, la optimización de un área que ya ha determinado que es un cuello de botella. Encuentro que los proyectos donde los autores que saltan al ensamblaje porque están allí a menudo escriben código menos claro o no reconocen cuando un algoritmo se aplica incorrectamente. No digo específicamente que sea usted, sino más bien en el caso más general.
akohlsmith
4

En general esto no es posible. Que yo sepa, no es posible con los PIC.

Sé que solo hay un microcontrolador que puede hacer esto, el Cypress PSoC . Es un sistema altamente configurable en chip. Una de las muchas cosas que le permite hacer es, literalmente, definir su propio registro (1-8 bits) y conectarlo a cualquier pin que desee, o incluso a circuitos internos.

Cableado PSoC

Por ejemplo, aquí he creado un registro de control de 6 bits. 5 de los bits van directamente a los pines, mientras que el sexto bit lo estoy usando para XOR con la entrada de un séptimo pin.

Pines PSoC

En el chip, puedo elegir asignar estos pines a cualquiera de los pines GPIO disponibles. (Son los grises uno la imagen)

Rocketmagnet
fuente
1
LPC800 también debería poder hacerlo, ya que las funciones se pueden asignar libremente a los pines.
Starblue
-1

Puedes probar lo siguiente. Escriba una estructura propia que se asigne a los pines respectivos de los 2 puertos (que se utilizarán). Ahora, actualizar el valor en este registro establecerá / restablecerá los pines de esos 2 puertos. ¡Solo intenta y dinos si funcionó!

Estoy seguro de que esto debería funcionar.

Rahul Ranjan
fuente
2
En C puede asignar una estructura a una ubicación de memoria, y puede asignar bits de su estructura (campos de bits) a compensaciones de bits, pero no hay forma de evitar que el compilador juegue con los bits 'intermedios', y ahora hay manera de ver la estructura 'general' de un solo valor entero. Esto no funcionara.
Wouter van Ooijen
-1

Si he entendido la pregunta correctamente, es bastante fácil en C:

Declaración de tipo genérico, se puede reutilizar para cualquier registro:

typedef union    // Generic 8-bit register Type
{
  uint8 reg; // Whole register
  struct
  {
    unsigned  bit7     : 1;  // Bit 7 
    unsigned  bit6     : 1;  // Bit 6 
    unsigned  bit5     : 1;  // Bit 5 
    unsigned  bit4     : 1;  // Bit 4 
    unsigned  bit3     : 1;  // Bit 3 
    unsigned  bit2     : 1;  // Bit 2 
    unsigned  bit1     : 1;  // Bit 1 
    unsigned  bit0     : 1;  // Bit 0 
  } bit;
} typ_GENERIC_REG8;

Entonces, para definir un puerto que queremos abordar:

#define MCU_GPO_PORTx   (*(volatile typ_GENERIC_REG8 *)(0x12345678)) // Number is address

Y para girar directamente un pin en ese puerto:

#define MCU_PORTx_PINn  (MCU_GPO_PORTx.bit.bit0)

En codigo:

MCU_PORTx_PINn = 1; // Set pin high

Registro completo:

MCU_GPO_PORTx.reg = 0xF; // All pins high

Vale la pena leer sobre estructuras, uniones, typedefs y enumeraciones, ¡todo esto hace la vida mucho más agradable en embebido y en general!

John U
fuente
OP quiere combinar varios bits de diferentes puertos en 'un byte'. No veo cómo esto haría eso. Olin Lathrop explica por qué no es posible.
En realidad, esto no soluciona el problema y, dependiendo de cuán "smrt" sea su compilador, podría generar un nuevo conjunto de problemas para depurar.
akohlsmith