微控制器不同端口的各个引脚可以映射到寄存器并在更改寄存器值时更改它们的值吗?

电器工程 微控制器 图片 数字逻辑 嵌入式 8051
2022-02-01 15:59:01

Q:微控制器不同端口的个别管脚是否可以映射到一个寄存器并在改变寄存器值时改变它们的值?

场景:我已经用完了微控制器每个端口(8 位)的一些引脚。现在我想连接一个需要 8 位总线的设备(假设 D0 到 D7 顺序),也就是说我需要来自控制器的 8 个引脚,以便我可以以一对一的方式连接它们

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

但是我没有可以与此设备连接的 8 个引脚的整个端口,而是我有一些来自 portx 的引脚,一些来自 porty 和一些来自 portz 的引脚。新的连接场景为(分别从微控制器连接到设备)

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

在这种情况下,如果我想发送一个值说

unsigned char dataReg = 0xFA;

从控制器到我的设备,我必须对要发送的值执行按位操作,并根据寄存器中的值单独设置每个引脚。例如

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

现在,回到主要问题,为了避免在不同端口上的每个位上进行这些单独的计算,微控制器不同端口的各个引脚是否可以映射到寄存器并在更改寄存器值时更改它们的值?

4个回答

看来您的问题归结为固件中有一个 8 位值,并且想要从任意端口引脚集合中读取和写入该值。

没有直接的硬件方法可以做到这一点。您必须编写两个例程,一个用于读取 8 位值,一个用于写入。其他人提到使用工会,但这是一个坏主意。使用联合,您必须单独处理每个位,并且代码变得依赖于微的位顺序。如果所有 8 位完全独立地分散,这可能是无论如何都要走的路。如果是这样,除了为每一位制作特殊代码外,您几乎无能为力。

执行此操作的更好方法是使用屏蔽、移位和 ORing,尤其是如果您可以将这些位分组到物理端口上的几个连续块中。例如,如果内部字节的低 3 位位于端口的位 <6-4> 上,则将该端口值右移 4 并与 7 进行与,以使这些位进入其最终位置。将来自其他端口的位移位和屏蔽(或屏蔽和移位)到位,并通过将结果或结果组合到其中来组装最后的 8 位字节。

这种低级位旋转在汇编程序中比在 C 中更容易完成。我可能会将字节读取和写入例程放在单个汇编程序模块中,并使接口可从 C 调用。

一般来说,这是不可能的。据我所知,图片是不可能的。

我知道只有一个微控制器可以做到这一点,赛普拉斯 PSoC这是一个高度可配置的片上系统。它允许您做的许多事情是从字面上定义您自己的寄存器(1-8 位)并将其连接到您喜欢的任何引脚,甚至连接到内部电路。

PSoC 接线

例如,这里我创建了一个 6 位控制寄存器。其中 5 个位直接进入引脚,而我使用的第 6 个位与来自第 7 个引脚的输入进行异或。

PSoC 引脚

在芯片上,我可以选择将这些引脚分配给任何可用的 GPIO 引脚。(这是图像中的灰色部分)

您可以尝试以下方法。编写一个您自己的结构,映射到 2 个端口的相应引脚(将要使用) 现在更新此寄存器中的值将设置/重置这 2 个端口的引脚。只要尝试让我们知道它是否有效!

我相信这应该会奏效。

如果我正确理解了这个问题,那么在 C 语言中就很容易了:

泛型类型声明,可重复用于任何寄存器:

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;

所以,要定义一个我们想要寻址的端口:

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

并直接在该端口上旋转一个引脚:

#define MCU_PORTx_PINn  (MCU_GPO_PORTx.bit.bit0)

在代码中:

MCU_PORTx_PINn = 1; // Set pin high

整个注册:

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

非常值得一读结构、联合、类型定义和枚举——所有这些都让嵌入式和一般情况下的生活变得更加美好!