Les broches individuelles de différents ports d'un microcontrôleur peuvent-elles être mappées sur un registre et leurs valeurs peuvent-elles être modifiées lors du changement de la valeur du registre?

12

Q: Les broches individuelles de différents ports d'un microcontrôleur peuvent-elles être mappées à un registre et leurs valeurs peuvent-elles être modifiées lors du changement de la valeur du registre?

Scénario: j'ai utilisé des broches de chaque port (8 bits) du micro-contrôleur. Maintenant, je veux interfacer un périphérique qui a besoin d'un bus 8 bits (supposons D0 à D7 EN SÉQUENCE), c'est-à-dire que j'ai besoin de 8 broches du contrôleur pour pouvoir les connecter de manière un à un

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

mais je n'ai pas un port entier de 8 broches que je peux connecter avec cet appareil, j'ai plutôt quelques broches de portx, certaines de porty et quelques broches de portz. Le nouveau scénario de connexion est comme (connexion du micro-contrôleur à l'appareil respectivement)

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

Dans cet état, si je veux envoyer une valeur, dites

unsigned char dataReg = 0xFA;

à mon appareil depuis le contrôleur, je dois effectuer des opérations au niveau du bit sur la valeur à envoyer et définir chaque broche en fonction de la valeur dans le registre individuellement. Par exemple

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 );

Maintenant, pour en venir à la question principale, afin d'éviter ces calculs individuels sur chaque bit sur différents ports, les broches individuelles de différents ports d'un microcontrôleur peuvent-elles être mappées sur un registre et leurs valeurs peuvent-elles être modifiées lors du changement de la valeur du registre?

Osaid
la source
1
J'ai eu la même idée il y a quelque temps. Avec les PIC, ce n'est pas possible: microchip.com/forums/tm.aspx?high=&m=696277 - Je ne pense pas que ce soit possible avec n'importe quel micro, mais lister votre appareil serait utile.

Réponses:

6

Il semble que votre question se résume à avoir une valeur de 8 bits dans le micrologiciel et à vouloir lire et écrire cela depuis et vers une collection arbitraire de broches de port.

Il n'y a aucun moyen matériel direct de le faire. Vous devez écrire deux routines, une pour lire la valeur 8 bits et une pour l'écrire. D'autres ont mentionné le recours aux syndicats, mais c'est une mauvaise idée. Avec les unions, vous devez traiter chaque bit séparément et le code dépend de l'ordre des bits du micro. Cela pourrait être la voie à suivre de toute façon si tous les 8 bits sont dispersés de manière complètement indépendante. Si c'est le cas, vous ne pouvez pas faire grand-chose sauf pour créer du code spécial pour chaque bit.

La meilleure façon de le faire, surtout si vous pouvez regrouper les bits en quelques morceaux contigus sur les ports physiques, est d'utiliser le masquage, le décalage et l'OR. Par exemple, si les trois bits de poids faible de l'octet interne se trouvent sur les bits <6-4> d'un port, décalez vers la droite cette valeur de port de 4 et ET avec 7 pour obtenir ces bits dans leur position finale. Décaler et masquer (ou masquer et décaler) les bits des autres ports en place et assembler l'octet final de 8 bits en OU les résultats.

Ce type de twiddling de bits de bas niveau est plus facile à faire dans l'assembleur que C. Je mettrais probablement les routines de lecture et d'écriture d'octets dans un seul module assembleur et rendrais l'interface appelable à partir de C.

