有效地随机选择端口(uint8_t 位掩码)

问题描述 投票:0回答:1

假设我有 4 个可能打开和关闭的端口,并由 uint8_t 掩码的 LSB 表示,意味着 0b00001001 表示端口 0、3 处于打开状态。

给定 0-3 之间的数字(代表随机化,来自 mod4,或更具体地说是按位 &),我想根据以均匀分布方式接收到的数字从该掩码中选择一个随机端口,并且为了提高效率,没有 if 语句/switch case - 仅进行一些操作/操作:

如果 __builtin_popcount(mask) = 1: 将始终返回唯一 1 的索引 (__builtin_ctz(mask))。

如果 __builtin_popcount(mask) = 2:数字 0,1 将产生第一个端口的返回值,2,3 将产生第二个端口。因此,在上面给定 0 和 1 的示例中,我希望返回端口 0,对于 2 和 3,我希望返回端口 3。

如果 __builtin_popcount(mask) = 3:这是主要问题,因为我们不想总是将两个数字映射到同一个端口,因为假设数字是随机的,那么这将不再均匀分布。我认为其中 3 个数字可以映射到 3 个端口,而第 4 个数字将根据每次调用的所有其他 3 个端口之间的函数中的某些全局/可访问变量进行交替。

如果 __builtin_popcount(mask) = 4:发生这种情况的唯一方法是掩码为 0b00001111,这样每个数字就会简单地映射到自己的端口。

实现上述内容对于 if 语句/switch 用例来说不是问题,但这违背了目的,因为我必须以尽可能最有效的方式完成此操作。甚至模数也是不允许的,因为成本太高。所以不知何故,我希望得到帮助/指导,看看如何使用按位运算来完成所有这一切,并且所有这 4 件事都发生在其中。

谢谢!

我尝试的所有操作都导致我必须至少在某个地方使用 if 语句,并且我无法想出一种方法将所有要求概括为位操作,这很可能是由于我缺乏按位操作的经验摆弄。

我想到了拥有1UL的技巧<< (number - 1) and &'ing that and then finding the trailing zeros with __builtin_ctz but again it becomes an issue when I want all 4 to work. Perhaps a few commands like that could work.

c bitmap bit-manipulation bitwise-operators
1个回答
0
投票

如果不完全确定你想要什么,但解决方案可能是查找表。它们快速、灵活且易于维护。像这样的东西:

typedef enum : uint8_t // C23 enum, not necessary, uint8_t + defines works too
{
  PORT0 = 1u << 0, 
  PORT1 = 1u << 1,
  PORT2 = 1u << 2,
  PORT3 = 1u << 3,
} port_t;

#define N 4
#define PORTS 4

// on a microcontroller, this will be allocated in flash:
static const port_t ports[N][PORTS] =
{ 
  // customize this in any way you want:

  [0] = {0},

  [1][0] = PORT0,
  [1][1] = PORT0,
  [1][2] = PORT0,
  [1][3] = PORT0,

  [2][0] = PORT0,
  [2][1] = PORT0,
  [2][2] = PORT1,
  [2][3] = PORT1,

  [3][0] = PORT0 | PORT1,
  [3][1] = PORT0 | PORT1 | PORT2,
};

...

PORTX = ports[i][j]; // PORTX being the actual GPIO register
© www.soinside.com 2019 - 2024. All rights reserved.