Olin Lathrop
la source
6
Ma réponse serait presque identique à la vôtre, sauf que je n'utiliserais pas du tout l'assemblage; les manipulations de bits sont triviales en C. Je pense que ce serait plus un casse-tête (ré) apprendre la convention d'appel C spécifique pour le compilateur et comment exécuter l'éditeur de liens. Cela dépend vraiment du compilateur et de la difficulté avec laquelle il fait les choses. :-)
akohlsmith
@Andrew: Sérieusement? Les conventions d'appel sont clairement énoncées dans tout manuel du compilateur que j'ai vu où il pourrait être nécessaire d'interfacer avec le code assembleur. La manipulation des bits peut être "triviale" à écrire en C, mais c'est un domaine où les compilateurs peuvent produire du code horrible. Si la vitesse ou l'espace de code n'a pas d'importance, utilisez ce qui vous convient le mieux. Je suis plus à l'aise avec l'assembleur pour le twiddling de bits de bas niveau, donc je l'utiliserais. S'il s'agit d'une routine de vitesse critique à faible niveau, vous devez le faire dans l'assembleur. Ça devrait vraiment être facile.
Olin Lathrop du
1
Ce que je veux dire, c'est que devoir m'arranger avec ça pour quelque chose d'aussi banal que la manipulation de bits n'est pas quelque chose que je ferais à moins qu'il y ait une très bonne raison à cela. Nous ne connaissons pas les spécificités de son bus parallèle, mais la plupart des bus ont des signaux stroboscopiques qui éliminent le besoin de mises à jour "quasi atomiques" de toutes les broches du bus, donc passer à l'assemblage est probablement une optimisation inutile et une complexité inutile (même si c'est le cas). simple).
akohlsmith
@Andrew: C'est compliqué ou complexe seulement si vous ne savez pas ce que vous faites. Je pense que le vrai problème est que certaines personnes ont peur de l'assembleur et ne le connaissent pas bien. C'est une erreur. Il doit être un outil prêt dans votre boîte à outils. Si vous ne le connaissez pas bien ou si vous n'êtes pas à l'aise avec cela, vous serez toujours en train de justifier comment les choses devraient être faites d'une autre manière. Certaines choses sont plus faciles dans l'assembleur si vous le connaissez aussi bien que le HLL. La plupart des gens ne le font pas, mais c'est un problème avec eux, pas avec l'assembleur.
Olin Lathrop
2
Je connais bien le langage d'assemblage sur un certain nombre de microcontrôleurs / microprocesseurs. Je ne suis pas d'accord que ce devrait être un outil prêt; il doit être utilisé avec parcimonie et uniquement lorsque cela est nécessaire, généralement pour une initialisation de très bas niveau, un code critique en termes de timing ou de taille ou, dans le cas le plus courant, l'optimisation d'une zone que vous avez déjà déterminée comme un goulot d'étranglement. Je trouve que les projets où les auteurs qui sautent à l'assemblage parce qu'il est là écrivent souvent du code moins clair ou ne reconnaissent pas quand un algorithme est mal appliqué. Je ne dis pas spécifiquement que c'est vous, mais plutôt dans le cas plus général.
akohlsmith
4

En général, ce n'est pas possible. Pour autant que je sache, ce n'est pas possible avec les PIC.

Je ne connais qu'un seul microcontrôleur qui peut le faire, le Cypress PSoC . C'est un système sur puce hautement configurable. Parmi les nombreuses choses qu'il vous permet de faire, vous devez définir littéralement votre propre registre (1-8 bits) et le connecter à toutes les broches que vous aimez, ou même à des circuits internes.

Câblage PSoC

Par exemple, ici, j'ai créé un registre de contrôle 6 bits. 5 des bits vont directement aux broches, tandis que le 6ème bit que j'utilise pour XOR avec l'entrée d'une 7ème broche.

Broches PSoC

Sur la puce, je peux choisir d'affecter ces broches à l'une des broches GPIO disponibles. (Ce sont les gris sur l'image)

Rocketmagnet
la source
1
Le LPC800 devrait également pouvoir le faire, car les fonctions peuvent être attribuées librement aux broches.
starblue
-1

Vous pouvez essayer ce qui suit. Écrivez votre propre structure qui correspond aux broches respectives des 2 ports (qui doivent être utilisés). Maintenant, la mise à jour de la valeur dans ce registre doit définir / réinitialiser les broches de ces 2 ports. Essayez et faites-nous savoir si cela a fonctionné !!

Je suis convaincu que cela devrait fonctionner.

Rahul Ranjan
la source
2
En C, vous pouvez mapper une structure à un emplacement de mémoire et vous pouvez mapper des bits de votre structure (champs de bits) à des décalages de bits, mais il n'y a aucun moyen d'empêcher le compilateur de jouer avec les bits `` intermédiaires '', et il y a maintenant façon de voir la structure «globale» une valeur entière unique. Ça ne marchera pas.
Wouter van Ooijen
-1

Si j'ai bien compris la question, c'est assez simple en C:

Déclaration de type générique, peut être réutilisée pour n'importe quel registre:

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;

Donc, pour définir un port que nous voulons aborder:

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

Et pour tordre directement une broche sur ce port:

#define MCU_PORTx_PINn  (MCU_GPO_PORTx.bit.bit0)

Dans du code:

MCU_PORTx_PINn = 1; // Set pin high

Registre complet:

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

Il vaut la peine de lire sur les structures, les unions, les typedefs et les énumérations - tous ces éléments rendent la vie tellement plus agréable dans les systèmes intégrés et en général!

John U
la source
OP veut combiner plusieurs bits de différents ports en «un octet». Je ne vois pas comment cela ferait ça? Olin Lathrop explique pourquoi ce n'est pas possible.
Cela ne résout pas réellement le problème, et en fonction de la façon dont "smrt" est votre compilateur, pourrait générer un nouvel ensemble de problèmes à déboguer.
akohlsmith